4 * Copyright (C) 1993-1999 by Jochen Wiedmann and Marcin Orlowski
5 * Copyright (C) 2002-2015 FlexCat Open Source Team
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or (at
10 * your option) any later version.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 // parse a date string produced by strftime() and put the success in a struct tm
45 #define FLG_SEC (1<<0)
46 #define FLG_MIN (1<<1)
47 #define FLG_HOUR (1<<2)
48 #define FLG_MDAY (1<<3)
49 #define FLG_MON (1<<4)
50 #define FLG_YEAR (1<<5)
51 #define FLG_WDAY (1<<6)
52 #define FLG_YDAY (1<<7)
53 #define FLG_ISDST (1<<8)
54 #define FLG_4DIGIT_YEAR (1<<9)
56 char *strptime(const char *string
, const char *fmt
, struct tm
*res
)
61 enum ScanDateState state
= SDS_DEFAULT
;
64 // start with the first character in both strings
68 while(state
!= SDS_DONE
)
70 if(fc
== '\0' && sc
== '\0')
79 state
= SDS_SPECIFIER
;
84 // the format string seems to be malformed, bail out
94 case 'd': // %d - day number with leading zeros (01-31)
95 case 'e': // %e - day number with leading spaces ( 1-31)
98 state
= SDS_DAY_OF_MONTH
;
103 case 'm': // %m - month number with leading zeros (01-12)
111 case 'Y': // %Y - year using four digits with leading zeros
113 flags
|= FLG_4DIGIT_YEAR
;
115 // we fall through here
117 case 'y': // %y - year using two digits with leading zeros (00-99)
127 // ignore any switches between with/without leading zeros/spaces
134 // unknown specifier, bail out
142 case SDS_DAY_OF_MONTH
:
146 // next separator in format string found
151 else if(sc
>= '0' && sc
<= '9')
153 // valid number found, add it to the day of month
154 res
->tm_mday
= res
->tm_mday
* 10 + sc
- '0';
159 // unexpected character, bail out
169 // next separator in format string found
174 else if(sc
>= '0' && sc
<= '9')
176 // valid number found, add it to the month
177 res
->tm_mon
= res
->tm_mon
* 10 + sc
- '0';
182 // unexpected character, bail out
192 // next separator in format string found
197 else if(sc
>= '0' && sc
<= '9')
199 // valid number found, add it to the year
200 res
->tm_year
= res
->tm_year
* 10 + sc
- '0';
205 // unexpected character, bail out
217 // finally check if the calculated values are correct, but only those which
218 // were specified in the format string
219 if((flags
& FLG_MDAY
) || strstr(fmt
, "%d") != NULL
|| strstr(fmt
, "%-d") != NULL
|| strstr(fmt
, "%e") != NULL
)
221 if(res
->tm_mday
>= 1 && res
->tm_mday
<= 31)
230 if((flags
& FLG_MON
) || strstr(fmt
, "%m") != NULL
|| strstr(fmt
, "%-m") != NULL
)
232 if(res
->tm_mon
>= 1 && res
->tm_mon
<= 12)
234 // tm_mon counts from 0 to 11
242 if((flags
& FLG_YEAR
) || strstr(fmt
, "%y") != NULL
|| strstr(fmt
, "%-y") != NULL
|| strstr(fmt
, "%Y") != NULL
|| strstr(fmt
, "%-Y") != NULL
)
244 if((flags
& FLG_4DIGIT_YEAR
) || strstr(fmt
, "%Y") != NULL
|| strstr(fmt
, "%-Y") != NULL
)
246 if(res
->tm_year
>= 1900)
248 // tm_year counts the years from 1900
249 res
->tm_year
-= 1900;
253 // year numbers less than 1900 are not supported
259 // 2 digit year number, must be less than 100
260 if(res
->tm_year
< 100)
262 if(res
->tm_year
< 40)
264 // tm_year counts the years from 1900
265 // if the year number is less than 40 we assume a year between
266 // 2000 and 2039 instead of between 1900 and 1939 to allow a user
267 // age of at least ~70 years.
271 // Although we expect a two digit year number for %y we got one with more digits.
272 // Better not fail at this even if the entered string is wrong. People tend to
273 // forget the correct formatting.
274 else if(res
->tm_year
>= 1900)
276 // tm_year counts the years from 1900
277 res
->tm_year
-= 1900;
281 // numbers between 100 and 1899 are definitely not allowed
287 // finally check if the day value is correct
288 if(success
== 1 && (flags
& FLG_MDAY
))
292 // February has 29 days at most, but we don't check for leap years here
293 if(res
->tm_mday
> 29)
298 else if(res
->tm_mon
== 3 ||
303 // April, June, September and November have 30 days
304 if(res
->tm_mday
> 30)
311 return (char *)string
;