]> git.ipfire.org Git - thirdparty/git.git/commitdiff
approxidate: make "specials" respect fixed day-of-month
authorTuomas Ahola <taahol@utu.fi>
Thu, 21 May 2026 10:54:07 +0000 (13:54 +0300)
committerJunio C Hamano <gitster@pobox.com>
Thu, 21 May 2026 13:30:05 +0000 (22:30 +0900)
The special approxidate time formats, "noon" and "tea" differ from
"12pm" and "5pm" by having the feature of wrapping to the previous day
if the current time is before those hours:

now  -> 2026-05-13 11:00:00 +0000

12pm -> 2026-05-13 12:00:00 +0000
5pm  -> 2026-05-13 17:00:00 +0000

noon -> 2026-05-12 12:00:00 +0000
tea  -> 2026-05-12 17:00:00 +0000

However, that logic carries too far.  Even when the date is specified,
the behavior of the "specials" depends on the current time.  Assuming
the same time as above, we get:

today at noon -> 2026-05-12 12:00:00 +0000 (should be 13 May)
13 May at tea -> 2026-05-12 17:00:00 +0000

or, using an example mentioned in date-formats.adoc:

last Friday at noon -> 2026-05-07 12:00:00 +0000 (should be 8 May)

The quirk seems to be rather old.  Already in 2006, Linus Torvalds
remarked that the date yielded by "one year ago yesterday at tea-time"
was "just silly and not even correct".  Indeed, even today it gives:

One year ago yesterday at tea-time -> 2025-05-11 17:00:00 +0000
  (should be 12 May)

Let's fix all of those with a simple patch.  Check whether we already
have a specified day-of-month in `tm->tm_mday` and make `date_time()`
stick to it.  Ensure the correct behavior with relevant tests.

Links:
  1. https://lore.kernel.org/git/Pine.LNX.4.64.0610101102560.3952@g5.osdl.org/

Signed-off-by: Tuomas Ahola <taahol@utu.fi>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
date.c
t/t0006-date.sh

diff --git a/date.c b/date.c
index 633d1176fe90b929c342e446fdad99b9c70b58bb..1e9cfe4b6f5322a2d2aebfd106d937851295e371 100644 (file)
--- a/date.c
+++ b/date.c
@@ -1132,7 +1132,11 @@ static void date_yesterday(struct tm *tm, struct tm *now, int *num)
 
 static void date_time(struct tm *tm, struct tm *now, int hour)
 {
-       if (tm->tm_hour < hour)
+       /*
+        * If we do not yet have a specified day, we'll use the most recent
+        * version of "hour" relative to now.  But that may be yesterday.
+        */
+       if (tm->tm_mday < 0 && tm->tm_hour < hour)
                update_tm(tm, now, 24*60*60);
        tm->tm_hour = hour;
        tm->tm_min = 0;
index b9bb7a05d9f6c651079729d2c5845c6afee6cd07..62cbada774a1fa83a28687f95237f0748dce0c2c 100755 (executable)
@@ -209,8 +209,12 @@ check_approxidate '6pm yesterday' '2009-08-29 18:00:00'
 check_approxidate '3:00' '2009-08-30 03:00:00'
 check_approxidate '15:00' '2009-08-30 15:00:00'
 check_approxidate 'noon today' '2009-08-30 12:00:00'
+check_approxidate 'today at noon' '2009-08-30 12:00:00' '-12 hours'
 check_approxidate 'noon yesterday' '2009-08-29 12:00:00'
+check_approxidate 'last Friday at noon' '2009-08-28 12:00:00'
+check_approxidate 'last Friday at noon' '2009-08-28 12:00:00' '-12 hours'
 check_approxidate 'January 5th noon pm' '2009-01-05 12:00:00'
+check_approxidate 'January 5th noon pm' '2009-01-05 12:00:00' '-12 hours'
 check_approxidate 'January 5th today pm' '2009-01-30 12:00:00'
 check_approxidate '10am noon' '2009-08-29 12:00:00'
 check_approxidate 'January 5th yesterday' '2009-01-29 19:20:00'