[352] | 1 | /* musl-1.1.12/src/time/*.c */
|
---|
| 2 | /* musl as a whole is licensed under the following standard MIT license:
|
---|
| 3 | *
|
---|
| 4 | * ----------------------------------------------------------------------
|
---|
| 5 | * Copyright (C) 2005-2014 Rich Felker, et al.
|
---|
| 6 | *
|
---|
| 7 | * Permission is hereby granted, free of charge, to any person obtaining
|
---|
| 8 | * a copy of this software and associated documentation files (the
|
---|
| 9 | * "Software"), to deal in the Software without restriction, including
|
---|
| 10 | * without limitation the rights to use, copy, modify, merge, publish,
|
---|
| 11 | * distribute, sublicense, and/or sell copies of the Software, and to
|
---|
| 12 | * permit persons to whom the Software is furnished to do so, subject to
|
---|
| 13 | * the following conditions:
|
---|
| 14 | *
|
---|
| 15 | * The above copyright notice and this permission notice shall be
|
---|
| 16 | * included in all copies or substantial portions of the Software.
|
---|
| 17 | *
|
---|
| 18 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
---|
| 19 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
---|
| 20 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
---|
| 21 | * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
---|
| 22 | * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
---|
| 23 | * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
---|
| 24 | * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
---|
| 25 | * ----------------------------------------------------------------------*/
|
---|
| 26 | #include <string.h>
|
---|
| 27 | #include <limits.h>
|
---|
| 28 | #include <time.h>
|
---|
| 29 | //#include <errno.h>
|
---|
| 30 | #define EOVERFLOW 75
|
---|
| 31 |
|
---|
| 32 | int t_errno;
|
---|
| 33 |
|
---|
| 34 | /* 2000-03-01 (mod 400 year, immediately after feb29 */
|
---|
| 35 | #define LEAPOCH (946684800LL + 86400*(31+29))
|
---|
| 36 |
|
---|
| 37 | #define DAYS_PER_400Y (365*400 + 97)
|
---|
| 38 | #define DAYS_PER_100Y (365*100 + 24)
|
---|
| 39 | #define DAYS_PER_4Y (365*4 + 1)
|
---|
| 40 |
|
---|
| 41 | int __secs_to_tm(long long t, struct tm* tm)
|
---|
| 42 | {
|
---|
| 43 | long long days, secs, years;
|
---|
| 44 | int remdays, remsecs, remyears;
|
---|
| 45 | int qc_cycles, c_cycles, q_cycles;
|
---|
| 46 | int months;
|
---|
| 47 | int wday, yday, leap;
|
---|
| 48 | static const char days_in_month[] = {31,30,31,30,31,31,30,31,30,31,31,29};
|
---|
| 49 |
|
---|
| 50 | /* Reject time_t values whose year would overflow int */
|
---|
| 51 | if (t < INT_MIN * 31622400LL || t > INT_MAX * 31622400LL)
|
---|
| 52 | return -1;
|
---|
| 53 |
|
---|
| 54 | secs = t - LEAPOCH;
|
---|
| 55 | days = secs / 86400;
|
---|
| 56 | remsecs = secs % 86400;
|
---|
| 57 | if (remsecs < 0) {
|
---|
| 58 | remsecs += 86400;
|
---|
| 59 | days--;
|
---|
| 60 | }
|
---|
| 61 |
|
---|
| 62 | wday = (3 + days) % 7;
|
---|
| 63 | if (wday < 0) wday += 7;
|
---|
| 64 |
|
---|
| 65 | qc_cycles = days / DAYS_PER_400Y;
|
---|
| 66 | remdays = days % DAYS_PER_400Y;
|
---|
| 67 | if (remdays < 0) {
|
---|
| 68 | remdays += DAYS_PER_400Y;
|
---|
| 69 | qc_cycles--;
|
---|
| 70 | }
|
---|
| 71 |
|
---|
| 72 | c_cycles = remdays / DAYS_PER_100Y;
|
---|
| 73 | if (c_cycles == 4) c_cycles--;
|
---|
| 74 | remdays -= c_cycles * DAYS_PER_100Y;
|
---|
| 75 |
|
---|
| 76 | q_cycles = remdays / DAYS_PER_4Y;
|
---|
| 77 | if (q_cycles == 25) q_cycles--;
|
---|
| 78 | remdays -= q_cycles * DAYS_PER_4Y;
|
---|
| 79 |
|
---|
| 80 | remyears = remdays / 365;
|
---|
| 81 | if (remyears == 4) remyears--;
|
---|
| 82 | remdays -= remyears * 365;
|
---|
| 83 |
|
---|
| 84 | leap = !remyears && (q_cycles || !c_cycles);
|
---|
| 85 | yday = remdays + 31 + 28 + leap;
|
---|
| 86 | if (yday >= 365 + leap) yday -= 365 + leap;
|
---|
| 87 |
|
---|
| 88 | years = remyears + 4 * q_cycles + 100 * c_cycles + 400LL * qc_cycles;
|
---|
| 89 |
|
---|
| 90 | for (months = 0; days_in_month[months] <= remdays; months++)
|
---|
| 91 | remdays -= days_in_month[months];
|
---|
| 92 |
|
---|
| 93 | if (years + 100 > INT_MAX || years + 100 < INT_MIN)
|
---|
| 94 | return -1;
|
---|
| 95 |
|
---|
| 96 | tm->tm_year = years + 100;
|
---|
| 97 | tm->tm_mon = months + 2;
|
---|
| 98 | if (tm->tm_mon >= 12) {
|
---|
| 99 | tm->tm_mon -= 12;
|
---|
| 100 | tm->tm_year++;
|
---|
| 101 | }
|
---|
| 102 | tm->tm_mday = remdays + 1;
|
---|
| 103 | tm->tm_wday = wday;
|
---|
| 104 | tm->tm_yday = yday;
|
---|
| 105 |
|
---|
| 106 | tm->tm_hour = remsecs / 3600;
|
---|
| 107 | tm->tm_min = remsecs / 60 % 60;
|
---|
| 108 | tm->tm_sec = remsecs % 60;
|
---|
| 109 |
|
---|
| 110 | return 0;
|
---|
| 111 | }
|
---|
| 112 |
|
---|
| 113 | long long __year_to_secs(long long year, int *is_leap)
|
---|
| 114 | {
|
---|
| 115 | if (year - 2ULL <= 136) {
|
---|
| 116 | int y = year;
|
---|
| 117 | int leaps = (y - 68) >> 2;
|
---|
| 118 | if (!((y - 68) & 3)) {
|
---|
| 119 | leaps--;
|
---|
| 120 | if (is_leap) *is_leap = 1;
|
---|
| 121 | }
|
---|
| 122 | else if (is_leap) *is_leap = 0;
|
---|
| 123 | return 31536000 * (y - 70) + 86400 * leaps;
|
---|
| 124 | }
|
---|
| 125 |
|
---|
| 126 | int cycles, centuries, leaps, rem;
|
---|
| 127 |
|
---|
| 128 | if (!is_leap) is_leap = &(int) { 0 };
|
---|
| 129 | cycles = (year - 100) / 400;
|
---|
| 130 | rem = (year - 100) % 400;
|
---|
| 131 | if (rem < 0) {
|
---|
| 132 | cycles--;
|
---|
| 133 | rem += 400;
|
---|
| 134 | }
|
---|
| 135 | if (!rem) {
|
---|
| 136 | *is_leap = 1;
|
---|
| 137 | centuries = 0;
|
---|
| 138 | leaps = 0;
|
---|
| 139 | }
|
---|
| 140 | else {
|
---|
| 141 | if (rem >= 200) {
|
---|
| 142 | if (rem >= 300) centuries = 3, rem -= 300;
|
---|
| 143 | else centuries = 2, rem -= 200;
|
---|
| 144 | }
|
---|
| 145 | else {
|
---|
| 146 | if (rem >= 100) centuries = 1, rem -= 100;
|
---|
| 147 | else centuries = 0;
|
---|
| 148 | }
|
---|
| 149 | if (!rem) {
|
---|
| 150 | *is_leap = 0;
|
---|
| 151 | leaps = 0;
|
---|
| 152 | }
|
---|
| 153 | else {
|
---|
| 154 | leaps = rem / 4U;
|
---|
| 155 | rem %= 4U;
|
---|
| 156 | *is_leap = !rem;
|
---|
| 157 | }
|
---|
| 158 | }
|
---|
| 159 |
|
---|
| 160 | leaps += 97 * cycles + 24 * centuries - *is_leap;
|
---|
| 161 |
|
---|
| 162 | return (year - 100) * 31536000LL + leaps * 86400LL + 946684800 + 86400;
|
---|
| 163 | }
|
---|
| 164 |
|
---|
| 165 | int __month_to_secs(int month, int is_leap)
|
---|
| 166 | {
|
---|
| 167 | static const int secs_through_month[] = {
|
---|
| 168 | 0, 31 * 86400, 59 * 86400, 90 * 86400,
|
---|
| 169 | 120 * 86400, 151 * 86400, 181 * 86400, 212 * 86400,
|
---|
| 170 | 243 * 86400, 273 * 86400, 304 * 86400, 334 * 86400};
|
---|
| 171 | int t = secs_through_month[month];
|
---|
| 172 | if (is_leap && month >= 2) t += 86400;
|
---|
| 173 | return t;
|
---|
| 174 | }
|
---|
| 175 |
|
---|
| 176 | long long __tm_to_secs(const struct tm *tm)
|
---|
| 177 | {
|
---|
| 178 | int is_leap;
|
---|
| 179 | long long year = tm->tm_year;
|
---|
| 180 | int month = tm->tm_mon;
|
---|
| 181 | if (month >= 12 || month < 0) {
|
---|
| 182 | int adj = month / 12;
|
---|
| 183 | month %= 12;
|
---|
| 184 | if (month < 0) {
|
---|
| 185 | adj--;
|
---|
| 186 | month += 12;
|
---|
| 187 | }
|
---|
| 188 | year += adj;
|
---|
| 189 | }
|
---|
| 190 | long long t = __year_to_secs(year, &is_leap);
|
---|
| 191 | t += __month_to_secs(month, is_leap);
|
---|
| 192 | t += 86400LL * (tm->tm_mday - 1);
|
---|
| 193 | t += 3600LL * tm->tm_hour;
|
---|
| 194 | t += 60LL * tm->tm_min;
|
---|
| 195 | t += tm->tm_sec;
|
---|
| 196 | return t;
|
---|
| 197 | }
|
---|
| 198 |
|
---|
| 199 | struct tm *localtime_r(const time_t *t, struct tm *tm)
|
---|
| 200 | {
|
---|
| 201 | /* Reject time_t values whose year would overflow int because
|
---|
| 202 | * __secs_to_zone cannot safely handle them. */
|
---|
| 203 | if (*t < INT_MIN * 31622400LL || *t > INT_MAX * 31622400LL) {
|
---|
| 204 | t_errno = EOVERFLOW;
|
---|
| 205 | return 0;
|
---|
| 206 | }
|
---|
| 207 | //TODO:__secs_to_zone(*t, 0, &tm->tm_isdst, &tm->__tm_gmtoff, 0, &tm->__tm_zone);
|
---|
| 208 | if (__secs_to_tm((long long)*t /*+ tm->__tm_gmtoff*/, tm) < 0) {
|
---|
| 209 | t_errno = EOVERFLOW;
|
---|
| 210 | return 0;
|
---|
| 211 | }
|
---|
| 212 | return tm;
|
---|
| 213 | }
|
---|
| 214 |
|
---|
| 215 | struct tm *localtime(const time_t *time)
|
---|
| 216 | {
|
---|
| 217 | static struct tm tm;
|
---|
| 218 | return localtime_r(time, &tm);
|
---|
| 219 | }
|
---|
| 220 |
|
---|
| 221 | struct tm *gmtime_r(const time_t *t, struct tm *tm)
|
---|
| 222 | {
|
---|
| 223 | if (__secs_to_tm(*t, tm) < 0) {
|
---|
| 224 | t_errno = EOVERFLOW;
|
---|
| 225 | return 0;
|
---|
| 226 | }
|
---|
| 227 | tm->tm_isdst = 0;
|
---|
| 228 | /*tm->__tm_gmtoff = 0;
|
---|
| 229 | tm->__tm_zone = NULL;//__gmt;*/
|
---|
| 230 | return tm;
|
---|
| 231 | }
|
---|
| 232 |
|
---|
| 233 | /* There is no other implemented value than TIME_UTC; all other values
|
---|
| 234 | * are considered erroneous. */
|
---|
| 235 | /*int timespec_get(struct timespec * ts, int base)
|
---|
| 236 | {
|
---|
| 237 | if (base != TIME_UTC) return 0;
|
---|
| 238 | int ret = __clock_gettime(CLOCK_REALTIME, ts);
|
---|
| 239 | return ret < 0 ? 0 : base;
|
---|
| 240 | }*/
|
---|
| 241 | time_t mktime(struct tm *tm)
|
---|
| 242 | {
|
---|
| 243 | struct tm new;
|
---|
| 244 | long opp;
|
---|
| 245 | long long t = __tm_to_secs(tm);
|
---|
| 246 |
|
---|
| 247 | if (__secs_to_tm(t, &new) < 0) goto error;
|
---|
| 248 |
|
---|
| 249 | *tm = new;
|
---|
| 250 | return t;
|
---|
| 251 |
|
---|
| 252 | error:
|
---|
| 253 | t_errno = EOVERFLOW;
|
---|
| 254 | return -1;
|
---|
| 255 | }
|
---|