77
}
78
79
/*
80
- * What value of "tz" was in effect back then at "time" in the
81
- * local timezone?
80
+ * Fill in the localtime 'struct tm' for the supplied time,
81
+ * and return the local tz.
82
*/
83
-static int local_tzoffset(timestamp_t time)
83
+static int local_time_tzoffset(time_t t, struct tm *tm)
84
{
85
- time_t t, t_local;
86
- struct tm tm;
85
+ time_t t_local;
86
int offset, eastwest;
87
89
- if (date_overflows(time))
90
- die("Timestamp too large for this system: %"PRItime, time);
91
-
92
- t = (time_t)time;
93
- localtime_r(&t, &tm);
94
- t_local = tm_to_time_t(&tm);
95
-
88
+ localtime_r(&t, tm);
89
+ t_local = tm_to_time_t(tm);
90
if (t_local == -1)
91
return 0; /* error; just use +0000 */
92
if (t_local < t) {
101
return offset * eastwest;
102
}
103
104
+/*
105
+ * What value of "tz" was in effect back then at "time" in the
106
+ * local timezone?
107
+ */
108
+static int local_tzoffset(timestamp_t time)
109
+{
110
+ struct tm tm;
111
+
112
+ if (date_overflows(time))
113
+ die("Timestamp too large for this system: %"PRItime, time);
114
+
115
+ return local_time_tzoffset((time_t)time, &tm);
116
+}
117
+
118
void show_date_relative(timestamp_t time, int tz,
119
const struct timeval *now,
120
struct strbuf *timebuf)
199
return &mode;
200
}
201
202
+static void show_date_normal(struct strbuf *buf, timestamp_t time, struct tm *tm, int tz, struct tm *human_tm, int human_tz, int local)
203
+{
204
+ struct {
205
+ unsigned int year:1,
206
+ date:1,
207
+ wday:1,
208
+ time:1,
209
+ seconds:1,
210
+ tz:1;
211
+ } hide = { 0 };
212
+
213
+ hide.tz = local || tz == human_tz;
214
+ hide.year = tm->tm_year == human_tm->tm_year;
215
+ if (hide.year) {
216
+ if (tm->tm_mon == human_tm->tm_mon) {
217
+ if (tm->tm_mday > human_tm->tm_mday) {
218
+ /* Future date: think timezones */
219
+ } else if (tm->tm_mday == human_tm->tm_mday) {
220
+ hide.date = hide.wday = 1;
221
+ } else if (tm->tm_mday + 5 > human_tm->tm_mday) {
222
+ /* Leave just weekday if it was a few days ago */
223
+ hide.date = 1;
224
+ }
225
+ }
226
+ }
227
+
228
+ /* Show "today" times as just relative times */
229
+ if (hide.wday) {
230
+ struct timeval now;
231
+ gettimeofday(&now, NULL);
232
+ show_date_relative(time, tz, &now, buf);
233
+ return;
234
+ }
235
+
236
+ /*
237
+ * Always hide seconds for human-readable.
238
+ * Hide timezone if showing date.
239
+ * Hide weekday and time if showing year.
240
+ *
241
+ * The logic here is two-fold:
242
+ * (a) only show details when recent enough to matter
243
+ * (b) keep the maximum length "similar", and in check
244
+ */
245
+ if (human_tm->tm_year) {
246
+ hide.seconds = 1;
247
+ hide.tz |= !hide.date;
248
+ hide.wday = hide.time = !hide.year;
249
+ }
250
+
251
+ if (!hide.wday)
252
+ strbuf_addf(buf, "%.3s ", weekday_names[tm->tm_wday]);
253
+ if (!hide.date)
254
+ strbuf_addf(buf, "%.3s %d ", month_names[tm->tm_mon], tm->tm_mday);
255
+
256
+ /* Do we want AM/PM depending on locale? */
257
+ if (!hide.time) {
258
+ strbuf_addf(buf, "%02d:%02d", tm->tm_hour, tm->tm_min);
259
+ if (!hide.seconds)
260
+ strbuf_addf(buf, ":%02d", tm->tm_sec);
261
+ } else
262
+ strbuf_rtrim(buf);
263
+
264
+ if (!hide.year)
265
+ strbuf_addf(buf, " %d", tm->tm_year + 1900);
266
+
267
+ if (!hide.tz)
268
+ strbuf_addf(buf, " %+05d", tz);
269
+}
270
+
271
const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)
272
{
273
struct tm *tm;
274
+ struct tm human_tm = { 0 };
275
+ int human_tz = -1;
276
static struct strbuf timebuf = STRBUF_INIT;
277
278
if (mode->type == DATE_UNIX) {
281
return timebuf.buf;
282
}
283
284
+ if (mode->type == DATE_HUMAN) {
285
+ struct timeval now;
286
+
287
+ gettimeofday(&now, NULL);
288
+
289
+ /* Fill in the data for "current time" in human_tz and human_tm */
290
+ human_tz = local_time_tzoffset(now.tv_sec, &human_tm);
291
+ }
292
+
293
if (mode->local)
294
tz = local_tzoffset(time);
295
346
strbuf_addftime(&timebuf, mode->strftime_fmt, tm, tz,
347
!mode->local);
348
else
261
- strbuf_addf(&timebuf, "%.3s %.3s %d %02d:%02d:%02d %d%c%+05d",
262
- weekday_names[tm->tm_wday],
263
- month_names[tm->tm_mon],
264
- tm->tm_mday,
265
- tm->tm_hour, tm->tm_min, tm->tm_sec,
266
- tm->tm_year + 1900,
267
- mode->local ? 0 : ' ',
268
- tz);
349
+ show_date_normal(&timebuf, time, tm, tz, &human_tm, human_tz, mode->local);
350
return timebuf.buf;
351
}
352
883
return 0;
884
}
885
886
+static int auto_date_style(void)
887
+{
888
+ return (isatty(1) || pager_in_use()) ? DATE_HUMAN : DATE_NORMAL;
889
+}
890
+
891
static enum date_mode_type parse_date_type(const char *format, const char **end)
892
{
893
if (skip_prefix(format, "relative", end))
905
return DATE_SHORT;
906
if (skip_prefix(format, "default", end))
907
return DATE_NORMAL;
908
+ if (skip_prefix(format, "human", end))
909
+ return DATE_HUMAN;
910
+ if (skip_prefix(format, "auto", end))
911
+ return auto_date_style();
912
if (skip_prefix(format, "raw", end))
913
return DATE_RAW;
914
if (skip_prefix(format, "unix", end))