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