{"thread":{"id":"65733","subject":"[PATCH v2] doc: document and test `@` prefix for raw timestamps","startedAt":"2026-06-02T08:19:46Z","lastAt":"2026-06-02T16:35:46Z","messageCount":5,"participants":["Luna Schwalbe","Patrick Steinhardt","Junio C Hamano"],"isPatch":true,"patchVersion":2,"patchTotal":null},"messages":[{"id":"544469","messageId":"20260602081924.673763-2-dev@luna.gl","threadId":"65733","inReplyTo":null,"subject":"[PATCH v2] doc: document and test `@` prefix for raw timestamps","fromName":"Luna Schwalbe","fromEmail":"dev@luna.gl","sentAt":"2026-06-02T08:17:36Z","receivedAt":"2026-06-02T08:19:46Z","isPatch":true,"body":"The Git internal date format `<unix-timestamp> <time-zone-offset>`\nfails to parse when the timestamp is less than 100,000,000 (fewer than\n9 digits). This happens to avoid potential ambiguity with other date\nformats such as `YYYYMMDD`, especially when used with approxidate.\n\nTo force the parser to interpret the value as a raw timestamp, it must\nbe prefixed with `@` (e.g., `@0 +0000`). This behavior was introduced\nin 2c733fb24c10a9d7aacc51f956bf9b7881980870 (parse_date(): '@' prefix\nforces git-timestamp, 2012-02-02) but was never documented.\n\nDocument the `@` prefix in `Documentation/date-formats.adoc` to make\nthis behavior explicit. Also add test cases to `t/t0006-date.sh` to\nverify and demonstrate the difference between prefixed and unprefixed\nsmall timestamps (e.g., `@2000` vs `2000`).\n\nSigned-off-by: Luna Schwalbe <dev@luna.gl>\nCo-authored-by: Junio C Hamano <gitster@pobox.com>\n---\nFixed the asciidoc formatting, removed parens around YYYYMMDD example.\n\n Documentation/date-formats.adoc |  5 +++++\n t/t0006-date.sh                 | 11 +++++++++++\n 2 files changed, 16 insertions(+)\n\ndiff --git a/Documentation/date-formats.adoc b/Documentation/date-formats.adoc\nindex e24517c49..330424b2b 100644\n--- a/Documentation/date-formats.adoc\n+++ b/Documentation/date-formats.adoc\n@@ -9,6 +9,11 @@ Git internal format::\n \t`<unix-timestamp>` is the number of seconds since the UNIX epoch.\n \t`<time-zone-offset>` is a positive or negative offset from UTC.\n \tFor example CET (which is 1 hour ahead of UTC) is `+0100`.\n++\n+It is safer to prepend the `<unix-timestamp>` with `@` (e.g.,\n+`@0 +0000`), which forces Git to interpret it as a raw timestamp. This\n+is required for values less than 100,000,000 (which have fewer than 9\n+digits) to avoid confusion with other date formats like `YYYYMMDD`.\n \n RFC 2822::\n \tThe standard date format as described by RFC 2822, for example\ndiff --git a/t/t0006-date.sh b/t/t0006-date.sh\nindex 53ced36df..8b4e1870b 100755\n--- a/t/t0006-date.sh\n+++ b/t/t0006-date.sh\n@@ -138,6 +138,13 @@ check_parse '1969-12-31 23:59:59 Z' bad\n check_parse '1969-12-31 23:59:59 +11' bad\n check_parse '1969-12-31 23:59:59 -11' bad\n \n+# pathologically small timestamps requiring `@` prefix\n+check_parse '@0 +0000' '1970-01-01 00:00:00 +0000'\n+check_parse '@99999999 +0000' '1973-03-03 09:46:39 +0000'\n+check_parse '99999999 +0000' bad\n+check_parse '@100000000 +0000' '1973-03-03 09:46:40 +0000'\n+check_parse '100000000 +0000' '1973-03-03 09:46:40 +0000'\n+\n REQUIRE_64BIT_TIME=HAVE_64BIT_TIME\n check_parse '2099-12-31 23:59:59' '2099-12-31 23:59:59 +0000'\n check_parse '2099-12-31 23:59:59 +00' '2099-12-31 23:59:59 +0000'\n@@ -195,6 +202,10 @@ check_approxidate '6AM, June 7, 2009' '2009-06-07 06:00:00'\n check_approxidate '2008-12-01' '2008-12-01 19:20:00'\n check_approxidate '2009-12-01' '2009-12-01 19:20:00'\n \n+# ambiguous raw timestamp\n+check_approxidate '2000 +0000' '2000-08-30 19:20:00'\n+check_approxidate '@2000 +0000' '1970-01-01 00:33:20'\n+\n check_date_format_human() {\n \tt=$(($GIT_TEST_DATE_NOW - $1))\n \techo \"$t -> $2\" >expect\n-- \n2.53.0\n\n"},{"id":"544472","messageId":"ah6X0X9EQdL6hn53@pks.im","threadId":"65733","inReplyTo":"20260602081924.673763-2-dev@luna.gl","subject":"Re: [PATCH v2] doc: document and test `@` prefix for raw timestamps","fromName":"Patrick Steinhardt","fromEmail":"ps@pks.im","sentAt":"2026-06-02T08:44:01Z","receivedAt":"2026-06-02T08:44:06Z","isPatch":true,"body":"On Tue, Jun 02, 2026 at 10:17:36AM +0200, Luna Schwalbe wrote:\n> The Git internal date format `<unix-timestamp> <time-zone-offset>`\n> fails to parse when the timestamp is less than 100,000,000 (fewer than\n> 9 digits). This happens to avoid potential ambiguity with other date\n> formats such as `YYYYMMDD`, especially when used with approxidate.\n> \n> To force the parser to interpret the value as a raw timestamp, it must\n> be prefixed with `@` (e.g., `@0 +0000`). This behavior was introduced\n> in 2c733fb24c10a9d7aacc51f956bf9b7881980870 (parse_date(): '@' prefix\n> forces git-timestamp, 2012-02-02) but was never documented.\n> \n> Document the `@` prefix in `Documentation/date-formats.adoc` to make\n> this behavior explicit. Also add test cases to `t/t0006-date.sh` to\n> verify and demonstrate the difference between prefixed and unprefixed\n> small timestamps (e.g., `@2000` vs `2000`).\n> \n> Signed-off-by: Luna Schwalbe <dev@luna.gl>\n> Co-authored-by: Junio C Hamano <gitster@pobox.com>\n\nOne nit: the order of trailers is wrong, as your Signed-off-by trailer\nshould always be the last line of the commit message.\n\nIt would also be great to send the new version of a series as a reply to\nthe previous version, so that it becomes easier for reviewers to connect\nthe two series.\n\nYou can use a tool like b4, which can nowadays be configured exactly\nlike this with `git config set b4.send-same-thread shallow`. b4 overall\nmakes all of the mailing list wrangling a ton easier. Makes me wonder\nwhether we should maybe highlight this tool more in our docs.\n\nThe patch itself looks good to me, thanks!\n\nPatrick\n"},{"id":"544482","messageId":"xmqqmrxdxq1r.fsf@gitster.g","threadId":"65733","inReplyTo":"20260602081924.673763-2-dev@luna.gl","subject":"Re: [PATCH v2] doc: document and test `@` prefix for raw timestamps","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-06-02T09:14:08Z","receivedAt":"2026-06-02T09:14:10Z","isPatch":true,"body":"Luna Schwalbe <dev@luna.gl> writes:\n\n> The Git internal date format `<unix-timestamp> <time-zone-offset>`\n> fails to parse when the timestamp is less than 100,000,000 (fewer than\n> 9 digits). This happens to avoid potential ambiguity with other date\n> formats such as `YYYYMMDD`, especially when used with approxidate.\n>\n> To force the parser to interpret the value as a raw timestamp, it must\n> be prefixed with `@` (e.g., `@0 +0000`). This behavior was introduced\n> in 2c733fb24c10a9d7aacc51f956bf9b7881980870 (parse_date(): '@' prefix\n> forces git-timestamp, 2012-02-02) but was never documented.\n>\n> Document the `@` prefix in `Documentation/date-formats.adoc` to make\n> this behavior explicit. Also add test cases to `t/t0006-date.sh` to\n> verify and demonstrate the difference between prefixed and unprefixed\n> small timestamps (e.g., `@2000` vs `2000`).\n>\n> Signed-off-by: Luna Schwalbe <dev@luna.gl>\n> Co-authored-by: Junio C Hamano <gitster@pobox.com>\n> ---\n> Fixed the asciidoc formatting, removed parens around YYYYMMDD example.\n\nLooks good.\n\nNext time, when sending a [v2] patch of a singleton topic,\nplease make it a reply e-mail message to the [v1] message.  That\nwould make it easier to see how patches evolved in mailing list\narchive.  E.g., https://lore.kernel.org/git/$message_id would show\nboth rounds (including the review comments they received) on the\nsame page.\n\nWill queue.  Thanks.\n\n\n\n>  Documentation/date-formats.adoc |  5 +++++\n>  t/t0006-date.sh                 | 11 +++++++++++\n>  2 files changed, 16 insertions(+)\n>\n> diff --git a/Documentation/date-formats.adoc b/Documentation/date-formats.adoc\n> index e24517c49..330424b2b 100644\n> --- a/Documentation/date-formats.adoc\n> +++ b/Documentation/date-formats.adoc\n> @@ -9,6 +9,11 @@ Git internal format::\n>  \t`<unix-timestamp>` is the number of seconds since the UNIX epoch.\n>  \t`<time-zone-offset>` is a positive or negative offset from UTC.\n>  \tFor example CET (which is 1 hour ahead of UTC) is `+0100`.\n> ++\n> +It is safer to prepend the `<unix-timestamp>` with `@` (e.g.,\n> +`@0 +0000`), which forces Git to interpret it as a raw timestamp. This\n> +is required for values less than 100,000,000 (which have fewer than 9\n> +digits) to avoid confusion with other date formats like `YYYYMMDD`.\n>  \n>  RFC 2822::\n>  \tThe standard date format as described by RFC 2822, for example\n> diff --git a/t/t0006-date.sh b/t/t0006-date.sh\n> index 53ced36df..8b4e1870b 100755\n> --- a/t/t0006-date.sh\n> +++ b/t/t0006-date.sh\n> @@ -138,6 +138,13 @@ check_parse '1969-12-31 23:59:59 Z' bad\n>  check_parse '1969-12-31 23:59:59 +11' bad\n>  check_parse '1969-12-31 23:59:59 -11' bad\n>  \n> +# pathologically small timestamps requiring `@` prefix\n> +check_parse '@0 +0000' '1970-01-01 00:00:00 +0000'\n> +check_parse '@99999999 +0000' '1973-03-03 09:46:39 +0000'\n> +check_parse '99999999 +0000' bad\n> +check_parse '@100000000 +0000' '1973-03-03 09:46:40 +0000'\n> +check_parse '100000000 +0000' '1973-03-03 09:46:40 +0000'\n> +\n>  REQUIRE_64BIT_TIME=HAVE_64BIT_TIME\n>  check_parse '2099-12-31 23:59:59' '2099-12-31 23:59:59 +0000'\n>  check_parse '2099-12-31 23:59:59 +00' '2099-12-31 23:59:59 +0000'\n> @@ -195,6 +202,10 @@ check_approxidate '6AM, June 7, 2009' '2009-06-07 06:00:00'\n>  check_approxidate '2008-12-01' '2008-12-01 19:20:00'\n>  check_approxidate '2009-12-01' '2009-12-01 19:20:00'\n>  \n> +# ambiguous raw timestamp\n> +check_approxidate '2000 +0000' '2000-08-30 19:20:00'\n> +check_approxidate '@2000 +0000' '1970-01-01 00:33:20'\n> +\n>  check_date_format_human() {\n>  \tt=$(($GIT_TEST_DATE_NOW - $1))\n>  \techo \"$t -> $2\" >expect\n"},{"id":"544483","messageId":"xmqqik81xpqx.fsf@gitster.g","threadId":"65733","inReplyTo":"ah6X0X9EQdL6hn53@pks.im","subject":"Re: [PATCH v2] doc: document and test `@` prefix for raw timestamps","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2026-06-02T09:20:38Z","receivedAt":"2026-06-02T09:20:40Z","isPatch":true,"body":"Patrick Steinhardt <ps@pks.im> writes:\n\n> You can use a tool like b4, which can nowadays be configured exactly\n> like this with `git config set b4.send-same-thread shallow`. b4 overall\n> makes all of the mailing list wrangling a ton easier. Makes me wonder\n> whether we should maybe highlight this tool more in our docs.\n\nIt would be a very much welcome change.\n\nAnd \"b4\" also helps the receiving end, not just the sender.  With\n\"b4\" finding the latest round automatically, getting updated round\nonce a topic is in my tree is a breeze, thanks to the amlog notes.\nEssentially, I detach the HEAD at the previous base commit (often a\nbit older 'master', but a few prerequisite topis merged into it),\ngive \"b4 am -o-\" a message-id of one of the patches I have queued to\ndownload the latest and pipe that to \"git am -s\". That way, both\n\"git range-diff @{-1}...\" and \"git diff @{-1}\" become very effective\nways to see what changes were made to the topic.\n"},{"id":"544534","messageId":"8b2c15f8-0233-4e52-9412-9412b42756a8@luna.gl","threadId":"65733","inReplyTo":"xmqqmrxdxq1r.fsf@gitster.g","subject":"Re: [PATCH v2] doc: document and test `@` prefix for raw timestamps","fromName":"Luna Schwalbe","fromEmail":"dev@luna.gl","sentAt":"2026-06-02T16:35:41Z","receivedAt":"2026-06-02T16:35:46Z","isPatch":true,"body":"Thanks to both of you for pointing out my mistakes! I'll make sure to do \nit right next time.\n"}]}