#include "cache.h"
-static time_t my_mktime(struct tm *tm)
+/*
+ * This is like mktime, but without normalization of tm_wday and tm_yday.
+ */
+time_t tm_to_time_t(const struct tm *tm)
{
static const int mdays[] = {
0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
t = time;
localtime_r(&t, &tm);
- t_local = my_mktime(&tm);
+ t_local = tm_to_time_t(&tm);
if (t_local < t) {
eastwest = -1;
tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec,
tz);
+ else if (mode == DATE_RFC2822)
+ sprintf(timebuf, "%.3s, %d %.3s %d %02d:%02d:%02d %+05d",
+ weekday_names[tm->tm_wday], tm->tm_mday,
+ month_names[tm->tm_mon], tm->tm_year + 1900,
+ tm->tm_hour, tm->tm_min, tm->tm_sec, tz);
else
sprintf(timebuf, "%.3s %.3s %d %02d:%02d:%02d %d%c%+05d",
weekday_names[tm->tm_wday],
return timebuf;
}
-const char *show_rfc2822_date(unsigned long time, int tz)
-{
- struct tm *tm;
- static char timebuf[200];
-
- tm = time_to_tm(time, tz);
- if (!tm)
- return NULL;
- sprintf(timebuf, "%.3s, %d %.3s %d %02d:%02d:%02d %+05d",
- weekday_names[tm->tm_wday], tm->tm_mday,
- month_names[tm->tm_mon], tm->tm_year + 1900,
- tm->tm_hour, tm->tm_min, tm->tm_sec, tz);
- return timebuf;
-}
-
/*
* Check these. And note how it doesn't do the summer-time conversion.
*
{ "EAST", +10, 0, }, /* Eastern Australian Standard */
{ "EADT", +10, 1, }, /* Eastern Australian Daylight */
{ "GST", +10, 0, }, /* Guam Standard, USSR Zone 9 */
- { "NZT", +11, 0, }, /* New Zealand */
- { "NZST", +11, 0, }, /* New Zealand Standard */
- { "NZDT", +11, 1, }, /* New Zealand Daylight */
+ { "NZT", +12, 0, }, /* New Zealand */
+ { "NZST", +12, 0, }, /* New Zealand Standard */
+ { "NZDT", +12, 1, }, /* New Zealand Daylight */
{ "IDLE", +12, 0, }, /* International Date Line East */
};
if (!now_tm)
return 1;
- specified = my_mktime(r);
+ specified = tm_to_time_t(r);
/* Be it commit time or author time, it does not make
* sense to specify timestamp way into the future. Make
return end - date;
}
+/* Have we filled in any part of the time/date yet? */
+static inline int nodate(struct tm *tm)
+{
+ return tm->tm_year < 0 &&
+ tm->tm_mon < 0 &&
+ tm->tm_mday < 0 &&
+ !(tm->tm_hour | tm->tm_min | tm->tm_sec);
+}
+
/*
* We've seen a digit. Time? Year? Date?
*/
* more than 8 digits. This is because we don't want to rule out
* numbers like 20070606 as a YYYYMMDD date.
*/
- if (num >= 100000000) {
+ if (num >= 100000000 && nodate(tm)) {
time_t time = num;
if (gmtime_r(&time, tm)) {
*tm_gmt = 1;
return n;
}
+ /*
+ * Ignore lots of numerals. We took care of 4-digit years above.
+ * Days or months must be one or two digits.
+ */
+ if (n > 2)
+ return n;
+
/*
* NOTE! We will give precedence to day-of-month over month or
* year numbers in the 1-12 range. So 05 is always "mday 5",
if (num > 0 && num < 32) {
tm->tm_mday = num;
- } else if (num > 1900) {
- tm->tm_year = num - 1900;
- } else if (num > 70) {
- tm->tm_year = num;
} else if (num > 0 && num < 13) {
tm->tm_mon = num-1;
}
}
/* mktime uses local timezone */
- then = my_mktime(&tm);
+ then = tm_to_time_t(&tm);
if (offset == -1)
offset = (then - mktime(&tm)) / 60;
return date_string(then, offset, result, maxlen);
}
+enum date_mode parse_date_format(const char *format)
+{
+ if (!strcmp(format, "relative"))
+ return DATE_RELATIVE;
+ else if (!strcmp(format, "iso8601") ||
+ !strcmp(format, "iso"))
+ return DATE_ISO8601;
+ else if (!strcmp(format, "rfc2822") ||
+ !strcmp(format, "rfc"))
+ return DATE_RFC2822;
+ else if (!strcmp(format, "short"))
+ return DATE_SHORT;
+ else if (!strcmp(format, "local"))
+ return DATE_LOCAL;
+ else if (!strcmp(format, "default"))
+ return DATE_NORMAL;
+ else
+ die("unknown date format %s", format);
+}
+
void datestamp(char *buf, int bufsize)
{
time_t now;
time(&now);
- offset = my_mktime(localtime(&now)) - now;
+ offset = tm_to_time_t(localtime(&now)) - now;
offset /= 60;
date_string(now, offset, buf, bufsize);
tm->tm_hour = (hour % 12);
}
+static void date_never(struct tm *tm, int *num)
+{
+ time_t n = 0;
+ localtime_r(&n, tm);
+}
+
static const struct special {
const char *name;
void (*fn)(struct tm *, int *);
{ "tea", date_tea },
{ "PM", date_pm },
{ "AM", date_am },
+ { "never", date_never },
{ NULL }
};
}
}
- *num = number;
+ /* Accept zero-padding only for small numbers ("Dec 02", never "Dec 0002") */
+ if (date[0] != '0' || end - date <= 2)
+ *num = number;
return end;
}