1 // SPDX-License-Identifier: LGPL-2.0+ 1 // SPDX-License-Identifier: LGPL-2.0+ 2 /* 2 /* 3 * Copyright (C) 1993, 1994, 1995, 1996, 1997 3 * Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc. 4 * This file is part of the GNU C Library. 4 * This file is part of the GNU C Library. 5 * Contributed by Paul Eggert (eggert@twinsun. 5 * Contributed by Paul Eggert (eggert@twinsun.com). 6 * 6 * 7 * The GNU C Library is free software; you can 7 * The GNU C Library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Librar 8 * modify it under the terms of the GNU Library General Public License as 9 * published by the Free Software Foundation; 9 * published by the Free Software Foundation; either version 2 of the 10 * License, or (at your option) any later vers 10 * License, or (at your option) any later version. 11 * 11 * 12 * The GNU C Library is distributed in the hop 12 * The GNU C Library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Library General Public License for more det 15 * Library General Public License for more details. 16 * 16 * 17 * You should have received a copy of the GNU 17 * You should have received a copy of the GNU Library General Public 18 * License along with the GNU C Library; see t 18 * License along with the GNU C Library; see the file COPYING.LIB. If not, 19 * write to the Free Software Foundation, Inc. 19 * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 20 * Boston, MA 02111-1307, USA. 20 * Boston, MA 02111-1307, USA. 21 */ 21 */ 22 22 23 /* 23 /* 24 * Converts the calendar time to broken-down t 24 * Converts the calendar time to broken-down time representation >> 25 * Based on code from glibc-2.6 25 * 26 * 26 * 2009-7-14: 27 * 2009-7-14: 27 * Moved from glibc-2.6 to kernel by Zhaolei 28 * Moved from glibc-2.6 to kernel by Zhaolei<zhaolei@cn.fujitsu.com> 28 * 2021-06-02: << 29 * Reimplemented by Cassio Neri <cassio.neri << 30 */ 29 */ 31 30 32 #include <linux/time.h> 31 #include <linux/time.h> 33 #include <linux/module.h> 32 #include <linux/module.h> 34 #include <linux/kernel.h> !! 33 >> 34 /* >> 35 * Nonzero if YEAR is a leap year (every 4 years, >> 36 * except every 100th isn't, and every 400th is). >> 37 */ >> 38 static int __isleap(long year) >> 39 { >> 40 return (year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0); >> 41 } >> 42 >> 43 /* do a mathdiv for long type */ >> 44 static long math_div(long a, long b) >> 45 { >> 46 return a / b - (a % b < 0); >> 47 } >> 48 >> 49 /* How many leap years between y1 and y2, y1 must less or equal to y2 */ >> 50 static long leaps_between(long y1, long y2) >> 51 { >> 52 long leaps1 = math_div(y1 - 1, 4) - math_div(y1 - 1, 100) >> 53 + math_div(y1 - 1, 400); >> 54 long leaps2 = math_div(y2 - 1, 4) - math_div(y2 - 1, 100) >> 55 + math_div(y2 - 1, 400); >> 56 return leaps2 - leaps1; >> 57 } >> 58 >> 59 /* How many days come before each month (0-12). */ >> 60 static const unsigned short __mon_yday[2][13] = { >> 61 /* Normal years. */ >> 62 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, >> 63 /* Leap years. */ >> 64 {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366} >> 65 }; 35 66 36 #define SECS_PER_HOUR (60 * 60) 67 #define SECS_PER_HOUR (60 * 60) 37 #define SECS_PER_DAY (SECS_PER_HOUR * 24) 68 #define SECS_PER_DAY (SECS_PER_HOUR * 24) 38 69 39 /** 70 /** 40 * time64_to_tm - converts the calendar time t 71 * time64_to_tm - converts the calendar time to local broken-down time 41 * 72 * 42 * @totalsecs: the number of seconds elapsed !! 73 * @totalsecs the number of seconds elapsed since 00:00:00 on January 1, 1970, 43 * Coordinated Universal Time (UT 74 * Coordinated Universal Time (UTC). 44 * @offset: offset seconds adding to total !! 75 * @offset offset seconds adding to totalsecs. 45 * @result: pointer to struct tm variable !! 76 * @result pointer to struct tm variable to receive broken-down time 46 */ 77 */ 47 void time64_to_tm(time64_t totalsecs, int offs 78 void time64_to_tm(time64_t totalsecs, int offset, struct tm *result) 48 { 79 { 49 u32 u32tmp, day_of_century, year_of_ce !! 80 long days, rem, y; 50 u64 u64tmp, udays, century, year; << 51 bool is_Jan_or_Feb, is_leap_year; << 52 long days, rem; << 53 int remainder; 81 int remainder; >> 82 const unsigned short *ip; 54 83 55 days = div_s64_rem(totalsecs, SECS_PER 84 days = div_s64_rem(totalsecs, SECS_PER_DAY, &remainder); 56 rem = remainder; 85 rem = remainder; 57 rem += offset; 86 rem += offset; 58 while (rem < 0) { 87 while (rem < 0) { 59 rem += SECS_PER_DAY; 88 rem += SECS_PER_DAY; 60 --days; 89 --days; 61 } 90 } 62 while (rem >= SECS_PER_DAY) { 91 while (rem >= SECS_PER_DAY) { 63 rem -= SECS_PER_DAY; 92 rem -= SECS_PER_DAY; 64 ++days; 93 ++days; 65 } 94 } 66 95 67 result->tm_hour = rem / SECS_PER_HOUR; 96 result->tm_hour = rem / SECS_PER_HOUR; 68 rem %= SECS_PER_HOUR; 97 rem %= SECS_PER_HOUR; 69 result->tm_min = rem / 60; 98 result->tm_min = rem / 60; 70 result->tm_sec = rem % 60; 99 result->tm_sec = rem % 60; 71 100 72 /* January 1, 1970 was a Thursday. */ 101 /* January 1, 1970 was a Thursday. */ 73 result->tm_wday = (4 + days) % 7; 102 result->tm_wday = (4 + days) % 7; 74 if (result->tm_wday < 0) 103 if (result->tm_wday < 0) 75 result->tm_wday += 7; 104 result->tm_wday += 7; 76 105 77 /* !! 106 y = 1970; 78 * The following algorithm is, basical !! 107 79 * and Schneider [1]. In a few words: !! 108 while (days < 0 || days >= (__isleap(y) ? 366 : 365)) { 80 * (fictitious) calendar where the yea !! 109 /* Guess a corrected year, assuming 365 days per year. */ 81 * (*), and finishes in February, mont !! 110 long yg = y + math_div(days, 365); 82 * mathematically convenient because t !! 111 83 * depend on whether the year is leap !! 112 /* Adjust DAYS and Y to match the guessed year. */ 84 * !! 113 days -= (yg - y) * 365 + leaps_between(y, yg); 85 * March 1st 0-th day of th !! 114 y = yg; 86 * ... !! 115 } 87 * April 1st 31-st day of t !! 116 88 * ... !! 117 result->tm_year = y - 1900; 89 * January 1st 306-th day of !! 118 90 * ... !! 119 result->tm_yday = days; 91 * February 28th 364-th day of !! 120 92 * February 29th 365-th day of !! 121 ip = __mon_yday[__isleap(y)]; 93 * !! 122 for (y = 11; days < ip[y]; y--) 94 * After having worked out the date in !! 123 continue; 95 * (using just arithmetics) it's easy !! 124 days -= ip[y]; 96 * corresponding date in the Gregorian !! 125 97 * !! 126 result->tm_mon = y; 98 * [1] "Euclidean Affine Functions and !! 127 result->tm_mday = days + 1; 99 * Algorithms". https://arxiv.org/abs/ << 100 * << 101 * (*) The numbering of months follows << 102 * is slightly different from [1]. << 103 */ << 104 << 105 udays = ((u64) days) + 2305843009213 << 106 << 107 u64tmp = 4 * udays + 3; << 108 century = div64_u64_rem(u64tmp << 109 day_of_century = (u32) (u64tmp / 4); << 110 << 111 u32tmp = 4 * day_of_century + << 112 u64tmp = 2939745ULL * u32tmp; << 113 year_of_century = upper_32_bits(u64tmp << 114 day_of_year = lower_32_bits(u64tmp << 115 << 116 year = 100 * century + year << 117 is_leap_year = year_of_century ? !( << 118 << 119 u32tmp = 2141 * day_of_year + << 120 month = u32tmp >> 16; << 121 day = ((u16) u32tmp) / 214 << 122 << 123 /* << 124 * Recall that January 1st is the 306- << 125 * computational (not Gregorian) calen << 126 */ << 127 is_Jan_or_Feb = day_of_year >= 306; << 128 << 129 /* Convert to the Gregorian calendar a << 130 year = year + is_Jan_or_Feb << 131 month = is_Jan_or_Feb ? mont << 132 day = day + 1; << 133 day_of_year += is_Jan_or_Feb ? -30 << 134 << 135 /* Convert to tm's format. */ << 136 result->tm_year = (long) (year - 1900) << 137 result->tm_mon = (int) month; << 138 result->tm_mday = (int) day; << 139 result->tm_yday = (int) day_of_year; << 140 } 128 } 141 EXPORT_SYMBOL(time64_to_tm); 129 EXPORT_SYMBOL(time64_to_tm); 142 130
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.