approxidate: make "specials" respect fixed day-of-month

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>

Tuomas Ahola committed May 21, 2026 at 13:54 UTC bbe9b46ac826b5dad4f714513638dd223b6fe63f
2 files changed +9 -1
date.c
+5 -1
@@ -1132,7 +1132,11 @@ static void date_yesterday(struct tm *tm, struct tm *now, int *num)
1132
1133 static void date_time(struct tm *tm, struct tm *now, int hour)
1134 {
1135 - if (tm->tm_hour < hour)
1135 + /*
1136 + * If we do not yet have a specified day, we'll use the most recent
1137 + * version of "hour" relative to now. But that may be yesterday.
1138 + */
1139 + if (tm->tm_mday < 0 && tm->tm_hour < hour)
1140 update_tm(tm, now, 24*60*60);
1141 tm->tm_hour = hour;
1142 tm->tm_min = 0;
t/t0006-date.sh
+4
@@ -209,8 +209,12 @@ check_approxidate '6pm yesterday' '2009-08-29 18:00:00'
209 check_approxidate '3:00' '2009-08-30 03:00:00'
210 check_approxidate '15:00' '2009-08-30 15:00:00'
211 check_approxidate 'noon today' '2009-08-30 12:00:00'
212 +check_approxidate 'today at noon' '2009-08-30 12:00:00' '-12 hours'
213 check_approxidate 'noon yesterday' '2009-08-29 12:00:00'
214 +check_approxidate 'last Friday at noon' '2009-08-28 12:00:00'
215 +check_approxidate 'last Friday at noon' '2009-08-28 12:00:00' '-12 hours'
216 check_approxidate 'January 5th noon pm' '2009-01-05 12:00:00'
217 +check_approxidate 'January 5th noon pm' '2009-01-05 12:00:00' '-12 hours'
218 check_approxidate 'January 5th today pm' '2009-01-30 12:00:00'
219 check_approxidate '10am noon' '2009-08-29 12:00:00'
220 check_approxidate 'January 5th yesterday' '2009-01-29 19:20:00'