* Copyright (c) 1983 Eric P. Allman
* Copyright (c) 1988 Regents of the University of California.
* %sccs.include.redist.c%
static char sccsid
[] = "@(#)arpadate.c 6.2 (Berkeley) %G%";
** ARPADATE -- Create date in ARPANET format
** ud -- unix style date string. if NULL, one is created.
** pointer to an ARPANET date field
** date is stored in a local buffer -- subsequent
** Timezone is computed from local time, rather than
** from whereever (and whenever) the message was sent.
** To do better is very hard.
** Some sites are now inserting the timezone into the
** local date. This routine should figure out what
** the format is and work appropriately.
extern struct tm
*localtime(), *gmtime();
** This will be used if a null argument is passed and
** to resolve the timezone.
** Crack the UNIX date line in a singularly unoriginal way.
p
= &ud
[11]; /* 01:03:52 */
* should really get the timezone from the time in "ud" (which
* is only different if a non-null arg was passed which is different
* from the current time), but for all practical purposes, returning
* the current local zone will do (its all that is ever needed).
off
= (lt
->tm_hour
- gmt
.tm_hour
) * 60 + lt
->tm_min
- gmt
.tm_min
;
/* assume that offset isn't more than a day ... */
if (lt
->tm_year
< gmt
.tm_year
)
else if (lt
->tm_year
> gmt
.tm_year
)
else if (lt
->tm_yday
< gmt
.tm_yday
)
else if (lt
->tm_yday
> gmt
.tm_yday
)
if (off
>= 24*60) /* should be impossible */
off
= 23*60+59; /* if not, insert silly value */
*q
++ = (off
/ 600) + '0';
*q
++ = (off
/ 60) % 10 + '0';
** NEXTATOM -- Return pointer to next atom in header
** (skip whitespace and comments)
** s -- pointer to header string
** pointer advanced to next non-comment header atom
*p
&& (*p
== ' ' || *p
== '\t' || *p
== '\n' || *p
== '(');
** ARPATOUNIX -- Convert RFC-822/1123 date-time specification to ctime format.
** s -- pointer to date string
** pointer to a string in ctime format
** Calls asctime() which modifies its static area.
** date-time field specification from RFC822
** as amended by RFC 1123:
** [ day "," ] 1*2DIGIT month 2*4DIGIT \
** 2DIGIT ":" 2DIGIT [ ":" 2DIGIT ] zone
** Day can be "Mon" "Tue" "Wed" "Thu" "Fri" "Sat" "Sun"
** Month can be "Jan" "Feb" "Mar" "Apr" "May" "Jun" "Jul"
** "Aug" "Sep" "Oct" "Nov" "Dec" (also case-insensitive)
** Zone can be "UT" "GMT" "EST" "EDT" "CST" "CDT" "MST" "MDT"
** "PST" "PDT" or "+"4*DIGIT or "-"4*DIGIT
** (case-insensitive; military zones not useful
** Additional whitespace or comments may occur.
static char MonthDays
[] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
int h_offset
= 0; /* hours */
int m_offset
= 0; /* minutes */
extern char *DowList
[]; /* defined in collect.c */
extern char *MonthList
[]; /* defined in collect.c */
bzero((char *) &tm
, sizeof tm
);
tm
.tm_wday
= -1; /* impossible value */
/* next atom must be a day or a date */
for (tm
.tm_wday
= 0; DowList
[tm
.tm_wday
]; tm
.tm_wday
++)
if (strncasecmp (p
, DowList
[tm
.tm_wday
], 3))
p
= nextatom(p
); /* ',' */
while (isdigit((int) *p
)) /* skip over date */
p
= nextatom(p
); /* point to month name */
for (tm
.tm_mon
= 0; MonthList
[tm
.tm_mon
]; tm
.tm_mon
++)
if (strncasecmp(p
, MonthList
[tm
.tm_mon
], 3) == 0)
p
= nextatom(p
); /* year */
/* if this was 4 digits, subtract 1900 */
/* if 2 or 3 digits, guess which century and convert */
/* more likely +1 day than -100(0) years */
if (gmt
->tm_mon
== 11 && gmt
->tm_mday
== 31 &&
tm
.tm_mon
== 0 && tm
.tm_mday
== 1)
tm
.tm_year
+= ((gmt
->tm_year
+ 900 - tm
.tm_year
) / 1000) * 1000;
tm
.tm_year
+= ((gmt
->tm_year
- tm
.tm_year
) / 100) * 100;
while (isdigit((int) *p
)) /* skip over year */
p
= nextatom(p
); /* hours */
while (isdigit((int) *p
)) /* skip over hours */
p
= nextatom(p
); /* colon */
p
= nextatom(p
); /* minutes */
while (isdigit((int) *p
)) /* skip over minutes */
p
= nextatom(p
); /* colon or zone */
if (*p
== ':') /* have seconds field */
while (isdigit((int) *p
)) /* skip over seconds */
p
= nextatom(p
); /* zone */
if (!strncasecmp(p
, "UT", 2) || !strncasecmp(p
, "GMT", 3))
else if (!strncasecmp(p
, "EDT", 3))
else if (!strncasecmp(p
, "EST", 3))
else if (!strncasecmp(p
, "CDT", 3))
else if (!strncasecmp(p
, "CST", 3))
else if (!strncasecmp(p
, "MDT", 3))
else if (!strncasecmp(p
, "MST", 3))
else if (!strncasecmp(p
, "PDT", 3))
else if (!strncasecmp(p
, "PST", 3))
m_offset
= -1 * (off
% 100);
syslog(LOG_NOTICE
, "%s: arpatounix: unparseable date: %s",
/* is the year a leap year? */
if ((tm
.tm_year
% 4 == 0) &&
((tm
.tm_year
% 100 != 0) || (tm
.tm_year
% 400 == 0)))
if (h_offset
|| m_offset
)
else if (tm
.tm_hour
> 23)
/* is the year a leap year? */
if ((tm
.tm_year
% 4 == 0) &&
((tm
.tm_year
% 100 != 0) || (tm
.tm_year
% 400 == 0)))
tm
.tm_mday
+= MonthDays
[tm
.tm_mon
];
else if (tm
.tm_mday
> MonthDays
[tm
.tm_mon
])
tm
.tm_mday
-= MonthDays
[tm
.tm_mon
++];
* Don't have to worry about leap years in
/* determine day of week if not set from RFC822/1123 line */
for (i
= 0; i
< tm
.tm_mon
; i
++)
tm
.tm_yday
+= MonthDays
[i
];
tm
.tm_yday
+= tm
.tm_mday
;
/* I wouldn't change these constants if I were you... */
tm
.tm_wday
= (int) (((((tm
.tm_year
+ 699L) * 146097L) / 400L) + tm
.tm_yday
) % 7);
if ((p
= asctime(&tm
)) == NULL
|| *p
== '\0' || strlen(p
) < 25)
syslog(LOG_NOTICE
, "%s: arpatounix: asctime failed: %s",
if ((n
= index(p
, '\n')) != NULL
)