diff --git a/error.go b/error.go index b4e9a4bf..1930f593 100644 --- a/error.go +++ b/error.go @@ -163,8 +163,7 @@ type ( errLexControl struct{ r rune } errLexEscape struct{ r rune } errLexUTF8 struct{ b byte } - errLexInvalidNum struct{ v string } - errLexInvalidDate struct{ v string } + errParseDate struct{ v string } errLexInlineTableNL struct{} errLexStringNL struct{} errParseRange struct { @@ -183,10 +182,8 @@ func (e errLexEscape) Error() string { return fmt.Sprintf(`invalid escape func (e errLexEscape) Usage() string { return usageEscape } func (e errLexUTF8) Error() string { return fmt.Sprintf("invalid UTF-8 byte: 0x%02x", e.b) } func (e errLexUTF8) Usage() string { return "" } -func (e errLexInvalidNum) Error() string { return fmt.Sprintf("invalid number: %q", e.v) } -func (e errLexInvalidNum) Usage() string { return "" } -func (e errLexInvalidDate) Error() string { return fmt.Sprintf("invalid date: %q", e.v) } -func (e errLexInvalidDate) Usage() string { return "" } +func (e errParseDate) Error() string { return fmt.Sprintf("invalid datetime: %q", e.v) } +func (e errParseDate) Usage() string { return usageDate } func (e errLexInlineTableNL) Error() string { return "newlines not allowed within inline tables" } func (e errLexInlineTableNL) Usage() string { return usageInlineNewline } func (e errLexStringNL) Error() string { return "strings cannot contain newlines" } @@ -277,3 +274,23 @@ A duration must be as "number", without any spaces. Valid units are: You can combine multiple units; for example "5m10s" for 5 minutes and 10 seconds. ` + +const usageDate = ` +A TOML datetime must be in one of the following formats: + + 2006-01-02T15:04:05Z07:00 Date and time, with timezone. + 2006-01-02T15:04:05 Date and time, but without timezone. + 2006-01-02 Date without a time or timezone. + 15:04:05 Just a time, without any timezone. + +Seconds may optionally have a fraction, up to nanosecond precision: + + 15:04:05.123 + 15:04:05.856018510 +` + +// TOML 1.1: +// The seconds part in times is optional, and may be omitted: +// 2006-01-02T15:04Z07:00 +// 2006-01-02T15:04 +// 15:04 diff --git a/error_test.go b/error_test.go index b7e362fc..48f558b4 100644 --- a/error_test.go +++ b/error_test.go @@ -44,7 +44,7 @@ At line 9, column 3-8: 9 | [fruit.variety] ^^^^^`}, {"datetime/trailing-t.toml", ` -toml: error: Invalid TOML Datetime: "2006-01-30T". +toml: error: invalid datetime: "2006-01-30T" At line 2, column 4-15: @@ -204,6 +204,32 @@ func TestParseError(t *testing.T) { | seconds. `, }, + + { + &struct{ D time.Time }{}, + `D = 2006-01-99`, + ` + | toml: error: invalid datetime: "2006-01-99" + | + | At line 1, column 4-14: + | + | 1 | D = 2006-01-99 + | ^^^^^^^^^^ + | Error help: + | + | A TOML datetime must be in one of the following formats: + | + | 2006-01-02T15:04:05Z07:00 Date and time, with timezone. + | 2006-01-02T15:04:05 Date and time, but without timezone. + | 2006-01-02 Date without a time or timezone. + | 15:04:05 Just a time, without any timezone. + | + | Seconds may optionally have a fraction, up to nanosecond precision: + | + | 15:04:05.123 + | 15:04:05.856018510 + `, + }, } prep := func(s string) string { diff --git a/parse.go b/parse.go index 510304d0..39b89a6e 100644 --- a/parse.go +++ b/parse.go @@ -371,7 +371,7 @@ func (p *parser) valueDatetime(it item) (any, tomlType) { } } if !ok { - p.panicItemf(it, "Invalid TOML Datetime: %q.", it.val) + p.panicErr(it, errParseDate{it.val}) } return t, p.typeOfPrimitive(it) }