Prepare for 2.20-rc1
[gitweb.git] / date.c
diff --git a/date.c b/date.c
index 92ab31aa4411ffa0c406ba5a21daf4fc86c0c73f..9bc15df6f9dfa635fe91760914473d953b7c970b 100644 (file)
--- a/date.c
+++ b/date.c
@@ -46,7 +46,17 @@ static time_t gm_time_t(timestamp_t time, int tz)
        minutes = tz < 0 ? -tz : tz;
        minutes = (minutes / 100)*60 + (minutes % 100);
        minutes = tz < 0 ? -minutes : minutes;
-       return time + minutes * 60;
+
+       if (minutes > 0) {
+               if (unsigned_add_overflows(time, minutes * 60))
+                       die("Timestamp+tz too large: %"PRItime" +%04d",
+                           time, tz);
+       } else if (time < -minutes * 60)
+               die("Timestamp before Unix epoch: %"PRItime" %04d", time, tz);
+       time += minutes * 60;
+       if (date_overflows(time))
+               die("Timestamp too large for this system: %"PRItime, time);
+       return (time_t)time;
 }
 
 /*
@@ -60,6 +70,12 @@ static struct tm *time_to_tm(timestamp_t time, int tz)
        return gmtime(&t);
 }
 
+static struct tm *time_to_tm_local(timestamp_t time)
+{
+       time_t t = time;
+       return localtime(&t);
+}
+
 /*
  * What value of "tz" was in effect back then at "time" in the
  * local timezone?
@@ -70,7 +86,10 @@ static int local_tzoffset(timestamp_t time)
        struct tm tm;
        int offset, eastwest;
 
-       t = time;
+       if (date_overflows(time))
+               die("Timestamp too large for this system: %"PRItime, time);
+
+       t = (time_t)time;
        localtime_r(&t, &tm);
        t_local = tm_to_time_t(&tm);
 
@@ -166,7 +185,7 @@ struct date_mode *date_mode_from_type(enum date_mode_type type)
 {
        static struct date_mode mode;
        if (type == DATE_STRFTIME)
-               die("BUG: cannot create anonymous strftime date_mode struct");
+               BUG("cannot create anonymous strftime date_mode struct");
        mode.type = type;
        mode.local = 0;
        return &mode;
@@ -201,7 +220,10 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)
                return timebuf.buf;
        }
 
-       tm = time_to_tm(time, tz);
+       if (mode->local)
+               tm = time_to_tm_local(time);
+       else
+               tm = time_to_tm(time, tz);
        if (!tm) {
                tm = time_to_tm(0, 0);
                tz = 0;
@@ -233,7 +255,8 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)
                        month_names[tm->tm_mon], tm->tm_year + 1900,
                        tm->tm_hour, tm->tm_min, tm->tm_sec, tz);
        else if (mode->type == DATE_STRFTIME)
-               strbuf_addftime(&timebuf, mode->strftime_fmt, tm);
+               strbuf_addftime(&timebuf, mode->strftime_fmt, tm, tz,
+                               !mode->local);
        else
                strbuf_addf(&timebuf, "%.3s %.3s %d %02d:%02d:%02d %d%c%+05d",
                                weekday_names[tm->tm_wday],
@@ -864,20 +887,49 @@ static time_t update_tm(struct tm *tm, struct tm *now, time_t sec)
        return n;
 }
 
+/*
+ * Do we have a pending number at the end, or when
+ * we see a new one? Let's assume it's a month day,
+ * as in "Dec 6, 1992"
+ */
+static void pending_number(struct tm *tm, int *num)
+{
+       int number = *num;
+
+       if (number) {
+               *num = 0;
+               if (tm->tm_mday < 0 && number < 32)
+                       tm->tm_mday = number;
+               else if (tm->tm_mon < 0 && number < 13)
+                       tm->tm_mon = number-1;
+               else if (tm->tm_year < 0) {
+                       if (number > 1969 && number < 2100)
+                               tm->tm_year = number - 1900;
+                       else if (number > 69 && number < 100)
+                               tm->tm_year = number;
+                       else if (number < 38)
+                               tm->tm_year = 100 + number;
+                       /* We screw up for number = 00 ? */
+               }
+       }
+}
+
 static void date_now(struct tm *tm, struct tm *now, int *num)
 {
+       *num = 0;
        update_tm(tm, now, 0);
 }
 
 static void date_yesterday(struct tm *tm, struct tm *now, int *num)
 {
+       *num = 0;
        update_tm(tm, now, 24*60*60);
 }
 
 static void date_time(struct tm *tm, struct tm *now, int hour)
 {
        if (tm->tm_hour < hour)
-               date_yesterday(tm, now, NULL);
+               update_tm(tm, now, 24*60*60);
        tm->tm_hour = hour;
        tm->tm_min = 0;
        tm->tm_sec = 0;
@@ -885,16 +937,19 @@ static void date_time(struct tm *tm, struct tm *now, int hour)
 
 static void date_midnight(struct tm *tm, struct tm *now, int *num)
 {
+       pending_number(tm, num);
        date_time(tm, now, 0);
 }
 
 static void date_noon(struct tm *tm, struct tm *now, int *num)
 {
+       pending_number(tm, num);
        date_time(tm, now, 12);
 }
 
 static void date_tea(struct tm *tm, struct tm *now, int *num)
 {
+       pending_number(tm, num);
        date_time(tm, now, 17);
 }
 
@@ -930,6 +985,7 @@ static void date_never(struct tm *tm, struct tm *now, int *num)
 {
        time_t n = 0;
        localtime_r(&n, tm);
+       *num = 0;
 }
 
 static const struct special {
@@ -1087,33 +1143,6 @@ static const char *approxidate_digit(const char *date, struct tm *tm, int *num,
        return end;
 }
 
-/*
- * Do we have a pending number at the end, or when
- * we see a new one? Let's assume it's a month day,
- * as in "Dec 6, 1992"
- */
-static void pending_number(struct tm *tm, int *num)
-{
-       int number = *num;
-
-       if (number) {
-               *num = 0;
-               if (tm->tm_mday < 0 && number < 32)
-                       tm->tm_mday = number;
-               else if (tm->tm_mon < 0 && number < 13)
-                       tm->tm_mon = number-1;
-               else if (tm->tm_year < 0) {
-                       if (number > 1969 && number < 2100)
-                               tm->tm_year = number - 1900;
-                       else if (number > 69 && number < 100)
-                               tm->tm_year = number;
-                       else if (number < 38)
-                               tm->tm_year = 100 + number;
-                       /* We screw up for number = 00 ? */
-               }
-       }
-}
-
 static timestamp_t approxidate_str(const char *date,
                                   const struct timeval *tv,
                                   int *error_ret)