Expand PMF_FN_* macros.
[netbsd-mini2440.git] / external / ibm-public / postfix / dist / src / global / mail_date.c
blob39a73bddbd3412b2bccf3754a417a1c517396f1d
1 /* $NetBSD$ */
3 /*++
4 /* NAME
5 /* mail_date 3
6 /* SUMMARY
7 /* return formatted time
8 /* SYNOPSIS
9 /* #include <mail_date.h>
11 /* const char *mail_date(when)
12 /* time_t when;
13 /* DESCRIPTION
14 /* mail_date() converts the time specified in \fIwhen\fR to the
15 /* form: "Mon, 9 Dec 1996 05:38:26 -0500 (EST)" and returns
16 /* a pointer to the result. The result is overwritten upon
17 /* each call.
18 /* DIAGNOSTICS
19 /* Panic: the offset from UTC is more than a whole day. Fatal
20 /* error: out of memory.
21 /* LICENSE
22 /* .ad
23 /* .fi
24 /* The Secure Mailer license must be distributed with this software.
25 /* AUTHOR(S)
26 /* Wietse Venema
27 /* IBM T.J. Watson Research
28 /* P.O. Box 704
29 /* Yorktown Heights, NY 10598, USA
30 /*--*/
32 /* System library. */
34 #include <sys_defs.h>
35 #include <time.h>
36 #include <stdlib.h>
38 /* Utility library. */
40 #include <msg.h>
41 #include <vstring.h>
43 /* Global library. */
45 #include "mail_date.h"
48 * Application-specific.
50 #define DAY_MIN (24 * HOUR_MIN) /* minutes in a day */
51 #define HOUR_MIN 60 /* minutes in an hour */
52 #define MIN_SEC 60 /* seconds in a minute */
54 /* mail_date - return formatted time */
56 const char *mail_date(time_t when)
58 static VSTRING *vp;
59 struct tm *lt;
60 struct tm gmt;
61 int gmtoff;
64 * As if strftime() isn't expensive enough, we're dynamically adjusting
65 * the size for the result, so we won't be surprised by long names etc.
67 if (vp == 0)
68 vp = vstring_alloc(100);
69 else
70 VSTRING_RESET(vp);
73 * POSIX does not require that struct tm has a tm_gmtoff field, so we
74 * must compute the time offset from UTC by hand.
76 * Starting with the difference in hours/minutes between 24-hour clocks,
77 * adjust for differences in years, in yeardays, and in (leap) seconds.
79 * Assume 0..23 hours in a day, 0..59 minutes in an hour. The library spec
80 * has changed: we can no longer assume that there are 0..59 seconds in a
81 * minute.
83 gmt = *gmtime(&when);
84 lt = localtime(&when);
85 gmtoff = (lt->tm_hour - gmt.tm_hour) * HOUR_MIN + lt->tm_min - gmt.tm_min;
86 if (lt->tm_year < gmt.tm_year)
87 gmtoff -= DAY_MIN;
88 else if (lt->tm_year > gmt.tm_year)
89 gmtoff += DAY_MIN;
90 else if (lt->tm_yday < gmt.tm_yday)
91 gmtoff -= DAY_MIN;
92 else if (lt->tm_yday > gmt.tm_yday)
93 gmtoff += DAY_MIN;
94 if (lt->tm_sec <= gmt.tm_sec - MIN_SEC)
95 gmtoff -= 1;
96 else if (lt->tm_sec >= gmt.tm_sec + MIN_SEC)
97 gmtoff += 1;
100 * First, format the date and wall-clock time. XXX The %e format (day of
101 * month, leading zero replaced by blank) isn't in my POSIX book, but
102 * many vendors seem to support it.
104 #ifdef MISSING_STRFTIME_E
105 #define STRFTIME_FMT "%a, %d %b %Y %H:%M:%S "
106 #else
107 #define STRFTIME_FMT "%a, %e %b %Y %H:%M:%S "
108 #endif
110 while (strftime(vstring_end(vp), vstring_avail(vp), STRFTIME_FMT, lt) == 0)
111 VSTRING_SPACE(vp, 100);
112 VSTRING_SKIP(vp);
115 * Then, add the UTC offset.
117 if (gmtoff < -DAY_MIN || gmtoff > DAY_MIN)
118 msg_panic("UTC time offset %d is larger than one day", gmtoff);
119 vstring_sprintf_append(vp, "%+03d%02d", (int) (gmtoff / HOUR_MIN),
120 (int) (abs(gmtoff) % HOUR_MIN));
123 * Finally, add the time zone name.
125 while (strftime(vstring_end(vp), vstring_avail(vp), " (%Z)", lt) == 0)
126 VSTRING_SPACE(vp, vstring_avail(vp) + 100);
127 VSTRING_SKIP(vp);
129 return (vstring_str(vp));
132 #ifdef TEST
134 #include <vstream.h>
136 int main(void)
138 vstream_printf("%s\n", mail_date(time((time_t *) 0)));
139 vstream_fflush(VSTREAM_OUT);
140 return (0);
143 #endif