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 );
64 strlong_compare( const void* v1, const void* v2 )
66 const struct strlong* s1 = (const struct strlong*) v1;
67 const struct strlong* s2 = (const struct strlong*) v2;
68 return strcmp( s1->s, s2->s );
73 strlong_search( char* str, struct strlong* tab, int n, long* lP )
82 r = strcmp( str, tab[i].s );
99 scan_wday( char* str_wday, long* tm_wdayP )
101 static struct strlong wday_tab[] = {
102 { "sun", 0 }, { "sunday", 0 },
103 { "mon", 1 }, { "monday", 1 },
104 { "tue", 2 }, { "tuesday", 2 },
105 { "wed", 3 }, { "wednesday", 3 },
106 { "thu", 4 }, { "thursday", 4 },
107 { "fri", 5 }, { "friday", 5 },
108 { "sat", 6 }, { "saturday", 6 },
110 static int sorted = 0;
115 wday_tab, sizeof(wday_tab)/sizeof(struct strlong),
116 sizeof(struct strlong), strlong_compare );
119 pound_case( str_wday );
120 return strlong_search(
121 str_wday, wday_tab, sizeof(wday_tab)/sizeof(struct strlong), tm_wdayP );
126 scan_mon( char* str_mon, long* tm_monP )
128 static struct strlong mon_tab[] = {
129 { "jan", 0 }, { "january", 0 },
130 { "feb", 1 }, { "february", 1 },
131 { "mar", 2 }, { "march", 2 },
132 { "apr", 3 }, { "april", 3 },
134 { "jun", 5 }, { "june", 5 },
135 { "jul", 6 }, { "july", 6 },
136 { "aug", 7 }, { "august", 7 },
137 { "sep", 8 }, { "september", 8 },
138 { "oct", 9 }, { "october", 9 },
139 { "nov", 10 }, { "november", 10 },
140 { "dec", 11 }, { "december", 11 },
142 static int sorted = 0;
147 mon_tab, sizeof(mon_tab)/sizeof(struct strlong),
148 sizeof(struct strlong), strlong_compare );
151 pound_case( str_mon );
152 return strlong_search(
153 str_mon, mon_tab, sizeof(mon_tab)/sizeof(struct strlong), tm_monP );
160 return year % 400? ( year % 100 ? ( year % 4 ? 0 : 1 ) : 0 ) : 1;
164 /* Basically the same as mktime(). */
166 tm_to_time( struct tm* tmP )
169 static int monthtab[12] = {
170 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
172 /* Years since epoch, converted to days. */
173 t = ( tmP->tm_year - 70 ) * 365;
174 /* Leap days for previous years - this will break in 2100! */
175 t += ( tmP->tm_year - 69 ) / 4;
176 /* Days for the beginning of this month. */
177 t += monthtab[tmP->tm_mon];
178 /* Leap day for this year. */
179 if ( tmP->tm_mon >= 2 && is_leap( tmP->tm_year + 1900 ) )
181 /* Days since the beginning of this month. */
182 t += tmP->tm_mday - 1; /* 1-based field */
183 /* Hours, minutes, and seconds. */
184 t = t * 24 + tmP->tm_hour;
185 t = t * 60 + tmP->tm_min;
186 t = t * 60 + tmP->tm_sec;
193 tdate_parse( char* str )
197 char str_mon[500], str_wday[500];
198 int tm_sec, tm_min, tm_hour, tm_mday, tm_year;
199 long tm_mon, tm_wday;
203 (void) memset( (char*) &tm, 0, sizeof(struct tm) );
205 /* Skip initial whitespace ourselves - sscanf is clumsy at this. */
206 for ( cp = str; *cp == ' ' || *cp == '\t'; ++cp )
209 /* And do the sscanfs. WARNING: you can add more formats here,
210 ** but be careful! You can easily screw up the parsing of existing
211 ** formats when you add new ones. The order is important.
214 /* DD-mth-YY HH:MM:SS GMT */
215 if ( sscanf( cp, "%d-%400[a-zA-Z]-%d %d:%d:%d GMT",
216 &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
218 scan_mon( str_mon, &tm_mon ) )
220 tm.tm_mday = tm_mday;
222 tm.tm_year = tm_year;
223 tm.tm_hour = tm_hour;
228 /* DD mth YY HH:MM:SS GMT */
229 else if ( sscanf( cp, "%d %400[a-zA-Z] %d %d:%d:%d GMT",
230 &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
232 scan_mon( str_mon, &tm_mon ) )
234 tm.tm_mday = tm_mday;
236 tm.tm_year = tm_year;
237 tm.tm_hour = tm_hour;
242 /* HH:MM:SS GMT DD-mth-YY */
243 else if ( sscanf( cp, "%d:%d:%d GMT %d-%400[a-zA-Z]-%d",
244 &tm_hour, &tm_min, &tm_sec, &tm_mday, str_mon,
246 scan_mon( str_mon, &tm_mon ) )
248 tm.tm_hour = tm_hour;
251 tm.tm_mday = tm_mday;
253 tm.tm_year = tm_year;
256 /* HH:MM:SS GMT DD mth YY */
257 else if ( sscanf( cp, "%d:%d:%d GMT %d %400[a-zA-Z] %d",
258 &tm_hour, &tm_min, &tm_sec, &tm_mday, str_mon,
260 scan_mon( str_mon, &tm_mon ) )
262 tm.tm_hour = tm_hour;
265 tm.tm_mday = tm_mday;
267 tm.tm_year = tm_year;
270 /* wdy, DD-mth-YY HH:MM:SS GMT */
271 else if ( sscanf( cp, "%400[a-zA-Z], %d-%400[a-zA-Z]-%d %d:%d:%d GMT",
272 str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
274 scan_wday( str_wday, &tm_wday ) &&
275 scan_mon( str_mon, &tm_mon ) )
277 tm.tm_wday = tm_wday;
278 tm.tm_mday = tm_mday;
280 tm.tm_year = tm_year;
281 tm.tm_hour = tm_hour;
286 /* wdy, DD mth YY HH:MM:SS GMT */
287 else if ( sscanf( cp, "%400[a-zA-Z], %d %400[a-zA-Z] %d %d:%d:%d GMT",
288 str_wday, &tm_mday, str_mon, &tm_year, &tm_hour, &tm_min,
290 scan_wday( str_wday, &tm_wday ) &&
291 scan_mon( str_mon, &tm_mon ) )
293 tm.tm_wday = tm_wday;
294 tm.tm_mday = tm_mday;
296 tm.tm_year = tm_year;
297 tm.tm_hour = tm_hour;
302 /* wdy mth DD HH:MM:SS GMT YY */
303 else if ( sscanf( cp, "%400[a-zA-Z] %400[a-zA-Z] %d %d:%d:%d GMT %d",
304 str_wday, str_mon, &tm_mday, &tm_hour, &tm_min, &tm_sec,
306 scan_wday( str_wday, &tm_wday ) &&
307 scan_mon( str_mon, &tm_mon ) )
309 tm.tm_wday = tm_wday;
311 tm.tm_mday = tm_mday;
312 tm.tm_hour = tm_hour;
315 tm.tm_year = tm_year;
320 if ( tm.tm_year > 1900 )
322 else if ( tm.tm_year < 70 )
325 t = tm_to_time( &tm );