From 20e87a0f67a21db7b9bc7fb2bb7dbba6e19ca9a3 Mon Sep 17 00:00:00 2001 From: Martin Tournoij Date: Fri, 13 Oct 2023 13:49:36 +0100 Subject: [PATCH] Explicitly disallow year 0 Year "0" doesn't exist; it goes from 1 BC to 1 AD. RFC 3339 is somewhat unclear if this should be allowed, at least in my reading of it: > This document defines a [..] representation of dates and times using > the Gregorian calendar. "Gregorian calendar" has no "year zero", so it should be forbidden. But also: > All dates and times are assumed to be in the "current era", > somewhere between 0000AD and 9999AD. So meh. Practically speaking, supporting this across the board is rather tricky. Python's datetime has no way to represent this (other than None, maybe? Ugh.), PostgreSQL doesn't support it, Go's time.Time behaves oddly (e.g. IsZero() is false, which is rather surprising), etc. ISO 8601 defines year 0 as "1 BC", which is even worse since most datetime implementations don't really do BC dates. Just forbidding it is by far the easiest for everyone; for implementations with a datetime that supports it, it's just a single `if`, and for e.g. Python nothing needs to be done. The only potential downside is that people may have `d = 0000-01-01`. We already broke compatibility "for sanity" by disallowing table overrides, so I think that's okay. The alternative is making it implementation dependent. Meh. RFC 3339 is supposed to be a "ISO 8601, without obscure edge cases"; this seems to fit with the intended purpose. --- CHANGELOG.md | 1 + toml.abnf | 2 +- toml.md | 7 +++++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 14d3cebc..b7e346e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - Seconds in Date-Time and Time values are now optional. - Allow non-English scripts in unquoted (bare) keys - Clarify newline normalization in multi-line literal strings. +- Explicitly disallow year zero. ## 1.0.0 / 2021-01-11 diff --git a/toml.abnf b/toml.abnf index 0446f8b6..dedc4ee4 100644 --- a/toml.abnf +++ b/toml.abnf @@ -177,7 +177,7 @@ false = %x66.61.6C.73.65 ; false date-time = offset-date-time / local-date-time / local-date / local-time -date-fullyear = 4DIGIT +date-fullyear = 4DIGIT ; 0001-9999 date-month = 2DIGIT ; 01-12 date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on month/year time-delim = "T" / %x20 ; T, t, or space diff --git a/toml.md b/toml.md index 08cc9f67..9b5b3dfd 100644 --- a/toml.md +++ b/toml.md @@ -582,6 +582,13 @@ implementation-specific. If the value contains greater precision than the implementation can support, the additional precision must be truncated, not rounded. +The first year in the Gregorian calendar is year 1 (1 BC is followed by 1 AD), +and year 0 is not allowed: + +``` +odt7 = 0000-01-01 07:32:32Z # INVALID +``` + ## Local Date-Time If you omit the offset from an [RFC 3339](https://tools.ietf.org/html/rfc3339)