Subject: Re: [PATCH v3 3/4] approxidate: make "specials" respect fixed day-of-month

From: Junio C Hamano <[email-masked]>
Date: Fri, 15 May 2026 01:06:27 +0900

Tuomas Ahola <[email-masked]> writes:

> 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.

I find this vastly easier to follow the reasoning, compared to the
previous iteration.  Very nicely done.

>
> Links:
>   1. https://lore.kernel.org/git/[email-masked]/
>
> Signed-off-by: Tuomas Ahola <[email-masked]>
> ---
>
> Notes:
>     > Again, this may be just me, but I happen to find the version of
>     > comment in Peff's review on the earlier iteration of this series
>     > much easier to understand.
>     >
>     
>     Thanks, applied.
>
>  date.c          | 6 +++++-
>  t/t0006-date.sh | 4 ++++
>  2 files changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/date.c b/date.c
> index 412aca6dc4..73879d202c 100644
> --- 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;
> diff --git a/t/t0006-date.sh b/t/t0006-date.sh
> index c7667bade2..d800cb30fe 100755
> --- a/t/t0006-date.sh
> +++ b/t/t0006-date.sh
> @@ -208,8 +208,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 '10am noon' '2009-08-29 12:00:00'
>  check_approxidate 'January 5th yesterday' '2009-01-29 19:20:00'
>  check_approxidate 'January 5th yesterday' '2008-12-31 19:20:00' '+2 days'