1 /*************************************************
2 * Exim - an Internet mail transport agent *
3 *************************************************/
5 /* Copyright (c) University of Cambridge 1995 - 2009 */
6 /* See the file NOTICE for conditions of use and distribution. */
8 /* A function for returning the time of day in various formats */
13 /* #define TESTING_LOG_DATESTAMP */
16 static uschar timebuf[sizeof("www, dd-mmm-yyyy hh:mm:ss +zzzz")];
19 /*************************************************
21 *************************************************/
23 /* The log timestamp format is dd-mmm-yy so as to be non-confusing on both
24 sides of the Atlantic. We calculate an explicit numerical offset from GMT for
25 the full datestamp and BSD inbox datestamp. Note that on some systems
26 localtime() and gmtime() re-use the same store, so we must save the local time
27 values before calling gmtime(). If timestamps_utc is set, don't use
28 localtime(); all times are then in UTC (with offset +0000).
30 There are also some contortions to get the day of the month without
31 a leading zero for the full stamp, since Ustrftime() doesn't provide this
34 Argument: type of timestamp required:
35 tod_bsdin BSD inbox format
36 tod_epoch Unix epoch format
37 tod_full full date and time
38 tod_log log file data line format,
39 with zone if log_timezone is TRUE
40 tod_log_bare always without zone
41 tod_log_datestamp_daily for log file names when datestamped daily
42 tod_log_datestamp_monthly for log file names when datestamped monthly
43 tod_log_zone always with zone
44 tod_mbx MBX inbox format
45 tod_zone just the timezone offset
46 tod_zulu time in 8601 zulu format
48 Returns: pointer to fixed buffer containing the timestamp
54 time_t now = time(NULL);
57 /* Vary log type according to timezone requirement */
59 if (type == tod_log) type = log_timezone? tod_log_zone : tod_log_bare;
61 /* Styles that don't need local time */
63 else if (type == tod_epoch)
65 (void) sprintf(CS timebuf, "%d", (int)now); /* Unix epoch format */
69 else if (type == tod_zulu)
72 (void) sprintf(CS timebuf, "%04d%02d%02d%02d%02d%02dZ",
73 1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min,
78 /* Convert to local time or UTC */
80 t = timestamps_utc? gmtime(&now) : localtime(&now);
84 case tod_log_bare: /* Format used in logging without timezone */
85 (void) sprintf(CS timebuf, "%04d-%02d-%02d %02d:%02d:%02d",
86 1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday,
87 t->tm_hour, t->tm_min, t->tm_sec);
90 /* Format used as suffix of log file name when 'log_datestamp' is active. For
91 testing purposes, it changes the file every second. */
93 #ifdef TESTING_LOG_DATESTAMP
94 case tod_log_datestamp_daily:
95 case tod_log_datestamp_monthly:
96 (void) sprintf(CS timebuf, "%04d%02d%02d%02d%02d",
97 1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday, t->tm_hour, t->tm_min);
101 case tod_log_datestamp_daily:
102 (void) sprintf(CS timebuf, "%04d%02d%02d",
103 1900 + t->tm_year, 1 + t->tm_mon, t->tm_mday);
106 case tod_log_datestamp_monthly:
107 (void) sprintf(CS timebuf, "%04d%02d",
108 1900 + t->tm_year, 1 + t->tm_mon);
112 /* Format used in BSD inbox separator lines. Sort-of documented in RFC 976
113 ("UUCP Mail Interchange Format Standard") but only by example, not by
114 explicit definition. The examples show no timezone offsets, and some MUAs
115 appear to be sensitive to this, so Exim has been changed to remove the
116 timezone offsets that originally appeared. */
120 int len = Ustrftime(timebuf, sizeof(timebuf), "%a %b %d %H:%M:%S", t);
121 Ustrftime(timebuf + len, sizeof(timebuf) - len, " %Y", t);
125 /* Other types require the GMT offset to be calculated, or just set up in the
126 case of UTC timestamping. We need to take a copy of the local time first. */
130 int diff_hour, diff_min;
132 memcpy(&local, t, sizeof(struct tm));
136 diff_hour = diff_min = 0;
140 struct tm *gmt = gmtime(&now);
141 diff_min = 60*(local.tm_hour - gmt->tm_hour) + local.tm_min - gmt->tm_min;
142 if (local.tm_year != gmt->tm_year)
143 diff_min += (local.tm_year > gmt->tm_year)? 1440 : -1440;
144 else if (local.tm_yday != gmt->tm_yday)
145 diff_min += (local.tm_yday > gmt->tm_yday)? 1440 : -1440;
146 diff_hour = diff_min/60;
147 diff_min = abs(diff_min - diff_hour*60);
152 case tod_log_zone: /* Format used in logging with timezone */
153 (void) sprintf(CS timebuf, "%04d-%02d-%02d %02d:%02d:%02d %+03d%02d",
154 1900 + local.tm_year, 1 + local.tm_mon, local.tm_mday,
155 local.tm_hour, local.tm_min, local.tm_sec,
156 diff_hour, diff_min);
159 case tod_zone: /* Just the timezone offset */
160 (void) sprintf(CS timebuf, "%+03d%02d", diff_hour, diff_min);
163 /* tod_mbx: format used in MBX mailboxes - subtly different to tod_full */
169 (void) sprintf(CS timebuf, "%02d-", local.tm_mday);
170 len = Ustrlen(timebuf);
171 len += Ustrftime(timebuf + len, sizeof(timebuf) - len, "%b-%Y %H:%M:%S",
173 (void) sprintf(CS timebuf + len, " %+03d%02d", diff_hour, diff_min);
178 /* tod_full: format used in Received: headers (use as default just in case
179 called with a junk type value) */
183 int len = Ustrftime(timebuf, sizeof(timebuf), "%a, ", &local);
184 (void) sprintf(CS timebuf + len, "%02d ", local.tm_mday);
185 len += Ustrlen(timebuf + len);
186 len += Ustrftime(timebuf + len, sizeof(timebuf) - len, "%b %Y %H:%M:%S",
188 (void) sprintf(CS timebuf + len, " %+03d%02d", diff_hour, diff_min);