| /* |
| Copyright © 2005-2020 Rich Felker, et al. |
| |
| Permission is hereby granted, free of charge, to any person obtaining |
| a copy of this software and associated documentation files (the |
| "Software"), to deal in the Software without restriction, including |
| without limitation the rights to use, copy, modify, merge, publish, |
| distribute, sublicense, and/or sell copies of the Software, and to |
| permit persons to whom the Software is furnished to do so, subject to |
| the following conditions: |
| |
| The above copyright notice and this permission notice shall be |
| included in all copies or substantial portions of the Software. |
| |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
| IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
| CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
| TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
| SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| |
| static long long __year_to_secs(long long year, int *is_leap) |
| { |
| if (year-2ULL <= 136) { |
| int y = year; |
| int leaps = (y-68)>>2; |
| if (!((y-68)&3)) { |
| leaps--; |
| if (is_leap) *is_leap = 1; |
| } else if (is_leap) *is_leap = 0; |
| return 31536000*(y-70) + 86400*leaps; |
| } |
| |
| int cycles, centuries, leaps, rem, dummy; |
| |
| if (!is_leap) is_leap = &dummy; |
| cycles = (year-100) / 400; |
| rem = (year-100) % 400; |
| if (rem < 0) { |
| cycles--; |
| rem += 400; |
| } |
| if (!rem) { |
| *is_leap = 1; |
| centuries = 0; |
| leaps = 0; |
| } else { |
| if (rem >= 200) { |
| if (rem >= 300) centuries = 3, rem -= 300; |
| else centuries = 2, rem -= 200; |
| } else { |
| if (rem >= 100) centuries = 1, rem -= 100; |
| else centuries = 0; |
| } |
| if (!rem) { |
| *is_leap = 0; |
| leaps = 0; |
| } else { |
| leaps = rem / 4U; |
| rem %= 4U; |
| *is_leap = !rem; |
| } |
| } |
| |
| leaps += 97*cycles + 24*centuries - *is_leap; |
| |
| return (year-100) * 31536000LL + leaps * 86400LL + 946684800 + 86400; |
| } |
| |
| static int __month_to_secs(int month, int is_leap) |
| { |
| static const int secs_through_month[] = { |
| 0, 31*86400, 59*86400, 90*86400, |
| 120*86400, 151*86400, 181*86400, 212*86400, |
| 243*86400, 273*86400, 304*86400, 334*86400 }; |
| int t = secs_through_month[month]; |
| if (is_leap && month >= 2) t+=86400; |
| return t; |
| } |
| |
| static long long __tm_to_secs(const struct tm *tm) |
| { |
| int is_leap; |
| long long year = tm->tm_year; |
| int month = tm->tm_mon; |
| if (month >= 12 || month < 0) { |
| int adj = month / 12; |
| month %= 12; |
| if (month < 0) { |
| adj--; |
| month += 12; |
| } |
| year += adj; |
| } |
| long long t = __year_to_secs(year, &is_leap); |
| t += __month_to_secs(month, is_leap); |
| t += 86400LL * (tm->tm_mday-1); |
| t += 3600LL * tm->tm_hour; |
| t += 60LL * tm->tm_min; |
| t += tm->tm_sec; |
| return t; |
| } |