threads / discuss / 61110

log.date 'iso-strict' does not comply with ISO 8601-1:2020-12

Subject: log.date 'iso-strict' does not comply with ISO 8601-1:2020-12

## tl;dr

10 messages between Mar 13, 2024 and Mar 13, 2024.

replies: 9people: 4as markdown or json

Osipov, Michael (IN IT IN)· Mar 13, 2024, 11:27 UTC · lore
Folks,
I am running git version 2.43.0 and consider the following config:
> $ git config --system --list
> core.eol=native
> log.date=iso-strict
> color.ui=auto
when a commit happens with a zero offset the following is displayed:
Show 8 quoted lines
> osipovmi@deblndw011x:~/var/Projekte/tomcat-native ((ba1454e15...)|BISECTING)
> $ git log
> commit ba1454e15619a44fe66d86f59c766c0cc25323eb (HEAD)
> Author: Mark Thomas <markt@apache.org>
> Date:   2024-02-13T08:27:43+00:00
> 
>     Fix link
> 
This not right according to the standard in the original language 
version, namely in sections:
* 4.3.13 Zeitverschiebung (time shift) (roughly translated from German): 
Z denotes that there is no shift from UTC. It also says that you either 
have an offset or use "Z"
* 5.3.3 Uhrzeit in UTC (time in UTC) (roughly translated from German): 
...the formats from sections ... must be used followed by the UTC marker 
"Z" without space.

Throughout the definition neither +0000 for the basic format nor +00:00 for the extended format are used to denote a zero offset from UTC.

The offending code snippet is here: https://github.com/git/git/blob/945115026aa63df4ab849ab14a04da31623abece/date.c#L344-L352

See also Java's Instant class [1] which is based on ISO 8601 as well is Java's SimpleDateFormat XXX [2] which will *always* print "Z" in case of a zero offset.

I'd expect Git to comply with strict since this is why it has been introduced years ago instead of modifying 'iso'.

Regards,
Michael

[1] https://docs.oracle.com/javase/8/docs/api/java/time/Instant.html [2] https://github.com/openjdk/jdk8u-dev/blob/fbb3392d744d1572239eeca082d7365a03897b8b/jdk/src/share/classes/java/text/SimpleDateFormat.java#L1291-L1306

Beat Bolli· Mar 13, 2024, 17:50 UTC · re: Osipov, Michael (IN IT IN) · lore

[PATCH] date: make "iso-strict" conforming for the UTC timezone

ISO 8601-1:2020-12 specifies that a zero timezone offset must be denoted with a "Z" suffix instead of the numeric "+00:00". Add the correponding special case to show_date() and a new test.

Reported-by: Michael Osipov <michael.osipov@innomotics.com>
Link: https://lore.kernel.org/git/410d458c-ae5b-40cc-9c8e-97b016c74a76@siemens.com/
Signed-off-by: Beat Bolli <dev+git@drbeat.li>
---
 date.c          | 14 +++++++++-----
 t/t0006-date.sh |  1 +
 2 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/date.c b/date.c
index 619ada5b2044..44cf2221d81f 100644
--- a/date.c
+++ b/date.c
@@ -342,14 +342,18 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)
 				tm->tm_hour, tm->tm_min, tm->tm_sec,
 				tz);
 	else if (mode->type == DATE_ISO8601_STRICT) {
-		char sign = (tz >= 0) ? '+' : '-';
-		tz = abs(tz);
-		strbuf_addf(&timebuf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
+		strbuf_addf(&timebuf, "%04d-%02d-%02dT%02d:%02d:%02d",
 				tm->tm_year + 1900,
 				tm->tm_mon + 1,
 				tm->tm_mday,
-				tm->tm_hour, tm->tm_min, tm->tm_sec,
-				sign, tz / 100, tz % 100);
+				tm->tm_hour, tm->tm_min, tm->tm_sec);
+		if (tz == 0) {
+			strbuf_addch(&timebuf, 'Z');
+		} else {
+			strbuf_addch(&timebuf, tz >= 0 ? '+' : '-');
+			tz = abs(tz);
+			strbuf_addf(&timebuf, "%02d:%02d", tz / 100, tz % 100);
+		}
 	} else if (mode->type == DATE_RFC2822)
 		strbuf_addf(&timebuf, "%.3s, %d %.3s %d %02d:%02d:%02d %+05d",
 			weekday_names[tm->tm_wday], tm->tm_mday,
diff --git a/t/t0006-date.sh b/t/t0006-date.sh
index e18b1602864e..1d228a981ee9 100755
--- a/t/t0006-date.sh
+++ b/t/t0006-date.sh
@@ -46,6 +46,7 @@ check_show () {
 TIME='1466000000 +0200'
 check_show iso8601 "$TIME" '2016-06-15 16:13:20 +0200'
 check_show iso8601-strict "$TIME" '2016-06-15T16:13:20+02:00'
+check_show iso8601-strict "$(echo "$TIME" | sed 's/+0200$/+0000/')" '2016-06-15T14:13:20Z'
 check_show rfc2822 "$TIME" 'Wed, 15 Jun 2016 16:13:20 +0200'
 check_show short "$TIME" '2016-06-15'
 check_show default "$TIME" 'Wed Jun 15 16:13:20 2016 +0200'
-- 
2.44.0
Junio C Hamano· Mar 13, 2024, 18:30 UTC · re: Beat Bolli · lore

Re: [PATCH] date: make "iso-strict" conforming for the UTC timezone

"Beat Bolli" <bb@drbeat.li> writes:
> ISO 8601-1:2020-12 specifies that a zero timezone offset must be denoted
> with a "Z" suffix instead of the numeric "+00:00". Add the correponding
> special case to show_date() and a new test.

Hmph, would this break existing scripts that expects the current behaviour, and if it does, is it safe for us to blame the script authors for not following the standard?

Assuming that we do not need to worry about them, the patch itself looks perfectly reasonable to me.

Thanks.
Show 48 quoted lines
> Reported-by: Michael Osipov <michael.osipov@innomotics.com>
> Link: https://lore.kernel.org/git/410d458c-ae5b-40cc-9c8e-97b016c74a76@siemens.com/
> Signed-off-by: Beat Bolli <dev+git@drbeat.li>
> ---
>  date.c          | 14 +++++++++-----
>  t/t0006-date.sh |  1 +
>  2 files changed, 10 insertions(+), 5 deletions(-)
>
> diff --git a/date.c b/date.c
> index 619ada5b2044..44cf2221d81f 100644
> --- a/date.c
> +++ b/date.c
> @@ -342,14 +342,18 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)
>  				tm->tm_hour, tm->tm_min, tm->tm_sec,
>  				tz);
>  	else if (mode->type == DATE_ISO8601_STRICT) {
> -		char sign = (tz >= 0) ? '+' : '-';
> -		tz = abs(tz);
> -		strbuf_addf(&timebuf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
> +		strbuf_addf(&timebuf, "%04d-%02d-%02dT%02d:%02d:%02d",
>  				tm->tm_year + 1900,
>  				tm->tm_mon + 1,
>  				tm->tm_mday,
> -				tm->tm_hour, tm->tm_min, tm->tm_sec,
> -				sign, tz / 100, tz % 100);
> +				tm->tm_hour, tm->tm_min, tm->tm_sec);
> +		if (tz == 0) {
> +			strbuf_addch(&timebuf, 'Z');
> +		} else {
> +			strbuf_addch(&timebuf, tz >= 0 ? '+' : '-');
> +			tz = abs(tz);
> +			strbuf_addf(&timebuf, "%02d:%02d", tz / 100, tz % 100);
> +		}
>  	} else if (mode->type == DATE_RFC2822)
>  		strbuf_addf(&timebuf, "%.3s, %d %.3s %d %02d:%02d:%02d %+05d",
>  			weekday_names[tm->tm_wday], tm->tm_mday,
> diff --git a/t/t0006-date.sh b/t/t0006-date.sh
> index e18b1602864e..1d228a981ee9 100755
> --- a/t/t0006-date.sh
> +++ b/t/t0006-date.sh
> @@ -46,6 +46,7 @@ check_show () {
>  TIME='1466000000 +0200'
>  check_show iso8601 "$TIME" '2016-06-15 16:13:20 +0200'
>  check_show iso8601-strict "$TIME" '2016-06-15T16:13:20+02:00'
> +check_show iso8601-strict "$(echo "$TIME" | sed 's/+0200$/+0000/')" '2016-06-15T14:13:20Z'
>  check_show rfc2822 "$TIME" 'Wed, 15 Jun 2016 16:13:20 +0200'
>  check_show short "$TIME" '2016-06-15'
>  check_show default "$TIME" 'Wed Jun 15 16:13:20 2016 +0200'
Osipov, Michael (IN IT IN)· Mar 13, 2024, 19:29 UTC · re: Junio C Hamano · lore

Re: [PATCH] date: make "iso-strict" conforming for the UTC timezone

On 2024-03-13 19:30, Junio C Hamano wrote:
Show 9 quoted lines
> "Beat Bolli" <bb@drbeat.li> writes:
> 
>> ISO 8601-1:2020-12 specifies that a zero timezone offset must be denoted
>> with a "Z" suffix instead of the numeric "+00:00". Add the correponding
>> special case to show_date() and a new test.
> 
> Hmph, would this break existing scripts that expects the current
> behaviour, and if it does, is it safe for us to blame the script
> authors for not following the standard?
 From my PoV, if they don't stick it is not you to blame. The standard 
also says that it is equiv ("Z") to both numeral offsets. At the end 
strict is strict.
Thanks,
Michael
Beat Bolli· Mar 13, 2024, 22:29 UTC · re: Junio C Hamano · lore

[PATCH v2] date: make "iso-strict" conforming for the UTC timezone

ISO 8601-1:2020-12 specifies that a zero timezone offset must be denoted with a "Z" suffix instead of the numeric "+00:00". Add the correponding special case to show_date() and a new test.

This changes an established output format which might be depended on by scripts. The original patch 466fb6742d7f (pretty: provide a strict ISO 8601 date format, 2014-08-29) mentioned XML parsers as its rationale, which generally have good parsing support, so this change should be fine.

Reported-by: Michael Osipov <michael.osipov@innomotics.com>
Signed-off-by: Beat Bolli <dev+git@drbeat.li>
---
Changes from v1:
- added a comment why the change is fine
- removed the Link: trailer
 date.c          | 14 +++++++++-----
 t/t0006-date.sh |  1 +
 2 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/date.c b/date.c
index 619ada5b2044..44cf2221d81f 100644
--- a/date.c
+++ b/date.c
@@ -342,14 +342,18 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)
 				tm->tm_hour, tm->tm_min, tm->tm_sec,
 				tz);
 	else if (mode->type == DATE_ISO8601_STRICT) {
-		char sign = (tz >= 0) ? '+' : '-';
-		tz = abs(tz);
-		strbuf_addf(&timebuf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
+		strbuf_addf(&timebuf, "%04d-%02d-%02dT%02d:%02d:%02d",
 				tm->tm_year + 1900,
 				tm->tm_mon + 1,
 				tm->tm_mday,
-				tm->tm_hour, tm->tm_min, tm->tm_sec,
-				sign, tz / 100, tz % 100);
+				tm->tm_hour, tm->tm_min, tm->tm_sec);
+		if (tz == 0) {
+			strbuf_addch(&timebuf, 'Z');
+		} else {
+			strbuf_addch(&timebuf, tz >= 0 ? '+' : '-');
+			tz = abs(tz);
+			strbuf_addf(&timebuf, "%02d:%02d", tz / 100, tz % 100);
+		}
 	} else if (mode->type == DATE_RFC2822)
 		strbuf_addf(&timebuf, "%.3s, %d %.3s %d %02d:%02d:%02d %+05d",
 			weekday_names[tm->tm_wday], tm->tm_mday,
diff --git a/t/t0006-date.sh b/t/t0006-date.sh
index e18b1602864e..1d228a981ee9 100755
--- a/t/t0006-date.sh
+++ b/t/t0006-date.sh
@@ -46,6 +46,7 @@ check_show () {
 TIME='1466000000 +0200'
 check_show iso8601 "$TIME" '2016-06-15 16:13:20 +0200'
 check_show iso8601-strict "$TIME" '2016-06-15T16:13:20+02:00'
+check_show iso8601-strict "$(echo "$TIME" | sed 's/+0200$/+0000/')" '2016-06-15T14:13:20Z'
 check_show rfc2822 "$TIME" 'Wed, 15 Jun 2016 16:13:20 +0200'
 check_show short "$TIME" '2016-06-15'
 check_show default "$TIME" 'Wed Jun 15 16:13:20 2016 +0200'
-- 
2.44.0
Junio C Hamano· Mar 13, 2024, 22:42 UTC · re: Beat Bolli · lore

Re: [PATCH v2] date: make "iso-strict" conforming for the UTC timezone

"Beat Bolli" <bb@drbeat.li> writes:
Show 9 quoted lines
> ISO 8601-1:2020-12 specifies that a zero timezone offset must be denoted
> with a "Z" suffix instead of the numeric "+00:00". Add the correponding
> special case to show_date() and a new test.
>
> This changes an established output format which might be depended on by
> scripts. The original patch 466fb6742d7f (pretty: provide a strict ISO
> 8601 date format, 2014-08-29) mentioned XML parsers as its rationale,
> which generally have good parsing support, so this change should be
> fine.
"fine." -> "fine for that particular usecase."

Unlike in 2005, we no longer write our features only for our own single use case that motivated it. I do not think it is possible to make this change without breaking some real script, and admitting this is a breaking change and we are knowingly doing so is probably better in the longer term.

Saying "this should be fine" in the log will give future developers room to consider reverting it, and while they are free to make such a decision based on the reality at their time in the future, we should give them a data point from our point of view: we know it may break somebody but we are still doing so knowingly as upside to adhere to a published standard and help those users who adhere to the same standard is more valuable then the unfortunate script that bended themselves to match our earlier mistake.

Thanks.
Beat Bolli· Mar 13, 2024, 22:54 UTC · re: Junio C Hamano · lore

[PATCH v3] date: make "iso-strict" conforming for the UTC timezone

ISO 8601-1:2020-12 specifies that a zero timezone offset must be denoted with a "Z" suffix instead of the numeric "+00:00". Add the correponding special case to show_date() and a new test.

Changing an established output format which might be depended on by scripts is always problematic, but here we choose to adhere more closely to the published standard.

Reported-by: Michael Osipov <michael.osipov@innomotics.com>
Signed-off-by: Beat Bolli <dev+git@drbeat.li>
---
Changes from v2:
- changed the rationale according to Junio's feedback
Changes from v1:
- added a comment why the change is fine
- removed the Link: trailer
 date.c          | 14 +++++++++-----
 t/t0006-date.sh |  1 +
 2 files changed, 10 insertions(+), 5 deletions(-)
diff --git a/date.c b/date.c
index 619ada5b2044..44cf2221d81f 100644
--- a/date.c
+++ b/date.c
@@ -342,14 +342,18 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)
 				tm->tm_hour, tm->tm_min, tm->tm_sec,
 				tz);
 	else if (mode->type == DATE_ISO8601_STRICT) {
-		char sign = (tz >= 0) ? '+' : '-';
-		tz = abs(tz);
-		strbuf_addf(&timebuf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
+		strbuf_addf(&timebuf, "%04d-%02d-%02dT%02d:%02d:%02d",
 				tm->tm_year + 1900,
 				tm->tm_mon + 1,
 				tm->tm_mday,
-				tm->tm_hour, tm->tm_min, tm->tm_sec,
-				sign, tz / 100, tz % 100);
+				tm->tm_hour, tm->tm_min, tm->tm_sec);
+		if (tz == 0) {
+			strbuf_addch(&timebuf, 'Z');
+		} else {
+			strbuf_addch(&timebuf, tz >= 0 ? '+' : '-');
+			tz = abs(tz);
+			strbuf_addf(&timebuf, "%02d:%02d", tz / 100, tz % 100);
+		}
 	} else if (mode->type == DATE_RFC2822)
 		strbuf_addf(&timebuf, "%.3s, %d %.3s %d %02d:%02d:%02d %+05d",
 			weekday_names[tm->tm_wday], tm->tm_mday,
diff --git a/t/t0006-date.sh b/t/t0006-date.sh
index e18b1602864e..1d228a981ee9 100755
--- a/t/t0006-date.sh
+++ b/t/t0006-date.sh
@@ -46,6 +46,7 @@ check_show () {
 TIME='1466000000 +0200'
 check_show iso8601 "$TIME" '2016-06-15 16:13:20 +0200'
 check_show iso8601-strict "$TIME" '2016-06-15T16:13:20+02:00'
+check_show iso8601-strict "$(echo "$TIME" | sed 's/+0200$/+0000/')" '2016-06-15T14:13:20Z'
 check_show rfc2822 "$TIME" 'Wed, 15 Jun 2016 16:13:20 +0200'
 check_show short "$TIME" '2016-06-15'
 check_show default "$TIME" 'Wed Jun 15 16:13:20 2016 +0200'
-- 
2.44.0
Junio C Hamano· Mar 13, 2024, 23:06 UTC · re: Beat Bolli · lore

Re: [PATCH v3] date: make "iso-strict" conforming for the UTC timezone

"Beat Bolli" <bb@drbeat.li> writes:
Show 7 quoted lines
> ISO 8601-1:2020-12 specifies that a zero timezone offset must be denoted
> with a "Z" suffix instead of the numeric "+00:00". Add the correponding
> special case to show_date() and a new test.
>
> Changing an established output format which might be depended on by
> scripts is always problematic, but here we choose to adhere more closely
> to the published standard.

Perfect. Thanks for following it through. Will replace (I've queued v2 already but it is easy to replace).

Show 57 quoted lines
>
> Reported-by: Michael Osipov <michael.osipov@innomotics.com>
> Signed-off-by: Beat Bolli <dev+git@drbeat.li>
> ---
> Changes from v2:
>
> - changed the rationale according to Junio's feedback
>
> Changes from v1:
>
> - added a comment why the change is fine
> - removed the Link: trailer
>
>  date.c          | 14 +++++++++-----
>  t/t0006-date.sh |  1 +
>  2 files changed, 10 insertions(+), 5 deletions(-)
>
> diff --git a/date.c b/date.c
> index 619ada5b2044..44cf2221d81f 100644
> --- a/date.c
> +++ b/date.c
> @@ -342,14 +342,18 @@ const char *show_date(timestamp_t time, int tz, const struct date_mode *mode)
>  				tm->tm_hour, tm->tm_min, tm->tm_sec,
>  				tz);
>  	else if (mode->type == DATE_ISO8601_STRICT) {
> -		char sign = (tz >= 0) ? '+' : '-';
> -		tz = abs(tz);
> -		strbuf_addf(&timebuf, "%04d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d",
> +		strbuf_addf(&timebuf, "%04d-%02d-%02dT%02d:%02d:%02d",
>  				tm->tm_year + 1900,
>  				tm->tm_mon + 1,
>  				tm->tm_mday,
> -				tm->tm_hour, tm->tm_min, tm->tm_sec,
> -				sign, tz / 100, tz % 100);
> +				tm->tm_hour, tm->tm_min, tm->tm_sec);
> +		if (tz == 0) {
> +			strbuf_addch(&timebuf, 'Z');
> +		} else {
> +			strbuf_addch(&timebuf, tz >= 0 ? '+' : '-');
> +			tz = abs(tz);
> +			strbuf_addf(&timebuf, "%02d:%02d", tz / 100, tz % 100);
> +		}
>  	} else if (mode->type == DATE_RFC2822)
>  		strbuf_addf(&timebuf, "%.3s, %d %.3s %d %02d:%02d:%02d %+05d",
>  			weekday_names[tm->tm_wday], tm->tm_mday,
> diff --git a/t/t0006-date.sh b/t/t0006-date.sh
> index e18b1602864e..1d228a981ee9 100755
> --- a/t/t0006-date.sh
> +++ b/t/t0006-date.sh
> @@ -46,6 +46,7 @@ check_show () {
>  TIME='1466000000 +0200'
>  check_show iso8601 "$TIME" '2016-06-15 16:13:20 +0200'
>  check_show iso8601-strict "$TIME" '2016-06-15T16:13:20+02:00'
> +check_show iso8601-strict "$(echo "$TIME" | sed 's/+0200$/+0000/')" '2016-06-15T14:13:20Z'
>  check_show rfc2822 "$TIME" 'Wed, 15 Jun 2016 16:13:20 +0200'
>  check_show short "$TIME" '2016-06-15'
>  check_show default "$TIME" 'Wed Jun 15 16:13:20 2016 +0200'
Osipov, Michael (IN IT IN)· Mar 13, 2024, 19:27 UTC · re: Beat Bolli · lore

Re: [PATCH] date: make "iso-strict" conforming for the UTC timezone

On 2024-03-13 18:50, Beat Bolli wrote:
> ISO 8601-1:2020-12 specifies that a zero timezone offset must be denoted
> with a "Z" suffix instead of the numeric "+00:00". Add the correponding
> special case to show_date() and a new test.
Thanks for this lightspeed fix!
Kristoffer Haugsbakk· Mar 13, 2024, 20:09 UTC · re: Beat Bolli · lore

Re: [PATCH] date: make "iso-strict" conforming for the UTC timezone

On Wed, Mar 13, 2024, at 18:50, Beat Bolli wrote:
> Reported-by: Michael Osipov <michael.osipov@innomotics.com>
> Link: https://lore.kernel.org/git/410d458c-ae5b-40cc-9c8e-97b016c74a76@siemens.com/
> Signed-off-by: Beat Bolli <dev+git@drbeat.li>

I personally don’t really think `Link` trailers are necessary in this project given the existence of `refs/notes/amlog`.

🔗 https://lore.kernel.org/git/ebe188e5-7289-4f7b-b845-d59a47cd06fe@app.fastmail.com/
-- 
Kristoffer Haugsbakk

← back to recent threads