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