/* @(#)asctotime.c 4.2 (Melbourne) 82/02/15 */
* Asctotime by Mark Davoren (plus emitl and dcmp from unctime.c)
* Routines to take a date string and return the number of seconds
* since the epoch to 0:00 am that day (local time)
* There are 10 allowable formats
* where d, m and y represent day, month and year respectively.
* small letters mean a number, capitals mean a name.
* With the year either 19xx or xx is allowable.
* Times beyond the end of the 20th century are not handled.
* Any of the formats may include a time specification in the
* D : today <= D < today next week
* An optional '-' may directly precede the day name
* -D : today last week <= D < today
* This may also be suffixed by one of "week" or "fortnight"
* Most sensible abbreviations are allowable for day and month names,
* names can be of either upper, lower or mixed case.
* Formats 1-5 may have an optional 'st', 'nd', 'rd', 'th' after the day
* if the day is the first, second, third or later day of the month
* asctotime knows about leap years
#define error(s) { a2terr = s; return(-1); }
* Structures for days and months.
static struct daynum months
[] = {
* Getday is the main routine, which decodes the date string.
* It checks the values of each field and fills in default fields
register struct tm
*w
, *t
;
register int i
, mflag
= 0, flag678
= 0;
strncpy(copy
, p
, sizeof copy
- 1);
copy
[sizeof copy
- 1] = 0;
w
->tm_sec
= w
->tm_min
= w
->tm_hour
= 0;
if (q
= index(p
, ':')) { /* a time is specified */
while (isspace(*--q
) && q
> p
)
while (isdigit(*q
) && q
>= p
)
while (q
>= p
&& isspace(*q
))
s
= index(s
, ':')+1; /* ':' must exist */
if (index(s
, ':')) { /* have seconds */
else if (w
->tm_hour
== 12)
if (w
->tm_hour
> 23 || w
->tm_min
> 59 || w
->tm_sec
> 59)
/* now remove the time from the buffer */
if (strncmp(p
, "last", 4) == 0) {
} else if (strncmp(p
, "next", 4) == 0) {
} else if (*(p
-1) == '-')
/* if there is a word here put it into buff */
for (q
= buff
; isalpha(*p
) && q
< &buff
[bufmax
-1]; )
if (isdigit(*p
)) { /* Formats 1-5, 7, 8 */
if (w
->tm_mday
> 31) { /* must be a year instead */
if (flag678
) { /* Formats 7 or 8 */
if ((w
->tm_mon
= getname(months
, buff
) + 1) == 0)
} else if (isalpha(*p
)) { /* Formats 4, 5 */
for (q
= buff
; isalpha(*p
) && q
< &buff
[bufmax
-1]; )
if ((w
->tm_mon
= getname(months
, buff
) + 1) == 0)
} else { /* Formats 1-3 */
getends(w
->tm_mday
= getnum(&p
), &p
);
getends(w
->tm_year
= getnum(&p
), &p
);
error("month field too large");
if (w
->tm_mday
== 0 || w
->tm_mday
> months
[w
->tm_mon
].num
)
error("day field too large");
/* check for formats 1,2 and 5 */
if (w
->tm_mon
+ 8 < t
->tm_mon
&& mflag
<= 0)
/* check for 29th of feb in a non leap year */
&& !( w
->tm_year
% 4 == 0
|| w
->tm_year
% 400 == 0))
error("not a leap year");
else if (w
->tm_year
> 100 || w
->tm_year
< 70)
error("year field too small");
error("error in day name");
/* check for today & tomorrow & yesterday */
w
->tm_mday
= t
->tm_mday
- (t
->tm_wday
- i
);
if (mflag
> 0 && t
->tm_wday
<= i
)
if (mflag
== 0 && t
->tm_wday
> i
)
if (mflag
< 0 && t
->tm_wday
== i
)
if (strcmp(p
, "week") == 0)
else if (strcmp(p
, "fortnight") == 0)
/* allow for wrap around */
w
->tm_mday
+= months
[w
->tm_mon
].num
;
} else if (w
->tm_mday
> months
[w
->tm_mon
].num
) {
w
->tm_mday
-= months
[w
->tm_mon
].num
;
while(**pp
&& !isalpha(**pp
) && !isdigit(**pp
))
if (c0
== 's' && c1
== 't')
if (c0
== 'n' && c1
== 'd')
if (c0
== 'r' && c1
== 'd')
if (c0
== 't' && c1
== 'h')
while (*p
&& !isdigit(*p
))
sum
= sum
* 10 + *p
++ - '0';
* Getname searches arr an array of daynum structures for a name matching
* the name passed as an argument. The entries in the array consist
* of words with '_' delimiting abbreviations;
* eg 'mon_day' will match 'mon' or 'monday'
* Getname returns the index into arr which matches name or -1 if no match
register struct daynum
*i
;
for(i
= arr
; i
->name
; i
++) {
for (p
= name
, q
= i
->name
; *p
; p
++, q
++) {
if (*p
== '\0' && (*q
== '\0' || *q
== '_'))
* Routine to convert a localtime(3) format date back into
for (i
= 30; i
>= 0; i
--) {
if (dcmp(localtime(&conv
), dp
) > 0)
* Compare two localtime dates, return result.
register struct tm
*dp
, *dp2
;