Branch data Line data Source code
1 : : /* 2 : : * Copyright (c) 2019 Peter Bigot Consulting, LLC 3 : : * 4 : : * SPDX-License-Identifier: Apache-2.0 5 : : */ 6 : : 7 : : /* 8 : : * The time_civil_from_days function is derived directly from public 9 : : * domain content written by Howard Hinnant and available at: 10 : : * http://howardhinnant.github.io/date_algorithms.html#civil_from_days 11 : : */ 12 : : 13 : : #include <time.h> 14 : : 15 : : /* A signed type with the representation of time_t without its 16 : : * implications. 17 : : */ 18 : : typedef time_t bigint_type; 19 : : 20 : : /** Convert a UNIX time to civil time. 21 : : * 22 : : * This converts integral seconds since (before) 1970-01-01T00:00:00 23 : : * to the POSIX standard civil time representation. Any adjustments 24 : : * due to time zone, leap seconds, or a different epoch must be 25 : : * applied to @p time before invoking this function. 26 : : * 27 : : * @param time the time represented as seconds. 28 : : * 29 : : * @return the time information for corresponding to the provided 30 : : * instant. 31 : : * 32 : : * @see http://howardhinnant.github.io/date_algorithms.html#civil_from_days 33 : : */ 34 : 0 : static void time_civil_from_days(bigint_type z, 35 : : struct tm *ZRESTRICT tp) 36 : : { 37 [ # # ]: 0 : tp->tm_wday = (z >= -4) ? ((z + 4) % 7) : ((z + 5) % 7 + 6); 38 : 0 : z += 719468; 39 : : 40 [ # # ]: 0 : bigint_type era = ((z >= 0) ? z : (z - 146096)) / 146097; 41 : 0 : unsigned int doe = (z - era * (bigint_type)146097); 42 : 0 : unsigned int yoe = (doe - doe / 1460U + doe / 36524U - doe / 146096U) 43 : : / 365U; 44 : 0 : bigint_type y = (time_t)yoe + era * 400; 45 : 0 : unsigned int doy = doe - (365U * yoe + yoe / 4U - yoe / 100U); 46 : 0 : unsigned int mp = (5U * doy + 2U) / 153U; 47 : 0 : unsigned int d = doy - (153U * mp + 2U) / 5U + 1U; 48 [ # # ]: 0 : unsigned int m = mp + ((mp < 10) ? 3 : -9); 49 : : 50 : 0 : tp->tm_year = y + (m <= 2) - 1900; 51 : 0 : tp->tm_mon = m - 1; 52 : 0 : tp->tm_mday = d; 53 : : 54 : : /* Everything above is explained on the referenced page, but 55 : : * doy is relative to --03-01 and we need it relative to 56 : : * --01-01. 57 : : * 58 : : * doy=306 corresponds to --01-01, doy=364 to --02-28, and 59 : : * doy=365 to --02-29. So we can just subtract 306 to handle 60 : : * January and February. 61 : : * 62 : : * For doy<306 we have to add the number of days before 63 : : * --03-01, which is 59 in a common year and 60 in a leap 64 : : * year. Note that the first year in the era is a leap year. 65 : : */ 66 [ # # ]: 0 : if (doy >= 306U) { 67 : 0 : tp->tm_yday = doy - 306U; 68 : : } else { 69 [ # # # # : 0 : tp->tm_yday = doy + 59U + (((yoe % 4U == 0U) && (yoe % 100U != 0U)) || (yoe == 0U)); # # ] 70 : : } 71 : 0 : } 72 : : 73 : : /* Convert a UNIX time to civil time. 74 : : * 75 : : * This converts integral seconds since (before) 1970-01-01T00:00:00 76 : : * to the POSIX standard civil time representation. Any adjustments 77 : : * due to time zone, leap seconds, or a different epoch must be 78 : : * applied to @p time before invoking this function. 79 : : */ 80 : : struct tm *gmtime_r(const time_t *ZRESTRICT timep, 81 : : struct tm *ZRESTRICT result) 82 : : { 83 : 0 : time_t z = *timep; 84 [ # # ]: 0 : bigint_type days = (z >= 0 ? z : z - 86399) / 86400; 85 : 0 : unsigned int rem = z - days * 86400; 86 : : 87 : 0 : *result = (struct tm){ 0 }; 88 : : 89 : 0 : time_civil_from_days(days, result); 90 : : 91 : 0 : result->tm_hour = rem / 60U / 60U; 92 : 0 : rem -= result->tm_hour * 60 * 60; 93 : 0 : result->tm_min = rem / 60; 94 : 0 : result->tm_sec = rem - result->tm_min * 60; 95 : : 96 : 0 : return result; 97 : : } 98 : : 99 : : struct tm *gmtime(const time_t *timep) 100 : : { 101 : : static struct tm shared; 102 : : 103 : 0 : return gmtime_r(timep, &shared); 104 : : }