2 * Copyright (c) 1999 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of KTH nor the names of its contributors may be
18 * used to endorse or promote products derived from this software without
19 * specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
22 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
25 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
29 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
30 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
31 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
44 #include "../locale/setlocale.h"
46 #define _ctloc(x) (_CurrentTimeLocale->x)
48 static const int _DAYS_BEFORE_MONTH
[12] =
49 {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
56 #define SET_YMD (SET_YEAR | SET_MON | SET_MDAY)
59 * tm_year is relative this year
61 const int tm_year_base
= 1900;
64 * Return TRUE iff `year' was a leap year.
65 * Needed for strptime.
68 is_leap_year (int year
)
70 return (year
% 4) == 0 && ((year
% 100) != 0 || (year
% 400) == 0);
73 /* Needed for strptime. */
75 match_string (const char *__restrict
*buf
, const char * const*strs
,
80 for (i
= 0; strs
[i
] != NULL
; ++i
) {
81 int len
= strlen (strs
[i
]);
83 if (strncasecmp_l (*buf
, strs
[i
], len
, locale
) == 0) {
91 /* Needed for strptime. */
97 while (--year
>= 1970)
98 ret
= (ret
+ 365 + is_leap_year (year
)) % 7;
103 * Set `timeptr' given `wnum' (week number [0, 53])
104 * Needed for strptime
108 set_week_number_sun (struct tm
*timeptr
, int wnum
)
110 int fday
= first_day (timeptr
->tm_year
+ tm_year_base
);
112 timeptr
->tm_yday
= wnum
* 7 + timeptr
->tm_wday
- fday
;
113 if (timeptr
->tm_yday
< 0) {
114 timeptr
->tm_wday
= fday
;
115 timeptr
->tm_yday
= 0;
120 * Set `timeptr' given `wnum' (week number [0, 53])
121 * Needed for strptime
125 set_week_number_mon (struct tm
*timeptr
, int wnum
)
127 int fday
= (first_day (timeptr
->tm_year
+ tm_year_base
) + 6) % 7;
129 timeptr
->tm_yday
= wnum
* 7 + (timeptr
->tm_wday
+ 6) % 7 - fday
;
130 if (timeptr
->tm_yday
< 0) {
131 timeptr
->tm_wday
= (fday
+ 1) % 7;
132 timeptr
->tm_yday
= 0;
137 * Set `timeptr' given `wnum' (week number [0, 53])
138 * Needed for strptime
141 set_week_number_mon4 (struct tm
*timeptr
, int wnum
)
143 int fday
= (first_day (timeptr
->tm_year
+ tm_year_base
) + 6) % 7;
149 timeptr
->tm_yday
= offset
+ (wnum
- 1) * 7 + timeptr
->tm_wday
- fday
;
150 if (timeptr
->tm_yday
< 0) {
151 timeptr
->tm_wday
= fday
;
152 timeptr
->tm_yday
= 0;
157 strptime_l (const char *buf
, const char *format
, struct tm
*timeptr
,
163 const struct lc_time_T
*_CurrentTimeLocale
= __get_time_locale (locale
);
164 for (; (c
= *format
) != '\0'; ++format
) {
168 if (isspace_l ((unsigned char) c
, locale
)) {
169 while (isspace_l ((unsigned char) *buf
, locale
))
171 } else if (c
== '%' && format
[1] != '\0') {
173 if (c
== 'E' || c
== 'O')
177 ret
= match_string (&buf
, _ctloc (weekday
), locale
);
180 timeptr
->tm_wday
= ret
;
184 ret
= match_string (&buf
, _ctloc (wday
), locale
);
187 timeptr
->tm_wday
= ret
;
191 ret
= match_string (&buf
, _ctloc (month
), locale
);
194 timeptr
->tm_mon
= ret
;
199 ret
= match_string (&buf
, _ctloc (mon
), locale
);
202 timeptr
->tm_mon
= ret
;
206 ret
= strtol_l (buf
, &s
, 10, locale
);
209 timeptr
->tm_year
= (ret
* 100) - tm_year_base
;
213 case 'c' : /* %a %b %e %H:%M:%S %Y */
214 s
= strptime_l (buf
, _ctloc (c_fmt
), timeptr
, locale
);
218 ymd
|= SET_WDAY
| SET_YMD
;
220 case 'D' : /* %m/%d/%y */
221 s
= strptime_l (buf
, "%m/%d/%y", timeptr
, locale
);
229 ret
= strtol_l (buf
, &s
, 10, locale
);
232 timeptr
->tm_mday
= ret
;
236 case 'F' : /* %Y-%m-%d - GNU extension */
237 s
= strptime_l (buf
, "%Y-%m-%d", timeptr
, locale
);
238 if (s
== NULL
|| s
== buf
)
244 case 'k' : /* hour with leading space - GNU extension */
245 ret
= strtol_l (buf
, &s
, 10, locale
);
248 timeptr
->tm_hour
= ret
;
252 case 'l' : /* hour with leading space - GNU extension */
253 ret
= strtol_l (buf
, &s
, 10, locale
);
257 timeptr
->tm_hour
= 0;
259 timeptr
->tm_hour
= ret
;
263 ret
= strtol_l (buf
, &s
, 10, locale
);
266 timeptr
->tm_yday
= ret
- 1;
271 ret
= strtol_l (buf
, &s
, 10, locale
);
274 timeptr
->tm_mon
= ret
- 1;
279 ret
= strtol_l (buf
, &s
, 10, locale
);
282 timeptr
->tm_min
= ret
;
292 ret
= match_string (&buf
, _ctloc (am_pm
), locale
);
295 if (timeptr
->tm_hour
> 12)
297 else if (timeptr
->tm_hour
== 12)
298 timeptr
->tm_hour
= ret
* 12;
300 timeptr
->tm_hour
+= ret
* 12;
302 case 'q' : /* quarter year - GNU extension */
303 ret
= strtol_l (buf
, &s
, 10, locale
);
306 timeptr
->tm_mon
= (ret
- 1)*3;
310 case 'r' : /* %I:%M:%S %p */
311 s
= strptime_l (buf
, _ctloc (ampm_fmt
), timeptr
, locale
);
316 case 'R' : /* %H:%M */
317 s
= strptime_l (buf
, "%H:%M", timeptr
, locale
);
322 case 's' : /* seconds since Unix epoch - GNU extension */
330 sec
= strtoll_l (buf
, &s
, 10, locale
);
335 || localtime_r (&t
, timeptr
) != timeptr
)
339 ymd
|= SET_YDAY
| SET_WDAY
| SET_YMD
;
343 ret
= strtol_l (buf
, &s
, 10, locale
);
346 timeptr
->tm_sec
= ret
;
355 case 'T' : /* %H:%M:%S */
356 s
= strptime_l (buf
, "%H:%M:%S", timeptr
, locale
);
362 ret
= strtol_l (buf
, &s
, 10, locale
);
365 timeptr
->tm_wday
= ret
- 1;
370 ret
= strtol_l (buf
, &s
, 10, locale
);
373 timeptr
->tm_wday
= ret
;
378 ret
= strtol_l (buf
, &s
, 10, locale
);
381 set_week_number_sun (timeptr
, ret
);
386 ret
= strtol_l (buf
, &s
, 10, locale
);
389 set_week_number_mon4 (timeptr
, ret
);
394 ret
= strtol_l (buf
, &s
, 10, locale
);
397 set_week_number_mon (timeptr
, ret
);
402 s
= strptime_l (buf
, _ctloc (x_fmt
), timeptr
, locale
);
409 s
= strptime_l (buf
, _ctloc (X_fmt
), timeptr
, locale
);
415 ret
= strtol_l (buf
, &s
, 10, locale
);
419 timeptr
->tm_year
= 100 + ret
;
421 timeptr
->tm_year
= ret
;
426 ret
= strtol_l (buf
, &s
, 10, locale
);
429 timeptr
->tm_year
= ret
- tm_year_base
;
434 /* Unsupported. Just ignore. */
446 if (*buf
== '%' || *++buf
== c
)
460 if ((ymd
& SET_YMD
) == SET_YMD
) {
461 /* all of tm_year, tm_mon and tm_mday, but... */
463 if (!(ymd
& SET_YDAY
)) {
464 /* ...not tm_yday, so fill it in */
465 timeptr
->tm_yday
= _DAYS_BEFORE_MONTH
[timeptr
->tm_mon
]
467 if (!is_leap_year (timeptr
->tm_year
+ tm_year_base
)
468 || timeptr
->tm_mon
< 2)
475 else if ((ymd
& (SET_YEAR
| SET_YDAY
)) == (SET_YEAR
| SET_YDAY
)) {
476 /* both of tm_year and tm_yday, but... */
478 if (!(ymd
& SET_MON
)) {
479 /* ...not tm_mon, so fill it in, and/or... */
480 if (timeptr
->tm_yday
< _DAYS_BEFORE_MONTH
[1])
483 int leap
= is_leap_year (timeptr
->tm_year
+ tm_year_base
);
485 for (i
= 2; i
< 12; ++i
) {
486 if (timeptr
->tm_yday
< _DAYS_BEFORE_MONTH
[i
] + leap
)
489 timeptr
->tm_mon
= i
- 1;
493 if (!(ymd
& SET_MDAY
)) {
494 /* ...not tm_mday, so fill it in */
495 timeptr
->tm_mday
= timeptr
->tm_yday
496 - _DAYS_BEFORE_MONTH
[timeptr
->tm_mon
];
497 if (!is_leap_year (timeptr
->tm_year
+ tm_year_base
)
498 || timeptr
->tm_mon
< 2)
505 if ((ymd
& (SET_YEAR
| SET_YDAY
| SET_WDAY
)) == (SET_YEAR
| SET_YDAY
)) {
506 /* fill in tm_wday */
507 int fday
= first_day (timeptr
->tm_year
+ tm_year_base
);
508 timeptr
->tm_wday
= (fday
+ timeptr
->tm_yday
) % 7;
515 strptime (const char *buf
, const char *format
, struct tm
*timeptr
)
517 return strptime_l (buf
, format
, timeptr
, __get_current_locale ());