diff options
Diffstat (limited to 'third_party/git/date.c')
-rw-r--r-- | third_party/git/date.c | 112 |
1 files changed, 75 insertions, 37 deletions
diff --git a/third_party/git/date.c b/third_party/git/date.c index 06340a77f319..40726b7e7508 100644 --- a/third_party/git/date.c +++ b/third_party/git/date.c @@ -64,16 +64,16 @@ static time_t gm_time_t(timestamp_t time, int tz) * thing, which means that tz -0100 is passed in as the integer -100, * even though it means "sixty minutes off" */ -static struct tm *time_to_tm(timestamp_t time, int tz) +static struct tm *time_to_tm(timestamp_t time, int tz, struct tm *tm) { time_t t = gm_time_t(time, tz); - return gmtime(&t); + return gmtime_r(&t, tm); } -static struct tm *time_to_tm_local(timestamp_t time) +static struct tm *time_to_tm_local(timestamp_t time, struct tm *tm) { time_t t = time; - return localtime(&t); + return localtime_r(&t, tm); } /* @@ -128,16 +128,17 @@ static void get_time(struct timeval *now) gettimeofday(now, NULL); } -void show_date_relative(timestamp_t time, - const struct timeval *now, - struct strbuf *timebuf) +void show_date_relative(timestamp_t time, struct strbuf *timebuf) { + struct timeval now; timestamp_t diff; - if (now->tv_sec < time) { + + get_time(&now); + if (now.tv_sec < time) { strbuf_addstr(timebuf, _("in the future")); return; } - diff = now->tv_sec - time; + diff = now.tv_sec - time; if (diff < 90) { strbuf_addf(timebuf, Q_("%"PRItime" second ago", "%"PRItime" seconds ago", diff), diff); @@ -240,9 +241,7 @@ static void show_date_normal(struct strbuf *buf, timestamp_t time, struct tm *tm /* Show "today" times as just relative times */ if (hide.wday) { - struct timeval now; - get_time(&now); - show_date_relative(time, &now, buf); + show_date_relative(time, buf); return; } @@ -284,6 +283,7 @@ static void show_date_normal(struct strbuf *buf, timestamp_t time, struct tm *tm const char *show_date(timestamp_t time, int tz, const struct date_mode *mode) { struct tm *tm; + struct tm tmbuf = { 0 }; struct tm human_tm = { 0 }; int human_tz = -1; static struct strbuf timebuf = STRBUF_INIT; @@ -313,20 +313,17 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode) } if (mode->type == DATE_RELATIVE) { - struct timeval now; - strbuf_reset(&timebuf); - get_time(&now); - show_date_relative(time, &now, &timebuf); + show_date_relative(time, &timebuf); return timebuf.buf; } if (mode->local) - tm = time_to_tm_local(time); + tm = time_to_tm_local(time, &tmbuf); else - tm = time_to_tm(time, tz); + tm = time_to_tm(time, tz, &tmbuf); if (!tm) { - tm = time_to_tm(0, 0); + tm = time_to_tm(0, 0, &tmbuf); tz = 0; } @@ -515,7 +512,7 @@ static int match_alpha(const char *date, struct tm *tm, int *offset) return skip_alpha(date); } -static int is_date(int year, int month, int day, struct tm *now_tm, time_t now, struct tm *tm) +static int set_date(int year, int month, int day, struct tm *now_tm, time_t now, struct tm *tm) { if (month > 0 && month < 13 && day > 0 && day < 32) { struct tm check = *tm; @@ -536,9 +533,9 @@ static int is_date(int year, int month, int day, struct tm *now_tm, time_t now, else if (year < 38) r->tm_year = year + 100; else - return 0; + return -1; if (!now_tm) - return 1; + return 0; specified = tm_to_time_t(r); @@ -547,14 +544,33 @@ static int is_date(int year, int month, int day, struct tm *now_tm, time_t now, * sure it is not later than ten days from now... */ if ((specified != -1) && (now + 10*24*3600 < specified)) - return 0; + return -1; tm->tm_mon = r->tm_mon; tm->tm_mday = r->tm_mday; if (year != -1) tm->tm_year = r->tm_year; - return 1; + return 0; } - return 0; + return -1; +} + +static int set_time(long hour, long minute, long second, struct tm *tm) +{ + /* We accept 61st second because of leap second */ + if (0 <= hour && hour <= 24 && + 0 <= minute && minute < 60 && + 0 <= second && second <= 60) { + tm->tm_hour = hour; + tm->tm_min = minute; + tm->tm_sec = second; + return 0; + } + return -1; +} + +static int is_date_known(struct tm *tm) +{ + return tm->tm_year != -1 && tm->tm_mon != -1 && tm->tm_mday != -1; } static int match_multi_number(timestamp_t num, char c, const char *date, @@ -574,10 +590,14 @@ static int match_multi_number(timestamp_t num, char c, const char *date, case ':': if (num3 < 0) num3 = 0; - if (num < 25 && num2 >= 0 && num2 < 60 && num3 >= 0 && num3 <= 60) { - tm->tm_hour = num; - tm->tm_min = num2; - tm->tm_sec = num3; + if (set_time(num, num2, num3, tm) == 0) { + /* + * If %H:%M:%S was just parsed followed by: .<num4> + * Consider (& discard) it as fractional second + * if %Y%m%d is parsed before. + */ + if (*end == '.' && isdigit(end[1]) && is_date_known(tm)) + strtol(end + 1, &end, 10); break; } return 0; @@ -593,10 +613,10 @@ static int match_multi_number(timestamp_t num, char c, const char *date, if (num > 70) { /* yyyy-mm-dd? */ - if (is_date(num, num2, num3, NULL, now, tm)) + if (set_date(num, num2, num3, NULL, now, tm) == 0) break; /* yyyy-dd-mm? */ - if (is_date(num, num3, num2, NULL, now, tm)) + if (set_date(num, num3, num2, NULL, now, tm) == 0) break; } /* Our eastern European friends say dd.mm.yy[yy] @@ -604,14 +624,14 @@ static int match_multi_number(timestamp_t num, char c, const char *date, * mm/dd/yy[yy] form only when separator is not '.' */ if (c != '.' && - is_date(num3, num, num2, refuse_future, now, tm)) + set_date(num3, num, num2, refuse_future, now, tm) == 0) break; /* European dd.mm.yy[yy] or funny US dd/mm/yy[yy] */ - if (is_date(num3, num2, num, refuse_future, now, tm)) + if (set_date(num3, num2, num, refuse_future, now, tm) == 0) break; /* Funny European mm.dd.yy */ if (c == '.' && - is_date(num3, num, num2, refuse_future, now, tm)) + set_date(num3, num, num2, refuse_future, now, tm) == 0) break; return 0; } @@ -682,6 +702,20 @@ static int match_digit(const char *date, struct tm *tm, int *offset, int *tm_gmt n++; } while (isdigit(date[n])); + /* 8 digits, compact style of ISO-8601's date: YYYYmmDD */ + /* 6 digits, compact style of ISO-8601's time: HHMMSS */ + if (n == 8 || n == 6) { + unsigned int num1 = num / 10000; + unsigned int num2 = (num % 10000) / 100; + unsigned int num3 = num % 100; + if (n == 8) + set_date(num1, num2, num3, NULL, time(NULL), tm); + else if (n == 6 && set_time(num1, num2, num3, tm) == 0 && + *end == '.' && isdigit(end[1])) + strtoul(end + 1, &end, 10); + return end - date; + } + /* Four-digit year or a timezone? */ if (n == 4) { if (num <= 1400 && *offset == -1) { @@ -980,10 +1014,11 @@ void datestamp(struct strbuf *out) { time_t now; int offset; + struct tm tm = { 0 }; time(&now); - offset = tm_to_time_t(localtime(&now)) - now; + offset = tm_to_time_t(localtime_r(&now, &tm)) - now; offset /= 60; date_string(now, offset, out); @@ -1305,15 +1340,18 @@ static timestamp_t approxidate_str(const char *date, return (timestamp_t)update_tm(&tm, &now, 0); } -timestamp_t approxidate_relative(const char *date, const struct timeval *tv) +timestamp_t approxidate_relative(const char *date) { + struct timeval tv; timestamp_t timestamp; int offset; int errors = 0; if (!parse_date_basic(date, ×tamp, &offset)) return timestamp; - return approxidate_str(date, tv, &errors); + + get_time(&tv); + return approxidate_str(date, (const struct timeval *) &tv, &errors); } timestamp_t approxidate_careful(const char *date, int *error_ret) |