diff --git a/Documentation/rev-list-options.adoc b/Documentation/rev-list-options.adoc index 94a7b1c065..9e666b9f10 100644 --- a/Documentation/rev-list-options.adoc +++ b/Documentation/rev-list-options.adoc @@ -23,7 +23,8 @@ ordering and formatting options, such as `--reverse`. `--since=`:: `--after=`:: - Show commits more recent than __. + Show commits more recent than __. As a special case, + 'today' means the last midnight. `--since-as-filter=`:: Show all commits more recent than __. This visits diff --git a/date.c b/date.c index 17a95077cf..05b78d852f 100644 --- a/date.c +++ b/date.c @@ -1071,13 +1071,22 @@ void datestamp(struct strbuf *out) /* * Relative time update (eg "2 days ago"). If we haven't set the time * yet, we need to set it from current time. + * + * The tm->tm_mday field has an additional logic of using negative values + * for date adjustments: -2 means yesterday and -3 the day before that, + * and so on. The idea is to deref such adjustments until we are sure + * there's no explicit mday specification in the approxidate string. */ static time_t update_tm(struct tm *tm, struct tm *now, time_t sec) { time_t n; - if (tm->tm_mday < 0) + if (tm->tm_mday < 0) { + int offset = tm->tm_mday + 1; + if (sec == 0 && offset < 0) + sec = -offset * 24*60*60; tm->tm_mday = now->tm_mday; + } if (tm->tm_mon < 0) tm->tm_mon = now->tm_mon; if (tm->tm_year < 0) { @@ -1127,34 +1136,39 @@ static void date_now(struct tm *tm, struct tm *now, int *num) static void date_yesterday(struct tm *tm, struct tm *now, int *num) { *num = 0; + tm->tm_mday = -1; update_tm(tm, now, 24*60*60); } -static void date_time(struct tm *tm, struct tm *now, int hour) +static void date_time(struct tm *tm, int hour) { - if (tm->tm_hour < hour) - update_tm(tm, now, 24*60*60); + /* + * 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) + tm->tm_mday = -2; /* eventually handled by update_tm() */ tm->tm_hour = hour; tm->tm_min = 0; tm->tm_sec = 0; } -static void date_midnight(struct tm *tm, struct tm *now, int *num) +static void date_midnight(struct tm *tm, struct tm *now UNUSED, int *num) { pending_number(tm, num); - date_time(tm, now, 0); + date_time(tm, 0); } -static void date_noon(struct tm *tm, struct tm *now, int *num) +static void date_noon(struct tm *tm, struct tm *now UNUSED, int *num) { pending_number(tm, num); - date_time(tm, now, 12); + date_time(tm, 12); } -static void date_tea(struct tm *tm, struct tm *now, int *num) +static void date_tea(struct tm *tm, struct tm *now UNUSED, int *num) { pending_number(tm, num); - date_time(tm, now, 17); + date_time(tm, 17); } static void date_pm(struct tm *tm, struct tm *now UNUSED, int *num) @@ -1192,6 +1206,17 @@ static void date_never(struct tm *tm, struct tm *now UNUSED, int *num) *num = 0; } +static void date_today(struct tm *tm, struct tm *now, int *num) +{ + if (tm->tm_hour == now->tm_hour && + tm->tm_min == now->tm_min && + tm->tm_sec == now->tm_sec) + date_time(tm, 0); + *num = 0; + tm->tm_mday = -1; + update_tm(tm, now, 0); +} + static const struct special { const char *name; void (*fn)(struct tm *, struct tm *, int *); @@ -1204,6 +1229,7 @@ static const struct special { { "AM", date_am }, { "never", date_never }, { "now", date_now }, + { "today", date_today }, { NULL } }; diff --git a/t/t0006-date.sh b/t/t0006-date.sh index 53ced36df4..9a76b84ed9 100755 --- a/t/t0006-date.sh +++ b/t/t0006-date.sh @@ -155,15 +155,45 @@ check_parse '2100-00-00 00:00:00 -11' bad check_parse '2100-00-00 00:00:00 +11' bad REQUIRE_64BIT_TIME= +add_time_offset() { + case "$3" in + hours) + unit=$(( 60*60 )) + ;; + days) + unit=$(( 24*60*60 )) + ;; + esac + offset=$(( $2 * unit )) + echo $(( $1 + offset )) +} + check_approxidate() { + old_date=$GIT_TEST_DATE_NOW + if test "$3" = "failure" + then + expection="$3" + else + expection=${4:-success} + offset="$3" + fi + if test -n "$offset" + then + GIT_TEST_DATE_NOW=$(add_time_offset $old_date $offset) + caption="$1; offset $offset" + else + caption=$1 + fi echo "$1 -> $2 +0000" >expect - test_expect_${3:-success} "parse approxidate ($1)" " + test_expect_$expection "parse approxidate ($caption)" " test-tool date approxidate '$1' >actual && test_cmp expect actual " + GIT_TEST_DATE_NOW=$old_date } check_approxidate now '2009-08-30 19:20:00' +check_approxidate today '2009-08-30 00:00:00' check_approxidate '5 seconds ago' '2009-08-30 19:19:55' check_approxidate 5.seconds.ago '2009-08-30 19:19:55' check_approxidate 10.minutes.ago '2009-08-30 19:10:00' @@ -179,14 +209,26 @@ 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 today' '2009-09-01 12:00:00' '+36 hours' check_approxidate 'noon yesterday' '2009-08-29 12:00:00' +check_approxidate 'noon yesterday' '2009-08-29 12:00:00' '-12 hours' +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 'tea last saturday' '2009-08-29 17:00:00' +check_approxidate 'tea last saturday' '2009-08-29 17: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' +check_approxidate 'January 5th yesterday' '2008-12-31 19:20:00' '+2 days' check_approxidate 'last tuesday' '2009-08-25 19:20:00' check_approxidate 'July 5th' '2009-07-05 19:20:00' check_approxidate '06/05/2009' '2009-06-05 19:20:00' check_approxidate '06.05.2009' '2009-05-06 19:20:00' +check_approxidate 'Jan 5 today' '2009-01-30 00:00:00' check_approxidate 'Jun 6, 5AM' '2009-06-06 05:00:00' check_approxidate '5AM Jun 6' '2009-06-06 05:00:00'