1 /* tdate_parse - parse string dates into internal form, stripped-down version
3 ** Copyright © 1995 by Jef Poskanzer <jef@mail.acme.com>.
4 ** All rights reserved.
6 ** Redistribution and use in source and binary forms, with or without
7 ** modification, are permitted provided that the following conditions
9 ** 1. Redistributions of source code must retain the above copyright
10 ** notice, this list of conditions and the following disclaimer.
11 ** 2. Redistributions in binary form must reproduce the above copyright
12 ** notice, this list of conditions and the following disclaimer in the
13 ** documentation and/or other materials provided with the distribution.
15 ** THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 ** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 ** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 ** ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 ** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 ** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 ** OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 ** HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 ** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 ** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 /* This is a stripped-down version of date_parse.c, available at
29 ** http://www.acme.com/software/date_parse/
32 #include <sys/types.h>
43 #include "tdate_parse.h"
53 pound_case( char* str
)
55 for ( ; *str
!= '\0'; ++str
)
57 if ( isupper( (int) *str
) )
58 *str
= tolower( (int) *str
);
63 //strlong_compare( v1, v2 )
67 // return strcmp( ((struct strlong*) v1)->s, ((struct strlong*) v2)->s );
72 strlong_search( char* str
, const struct strlong
* tab
, int n
, long* lP
)
81 r
= strcmp( str
, tab
[i
].s
);
98 scan_wday( char* str_wday
, long* tm_wdayP
)
100 // static struct strlong wday_tab[] = {
101 // { "sun", 0 }, { "sunday", 0 },
102 // { "mon", 1 }, { "monday", 1 },
103 // { "tue", 2 }, { "tuesday", 2 },
104 // { "wed", 3 }, { "wednesday", 3 },
105 // { "thu", 4 }, { "thursday", 4 },
106 // { "fri", 5 }, { "friday", 5 },
107 // { "sat", 6 }, { "saturday", 6 },
109 // static int sorted = 0;
114 // wday_tab, sizeof(wday_tab)/sizeof(struct strlong),
115 // sizeof(struct strlong), strlong_compare );
119 /*manually sorted wday_tab to avoid concurrent accessing problem*/
120 static const struct strlong wday_tab
[] = {
121 { "fri", 5 }, { "friday", 5 },
122 { "mon", 1 }, { "monday", 1 },
123 { "sat", 6 }, { "saturday", 6 },
124 { "sun", 0 }, { "sunday", 0 },
125 { "thu", 4 }, { "thursday", 4 },
126 { "tue", 2 }, { "tuesday", 2 },
127 { "wed", 3 }, { "wednesday", 3 }
130 pound_case( str_wday
);
131 return strlong_search(
132 str_wday
, wday_tab
, sizeof(wday_tab
)/sizeof(struct strlong
), tm_wdayP
);
137 scan_mon( char* str_mon
, long* tm_monP
)
139 // static struct strlong mon_tab[] = {
140 // { "jan", 0 }, { "january", 0 },
141 // { "feb", 1 }, { "february", 1 },
142 // { "mar", 2 }, { "march", 2 },
143 // { "apr", 3 }, { "april", 3 },
145 // { "jun", 5 }, { "june", 5 },
146 // { "jul", 6 }, { "july", 6 },
147 // { "aug", 7 }, { "august", 7 },
148 // { "sep", 8 }, { "september", 8 },
149 // { "oct", 9 }, { "october", 9 },
150 // { "nov", 10 }, { "november", 10 },
151 // { "dec", 11 }, { "december", 11 },
153 // static int sorted = 0;
158 // mon_tab, sizeof(mon_tab)/sizeof(struct strlong),
159 // sizeof(struct strlong), strlong_compare );
163 /*manually sorted mon_tab to avoid concurrent accessing problem*/
164 static const struct strlong mon_tab
[] = {
165 { "apr", 3 }, { "april", 3 },
166 { "aug", 7 }, { "august", 7 },
167 { "dec", 11}, { "december", 11 },
168 { "feb", 1 }, { "february", 1 },
169 { "jan", 0 }, { "january", 0 },
170 { "jul", 6 }, { "july", 6 },
171 { "jun", 5 }, { "june", 5 },
172 { "mar", 2 }, { "march", 2 },
174 { "nov", 10}, { "november", 10 },
175 { "oct", 9 }, { "october", 9 },
176 { "sep", 8 }, { "september", 8 }
179 pound_case( str_mon
);
180 return strlong_search(
181 str_mon
, mon_tab
, sizeof(mon_tab
)/sizeof(struct strlong
), tm_monP
);
188 return year
% 400? ( year
% 100 ? ( year
% 4 ? 0 : 1 ) : 0 ) : 1;
192 /* Basically the same as mktime(). */
194 tm_to_time( struct tm
* tmP
)
197 static int monthtab
[12] = {
198 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
200 /* Years since epoch, converted to days. */
201 t
= ( tmP
->tm_year
- 70 ) * 365;
202 /* Leap days for previous years. */
203 t
+= ( tmP
->tm_year
- 69 ) / 4;
204 /* Days for the beginning of this month. */
205 t
+= monthtab
[tmP
->tm_mon
];
206 /* Leap day for this year. */
207 if ( tmP
->tm_mon
>= 2 && is_leap( tmP
->tm_year
+ 1900 ) )
209 /* Days since the beginning of this month. */
210 t
+= tmP
->tm_mday
- 1; /* 1-based field */
211 /* Hours, minutes, and seconds. */
212 t
= t
* 24 + tmP
->tm_hour
;
213 t
= t
* 60 + tmP
->tm_min
;
214 t
= t
* 60 + tmP
->tm_sec
;
221 tdate_parse( char* str
)
225 char str_mon
[500], str_wday
[500];
226 int tm_sec
, tm_min
, tm_hour
, tm_mday
, tm_year
;
227 long tm_mon
, tm_wday
;
231 (void) memset( (char*) &tm
, 0, sizeof(struct tm
) );
233 /* Skip initial whitespace ourselves - sscanf is clumsy at this. */
234 for ( cp
= str
; *cp
== ' ' || *cp
== '\t'; ++cp
)
237 /* And do the sscanfs. WARNING: you can add more formats here,
238 ** but be careful! You can easily screw up the parsing of existing
239 ** formats when you add new ones. The order is important.
242 /* DD-mth-YY HH:MM:SS GMT */
243 if ( sscanf( cp
, "%d-%400[a-zA-Z]-%d %d:%d:%d GMT",
244 &tm_mday
, str_mon
, &tm_year
, &tm_hour
, &tm_min
,
246 scan_mon( str_mon
, &tm_mon
) )
248 tm
.tm_mday
= tm_mday
;
250 tm
.tm_year
= tm_year
;
251 tm
.tm_hour
= tm_hour
;
256 /* DD mth YY HH:MM:SS GMT */
257 else if ( sscanf( cp
, "%d %400[a-zA-Z] %d %d:%d:%d GMT",
258 &tm_mday
, str_mon
, &tm_year
, &tm_hour
, &tm_min
,
260 scan_mon( str_mon
, &tm_mon
) )
262 tm
.tm_mday
= tm_mday
;
264 tm
.tm_year
= tm_year
;
265 tm
.tm_hour
= tm_hour
;
270 /* HH:MM:SS GMT DD-mth-YY */
271 else if ( sscanf( cp
, "%d:%d:%d GMT %d-%400[a-zA-Z]-%d",
272 &tm_hour
, &tm_min
, &tm_sec
, &tm_mday
, str_mon
,
274 scan_mon( str_mon
, &tm_mon
) )
276 tm
.tm_hour
= tm_hour
;
279 tm
.tm_mday
= tm_mday
;
281 tm
.tm_year
= tm_year
;
284 /* HH:MM:SS GMT DD mth YY */
285 else if ( sscanf( cp
, "%d:%d:%d GMT %d %400[a-zA-Z] %d",
286 &tm_hour
, &tm_min
, &tm_sec
, &tm_mday
, str_mon
,
288 scan_mon( str_mon
, &tm_mon
) )
290 tm
.tm_hour
= tm_hour
;
293 tm
.tm_mday
= tm_mday
;
295 tm
.tm_year
= tm_year
;
298 /* wdy, DD-mth-YY HH:MM:SS GMT */
299 else if ( sscanf( cp
, "%400[a-zA-Z], %d-%400[a-zA-Z]-%d %d:%d:%d GMT",
300 str_wday
, &tm_mday
, str_mon
, &tm_year
, &tm_hour
, &tm_min
,
302 scan_wday( str_wday
, &tm_wday
) &&
303 scan_mon( str_mon
, &tm_mon
) )
305 tm
.tm_wday
= tm_wday
;
306 tm
.tm_mday
= tm_mday
;
308 tm
.tm_year
= tm_year
;
309 tm
.tm_hour
= tm_hour
;
314 /* wdy, DD mth YY HH:MM:SS GMT */
315 else if ( sscanf( cp
, "%400[a-zA-Z], %d %400[a-zA-Z] %d %d:%d:%d GMT",
316 str_wday
, &tm_mday
, str_mon
, &tm_year
, &tm_hour
, &tm_min
,
318 scan_wday( str_wday
, &tm_wday
) &&
319 scan_mon( str_mon
, &tm_mon
) )
321 tm
.tm_wday
= tm_wday
;
322 tm
.tm_mday
= tm_mday
;
324 tm
.tm_year
= tm_year
;
325 tm
.tm_hour
= tm_hour
;
330 /* wdy mth DD HH:MM:SS GMT YY */
331 else if ( sscanf( cp
, "%400[a-zA-Z] %400[a-zA-Z] %d %d:%d:%d GMT %d",
332 str_wday
, str_mon
, &tm_mday
, &tm_hour
, &tm_min
, &tm_sec
,
334 scan_wday( str_wday
, &tm_wday
) &&
335 scan_mon( str_mon
, &tm_mon
) )
337 tm
.tm_wday
= tm_wday
;
339 tm
.tm_mday
= tm_mday
;
340 tm
.tm_hour
= tm_hour
;
343 tm
.tm_year
= tm_year
;
348 if ( tm
.tm_year
> 1900 )
350 else if ( tm
.tm_year
< 70 )
353 t
= tm_to_time( &tm
);