|
12 | 12 | #include "src/__support/macros/config.h"
|
13 | 13 | #include "src/time/time_constants.h"
|
14 | 14 |
|
| 15 | +#include <stdint.h> |
| 16 | + |
15 | 17 | namespace LIBC_NAMESPACE_DECL {
|
16 | 18 | namespace time_utils {
|
17 | 19 |
|
| 20 | +// TODO: clean this up in a followup patch |
| 21 | +int64_t mktime_internal(const tm *tm_out) { |
| 22 | + // Unlike most C Library functions, mktime doesn't just die on bad input. |
| 23 | + // TODO(rtenneti); Handle leap seconds. |
| 24 | + int64_t tm_year_from_base = tm_out->tm_year + time_constants::TIME_YEAR_BASE; |
| 25 | + |
| 26 | + // 32-bit end-of-the-world is 03:14:07 UTC on 19 January 2038. |
| 27 | + if (sizeof(time_t) == 4 && |
| 28 | + tm_year_from_base >= time_constants::END_OF32_BIT_EPOCH_YEAR) { |
| 29 | + if (tm_year_from_base > time_constants::END_OF32_BIT_EPOCH_YEAR) |
| 30 | + return time_utils::out_of_range(); |
| 31 | + if (tm_out->tm_mon > 0) |
| 32 | + return time_utils::out_of_range(); |
| 33 | + if (tm_out->tm_mday > 19) |
| 34 | + return time_utils::out_of_range(); |
| 35 | + else if (tm_out->tm_mday == 19) { |
| 36 | + if (tm_out->tm_hour > 3) |
| 37 | + return time_utils::out_of_range(); |
| 38 | + else if (tm_out->tm_hour == 3) { |
| 39 | + if (tm_out->tm_min > 14) |
| 40 | + return time_utils::out_of_range(); |
| 41 | + else if (tm_out->tm_min == 14) { |
| 42 | + if (tm_out->tm_sec > 7) |
| 43 | + return time_utils::out_of_range(); |
| 44 | + } |
| 45 | + } |
| 46 | + } |
| 47 | + } |
| 48 | + |
| 49 | + // Years are ints. A 32-bit year will fit into a 64-bit time_t. |
| 50 | + // A 64-bit year will not. |
| 51 | + static_assert( |
| 52 | + sizeof(int) == 4, |
| 53 | + "ILP64 is unimplemented. This implementation requires 32-bit integers."); |
| 54 | + |
| 55 | + // Calculate number of months and years from tm_mon. |
| 56 | + int64_t month = tm_out->tm_mon; |
| 57 | + if (month < 0 || month >= time_constants::MONTHS_PER_YEAR - 1) { |
| 58 | + int64_t years = month / 12; |
| 59 | + month %= 12; |
| 60 | + if (month < 0) { |
| 61 | + years--; |
| 62 | + month += 12; |
| 63 | + } |
| 64 | + tm_year_from_base += years; |
| 65 | + } |
| 66 | + bool tm_year_is_leap = time_utils::is_leap_year(tm_year_from_base); |
| 67 | + |
| 68 | + // Calculate total number of days based on the month and the day (tm_mday). |
| 69 | + int64_t total_days = tm_out->tm_mday - 1; |
| 70 | + for (int64_t i = 0; i < month; ++i) |
| 71 | + total_days += time_constants::NON_LEAP_YEAR_DAYS_IN_MONTH[i]; |
| 72 | + // Add one day if it is a leap year and the month is after February. |
| 73 | + if (tm_year_is_leap && month > 1) |
| 74 | + total_days++; |
| 75 | + |
| 76 | + // Calculate total numbers of days based on the year. |
| 77 | + total_days += (tm_year_from_base - time_constants::EPOCH_YEAR) * |
| 78 | + time_constants::DAYS_PER_NON_LEAP_YEAR; |
| 79 | + if (tm_year_from_base >= time_constants::EPOCH_YEAR) { |
| 80 | + total_days += |
| 81 | + time_utils::get_num_of_leap_years_before(tm_year_from_base - 1) - |
| 82 | + time_utils::get_num_of_leap_years_before(time_constants::EPOCH_YEAR); |
| 83 | + } else if (tm_year_from_base >= 1) { |
| 84 | + total_days -= |
| 85 | + time_utils::get_num_of_leap_years_before(time_constants::EPOCH_YEAR) - |
| 86 | + time_utils::get_num_of_leap_years_before(tm_year_from_base - 1); |
| 87 | + } else { |
| 88 | + // Calculate number of leap years until 0th year. |
| 89 | + total_days -= |
| 90 | + time_utils::get_num_of_leap_years_before(time_constants::EPOCH_YEAR) - |
| 91 | + time_utils::get_num_of_leap_years_before(0); |
| 92 | + if (tm_year_from_base <= 0) { |
| 93 | + total_days -= 1; // Subtract 1 for 0th year. |
| 94 | + // Calculate number of leap years until -1 year |
| 95 | + if (tm_year_from_base < 0) { |
| 96 | + total_days -= |
| 97 | + time_utils::get_num_of_leap_years_before(-tm_year_from_base) - |
| 98 | + time_utils::get_num_of_leap_years_before(1); |
| 99 | + } |
| 100 | + } |
| 101 | + } |
| 102 | + |
| 103 | + // TODO: https://github.com/llvm/llvm-project/issues/121962 |
| 104 | + // Need to handle timezone and update of tm_isdst. |
| 105 | + int64_t seconds = tm_out->tm_sec + |
| 106 | + tm_out->tm_min * time_constants::SECONDS_PER_MIN + |
| 107 | + tm_out->tm_hour * time_constants::SECONDS_PER_HOUR + |
| 108 | + total_days * time_constants::SECONDS_PER_DAY; |
| 109 | + return seconds; |
| 110 | +} |
| 111 | + |
18 | 112 | static int64_t computeRemainingYears(int64_t daysPerYears,
|
19 | 113 | int64_t quotientYears,
|
20 | 114 | int64_t *remainingDays) {
|
@@ -42,7 +136,7 @@ static int64_t computeRemainingYears(int64_t daysPerYears,
|
42 | 136 | //
|
43 | 137 | // Compute the number of months from the remaining days. Finally, adjust years
|
44 | 138 | // to be 1900 and months to be from January.
|
45 |
| -int64_t update_from_seconds(int64_t total_seconds, struct tm *tm) { |
| 139 | +int64_t update_from_seconds(int64_t total_seconds, tm *tm) { |
46 | 140 | // Days in month starting from March in the year 2000.
|
47 | 141 | static const char daysInMonth[] = {31 /* Mar */, 30, 31, 30, 31, 31,
|
48 | 142 | 30, 31, 30, 31, 31, 29};
|
|
0 commit comments