/*++ /* NAME /* mail_date 3 /* SUMMARY /* return formatted time /* SYNOPSIS /* #include /* /* const char *mail_date(when) /* time_t when; /* DESCRIPTION /* mail_date() converts the time specified in \fIwhen\fR to the /* form: "Mon, 9 Dec 1996 05:38:26 -0500 (EST)" and returns /* a pointer to the result. The result is overwritten upon /* each call. /* DIAGNOSTICS /* Panic: the offset from UTC is more than a whole day. Fatal /* error: out of memory. /* LICENSE /* .ad /* .fi /* The Secure Mailer license must be distributed with this software. /* AUTHOR(S) /* Wietse Venema /* IBM T.J. Watson Research /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA /*--*/ /* System library. */ #include #include #include /* Utility library. */ #include #include /* Global library. */ #include "mail_date.h" /* * Application-specific. */ #define DAY_MIN (24 * HOUR_MIN) /* minutes in a day */ #define HOUR_MIN 60 /* minutes in an hour */ #define MIN_SEC 60 /* seconds in a minute */ /* mail_date - return formatted time */ const char *mail_date(time_t when) { static VSTRING *vp; struct tm *lt; struct tm gmt; int gmtoff; /* * As if strftime() isn't expensive enough, we're dynamically adjusting * the size for the result, so we won't be surprised by long names etc. */ if (vp == 0) vp = vstring_alloc(100); else VSTRING_RESET(vp); /* * POSIX does not require that struct tm has a tm_gmtoff field, so we * must compute the time offset from UTC by hand. * * Starting with the difference in hours/minutes between 24-hour clocks, * adjust for differences in years, in yeardays, and in (leap) seconds. * * Assume 0..23 hours in a day, 0..59 minutes in an hour. The library spec * has changed: we can no longer assume that there are 0..59 seconds in a * minute. */ gmt = *gmtime(&when); lt = localtime(&when); gmtoff = (lt->tm_hour - gmt.tm_hour) * HOUR_MIN + lt->tm_min - gmt.tm_min; if (lt->tm_year < gmt.tm_year) gmtoff -= DAY_MIN; else if (lt->tm_year > gmt.tm_year) gmtoff += DAY_MIN; else if (lt->tm_yday < gmt.tm_yday) gmtoff -= DAY_MIN; else if (lt->tm_yday > gmt.tm_yday) gmtoff += DAY_MIN; if (lt->tm_sec <= gmt.tm_sec - MIN_SEC) gmtoff -= 1; else if (lt->tm_sec >= gmt.tm_sec + MIN_SEC) gmtoff += 1; /* * First, format the date and wall-clock time. XXX The %e format (day of * month, leading zero replaced by blank) isn't in my POSIX book, but * many vendors seem to support it. */ #ifdef MISSING_STRFTIME_E #define STRFTIME_FMT "%a, %d %b %Y %H:%M:%S " #else #define STRFTIME_FMT "%a, %e %b %Y %H:%M:%S " #endif while (strftime(vstring_end(vp), vstring_avail(vp), STRFTIME_FMT, lt) == 0) VSTRING_SPACE(vp, 100); VSTRING_SKIP(vp); /* * Then, add the UTC offset. */ if (gmtoff < -DAY_MIN || gmtoff > DAY_MIN) msg_panic("UTC time offset %d is larger than one day", gmtoff); vstring_sprintf_append(vp, "%+03d%02d", (int) (gmtoff / HOUR_MIN), (int) (abs(gmtoff) % HOUR_MIN)); /* * Finally, add the time zone name. */ while (strftime(vstring_end(vp), vstring_avail(vp), " (%Z)", lt) == 0) VSTRING_SPACE(vp, vstring_avail(vp) + 100); VSTRING_SKIP(vp); return (vstring_str(vp)); } #ifdef TEST #include int main(void) { vstream_printf("%s\n", mail_date(time((time_t *) 0))); vstream_fflush(VSTREAM_OUT); return (0); } #endif