Merge branch 'jc/epochtime-wo-tz' into maint-2.3
authorJunio C Hamano <gitster@pobox.com>
Mon, 11 May 2015 21:33:58 +0000 (14:33 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 11 May 2015 21:33:58 +0000 (14:33 -0700)
"git commit --date=now" or anything that relies on approxidate lost
the daylight-saving-time offset.

* jc/epochtime-wo-tz:
parse_date_basic(): let the system handle DST conversion
parse_date_basic(): return early when given a bogus timestamp

1  2 
date.c
diff --combined date.c
index 3eba2dfe8841cee28850e2f1f4177e1e32f1c8a8,52a99448d2541d6effb09b2c61bf275da1c577fd..733d1b29b19fc7dda04d599eb6a311e809212775
--- 1/date.c
--- 2/date.c
+++ b/date.c
@@@ -200,16 -200,7 +200,16 @@@ const char *show_date(unsigned long tim
                                tm->tm_mday,
                                tm->tm_hour, tm->tm_min, tm->tm_sec,
                                tz);
 -      else if (mode == DATE_RFC2822)
 +      else if (mode == DATE_ISO8601_STRICT) {
 +              char sign = (tz >= 0) ? '+' : '-';
 +              tz = abs(tz);
 +              strbuf_addf(&timebuf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
 +                              tm->tm_year + 1900,
 +                              tm->tm_mon + 1,
 +                              tm->tm_mday,
 +                              tm->tm_hour, tm->tm_min, tm->tm_sec,
 +                              sign, tz / 100, tz % 100);
 +      } else if (mode == DATE_RFC2822)
                strbuf_addf(&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,
@@@ -405,9 -396,9 +405,9 @@@ static int is_date(int year, int month
        return 0;
  }
  
 -static int match_multi_number(unsigned long num, char c, const char *date, char *end, struct tm *tm)
 +static int match_multi_number(unsigned long num, char c, const char *date,
 +                            char *end, struct tm *tm, time_t now)
  {
 -      time_t now;
        struct tm now_tm;
        struct tm *refuse_future;
        long num2, num3;
        case '-':
        case '/':
        case '.':
 -              now = time(NULL);
 +              if (!now)
 +                      now = time(NULL);
                refuse_future = NULL;
                if (gmtime_r(&now, &now_tm))
                        refuse_future = &now_tm;
  
                if (num > 70) {
                        /* yyyy-mm-dd? */
 -                      if (is_date(num, num2, num3, refuse_future, now, tm))
 +                      if (is_date(num, num2, num3, NULL, now, tm))
                                break;
                        /* yyyy-dd-mm? */
 -                      if (is_date(num, num3, num2, refuse_future, now, tm))
 +                      if (is_date(num, num3, num2, NULL, now, tm))
                                break;
                }
                /* Our eastern European friends say dd.mm.yy[yy]
@@@ -514,7 -504,7 +514,7 @@@ static int match_digit(const char *date
        case '/':
        case '-':
                if (isdigit(end[1])) {
 -                      int match = match_multi_number(num, *end, date, end, tm);
 +                      int match = match_multi_number(num, *end, date, end, tm, 0);
                        if (match)
                                return match;
                }
@@@ -615,7 -605,7 +615,7 @@@ static int match_tz(const char *date, i
        return end - date;
  }
  
 -static int date_string(unsigned long date, int offset, char *buf, int len)
 +static void date_string(unsigned long date, int offset, struct strbuf *buf)
  {
        int sign = '+';
  
                offset = -offset;
                sign = '-';
        }
 -      return snprintf(buf, len, "%lu %c%02d%02d", date, sign, offset / 60, offset % 60);
 +      strbuf_addf(buf, "%lu %c%02d%02d", date, sign, offset / 60, offset % 60);
  }
  
  /*
@@@ -704,10 -694,17 +704,17 @@@ int parse_date_basic(const char *date, 
                date += match;
        }
  
-       /* mktime uses local timezone */
+       /* do not use mktime(), which uses local timezone, here */
        *timestamp = tm_to_time_t(&tm);
+       if (*timestamp == -1)
+               return -1;
        if (*offset == -1) {
-               time_t temp_time = mktime(&tm);
+               time_t temp_time;
+               /* gmtime_r() in match_digit() may have clobbered it */
+               tm.tm_isdst = -1;
+               temp_time = mktime(&tm);
                if ((time_t)*timestamp > temp_time) {
                        *offset = ((time_t)*timestamp - temp_time) / 60;
                } else {
                }
        }
  
-       if (*timestamp == -1)
-               return -1;
        if (!tm_gmt)
                *timestamp -= *offset * 60;
        return 0; /* success */
@@@ -745,14 -739,13 +749,14 @@@ int parse_expiry_date(const char *date
        return errors;
  }
  
 -int parse_date(const char *date, char *result, int maxlen)
 +int parse_date(const char *date, struct strbuf *result)
  {
        unsigned long timestamp;
        int offset;
        if (parse_date_basic(date, &timestamp, &offset))
                return -1;
 -      return date_string(timestamp, offset, result, maxlen);
 +      date_string(timestamp, offset, result);
 +      return 0;
  }
  
  enum date_mode parse_date_format(const char *format)
        else if (!strcmp(format, "iso8601") ||
                 !strcmp(format, "iso"))
                return DATE_ISO8601;
 +      else if (!strcmp(format, "iso8601-strict") ||
 +               !strcmp(format, "iso-strict"))
 +              return DATE_ISO8601_STRICT;
        else if (!strcmp(format, "rfc2822") ||
                 !strcmp(format, "rfc"))
                return DATE_RFC2822;
                die("unknown date format %s", format);
  }
  
 -void datestamp(char *buf, int bufsize)
 +void datestamp(struct strbuf *out)
  {
        time_t now;
        int offset;
        offset = tm_to_time_t(localtime(&now)) - now;
        offset /= 60;
  
 -      date_string(now, offset, buf, bufsize);
 +      date_string(now, offset, out);
  }
  
  /*
@@@ -1014,8 -1004,7 +1018,8 @@@ static const char *approxidate_alpha(co
        return end;
  }
  
 -static const char *approxidate_digit(const char *date, struct tm *tm, int *num)
 +static const char *approxidate_digit(const char *date, struct tm *tm, int *num,
 +                                   time_t now)
  {
        char *end;
        unsigned long number = strtoul(date, &end, 10);
        case '/':
        case '-':
                if (isdigit(end[1])) {
 -                      int match = match_multi_number(number, *end, date, end, tm);
 +                      int match = match_multi_number(number, *end, date, end,
 +                                                     tm, now);
                        if (match)
                                return date + match;
                }
@@@ -1090,7 -1078,7 +1094,7 @@@ static unsigned long approxidate_str(co
                date++;
                if (isdigit(c)) {
                        pending_number(&tm, &number);
 -                      date = approxidate_digit(date-1, &tm, &number);
 +                      date = approxidate_digit(date-1, &tm, &number, time_sec);
                        touched = 1;
                        continue;
                }