diff --git a/decode.go b/decode.go index 895d140c..d3d3b839 100644 --- a/decode.go +++ b/decode.go @@ -65,8 +65,7 @@ func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error { // TOML table arrays correspond to either a slice of structs or a slice of maps. // // TOML datetimes correspond to Go time.Time values. Local datetimes are parsed -// in the local timezone and have the Location set to the decoders's Timezone -// value. This defaults to this computer's local timezone if not given. +// in the local timezone. // // All other TOML types (float, string, int, bool and array) correspond to the // obvious Go types. @@ -94,10 +93,6 @@ func (md *MetaData) PrimitiveDecode(primValue Primitive, v interface{}) error { // cyclic type is passed. type Decoder struct { r io.Reader - - // Timezone to use for local times. Defaults to this computer's local - // timezone if nil. - //Timezone *time.Location } // NewDecoder creates a new Decoder. diff --git a/decode_test.go b/decode_test.go index 92cb1c10..f51101f9 100644 --- a/decode_test.go +++ b/decode_test.go @@ -9,6 +9,8 @@ import ( "strings" "testing" "time" + + "github.com/BurntSushi/toml/internal" ) func TestDecodeReader(t *testing.T) { @@ -687,12 +689,12 @@ func TestDecodeDatetime(t *testing.T) { {"1979-05-27T07:32:12-07:00 # c", time.Date(1979, 05, 27, 07, 32, 12, 0, tz7)}, // Local times. - {"1979-05-27T07:32:00", time.Date(1979, 05, 27, 07, 32, 0, 0, LocalDatetime)}, - {"1979-05-27T07:32:00.999999", time.Date(1979, 05, 27, 07, 32, 0, 999999000, LocalDatetime)}, - {"1979-05-27T07:32:00.25", time.Date(1979, 05, 27, 07, 32, 0, 250000000, LocalDatetime)}, - {"1979-05-27", time.Date(1979, 05, 27, 0, 0, 0, 0, LocalDate)}, - {"07:32:00", time.Date(0, 1, 1, 07, 32, 0, 0, LocalTime)}, - {"07:32:00.999999", time.Date(0, 1, 1, 07, 32, 0, 999999000, LocalTime)}, + {"1979-05-27T07:32:00", time.Date(1979, 05, 27, 07, 32, 0, 0, internal.LocalDatetime)}, + {"1979-05-27T07:32:00.999999", time.Date(1979, 05, 27, 07, 32, 0, 999999000, internal.LocalDatetime)}, + {"1979-05-27T07:32:00.25", time.Date(1979, 05, 27, 07, 32, 0, 250000000, internal.LocalDatetime)}, + {"1979-05-27", time.Date(1979, 05, 27, 0, 0, 0, 0, internal.LocalDate)}, + {"07:32:00", time.Date(0, 1, 1, 07, 32, 0, 0, internal.LocalTime)}, + {"07:32:00.999999", time.Date(0, 1, 1, 07, 32, 0, 999999000, internal.LocalTime)}, } { t.Run(tt.in, func(t *testing.T) { var x struct{ D time.Time } diff --git a/encode.go b/encode.go index c8aa01b7..10d88ac6 100644 --- a/encode.go +++ b/encode.go @@ -12,6 +12,8 @@ import ( "strconv" "strings" "time" + + "github.com/BurntSushi/toml/internal" ) type tomlEncodeError struct{ error } @@ -184,17 +186,17 @@ func (enc *Encoder) eElement(rv reflect.Value) { case time.Time: // Using TextMarshaler adds extra quotes, which we don't want. format := time.RFC3339Nano switch v.Location() { - case LocalDatetime: + case internal.LocalDatetime: format = "2006-01-02T15:04:05.999999999" - case LocalDate: + case internal.LocalDate: format = "2006-01-02" - case LocalTime: + case internal.LocalTime: format = "15:04:05.999999999" } switch v.Location() { default: enc.wf(v.Format(format)) - case LocalDatetime, LocalDate, LocalTime: + case internal.LocalDatetime, internal.LocalDate, internal.LocalTime: enc.wf(v.In(time.UTC).Format(format)) } return diff --git a/internal/tag/add.go b/internal/tag/add.go index 4a23a54a..88f69503 100644 --- a/internal/tag/add.go +++ b/internal/tag/add.go @@ -5,7 +5,7 @@ import ( "math" "time" - "github.com/BurntSushi/toml" + "github.com/BurntSushi/toml/internal" ) // Add JSON tags to a data structure as expected by toml-test. @@ -44,11 +44,11 @@ func Add(key string, tomlData interface{}) interface{} { switch orig.Location() { default: return tag("datetime", orig.Format("2006-01-02T15:04:05.999999999Z07:00")) - case toml.LocalDatetime: + case internal.LocalDatetime: return tag("datetime-local", orig.Format("2006-01-02T15:04:05.999999999")) - case toml.LocalDate: + case internal.LocalDate: return tag("date-local", orig.Format("2006-01-02")) - case toml.LocalTime: + case internal.LocalTime: return tag("time-local", orig.Format("15:04:05.999999999")) } diff --git a/internal/tag/rm.go b/internal/tag/rm.go index 7be1224d..884cda15 100644 --- a/internal/tag/rm.go +++ b/internal/tag/rm.go @@ -5,7 +5,7 @@ import ( "strconv" "time" - "github.com/BurntSushi/toml" + "github.com/BurntSushi/toml/internal" ) // Rempve JSON tags to a data structure as returned by toml-test. @@ -70,11 +70,11 @@ func untag(typed map[string]interface{}) interface{} { case "datetime": return parseTime(v, "2006-01-02T15:04:05.999999999Z07:00", nil) case "datetime-local": - return parseTime(v, "2006-01-02T15:04:05.999999999", toml.LocalDatetime) + return parseTime(v, "2006-01-02T15:04:05.999999999", internal.LocalDatetime) case "date-local": - return parseTime(v, "2006-01-02", toml.LocalDate) + return parseTime(v, "2006-01-02", internal.LocalDate) case "time-local": - return parseTime(v, "15:04:05.999999999", toml.LocalTime) + return parseTime(v, "15:04:05.999999999", internal.LocalTime) case "bool": switch v { case "true": diff --git a/internal/tz.go b/internal/tz.go new file mode 100644 index 00000000..022f15bc --- /dev/null +++ b/internal/tz.go @@ -0,0 +1,36 @@ +package internal + +import "time" + +// Timezones used for local datetime, date, and time TOML types. +// +// The exact way times and dates without a timezone should be interpreted is not +// well-defined in the TOML specification and left to the implementation. These +// defaults to current local timezone offset of the computer, but this can be +// changed by changing these variables before decoding. +// +// TODO: +// Ideally we'd like to offer people the ability to configure the used timezone +// by setting Decoder.Timezone and Encoder.Timezone; however, this is a bit +// tricky: the reason we use three different variables for this is to support +// round-tripping – without these specific TZ names we wouldn't know which +// format to use. +// +// There isn't a good way to encode this right now though, and passing this sort +// of information also ties in to various related issues such as string format +// encoding, encoding of comments, etc. +// +// So, for the time being, just put this in internal until we can write a good +// comprehensive API for doing all of this. +// +// The reason they're exported is because they're referred from in e.g. +// internal/tag. +// +// Note that this behaviour is valid according to the TOML spec as the exact +// behaviour is left up to implementations. +var ( + localOffset = func() int { _, o := time.Now().Zone(); return o }() + LocalDatetime = time.FixedZone("datetime-local", localOffset) + LocalDate = time.FixedZone("date-local", localOffset) + LocalTime = time.FixedZone("time-local", localOffset) +) diff --git a/parse.go b/parse.go index 8006c884..d9ae5db9 100644 --- a/parse.go +++ b/parse.go @@ -7,6 +7,8 @@ import ( "strings" "time" "unicode/utf8" + + "github.com/BurntSushi/toml/internal" ) type parser struct { @@ -298,41 +300,14 @@ func (p *parser) valueFloat(it item) (interface{}, tomlType) { return num, p.typeOfPrimitive(it) } -// Timezones used for local datetime, date, and time TOML types. -// -// The exact way times and dates without a timezone should be interpreted is not -// well-defined in the TOML specification and left to the implementation. These -// defaults to current local timezone offset of the computer, but this can be -// changed by changing these variables before decoding. -// -// The reason we use three different variables for this is to support -// round-tripping. -// -// TODO: these really shouldn't be package-level globals, and there also -// shouldn't be three variables. The problem is that the time is decoded in the -// parse stage, rather than the decode stage. -// -// Decoder and Encoder should both support a Timezone attribute instead. -// Round-tripping is more tricky though, as there isn't a way to pass this -// information yet. -// -// The reason they're exported is because they're referred from in e.g. -// internal/tag. -var ( - localOffset = func() int { _, o := time.Now().Zone(); return o }() - LocalDatetime = time.FixedZone("datetime-local", localOffset) - LocalDate = time.FixedZone("date-local", localOffset) - LocalTime = time.FixedZone("time-local", localOffset) -) - var dtTypes = []struct { fmt string zone *time.Location }{ {time.RFC3339Nano, time.Local}, - {"2006-01-02T15:04:05.999999999", LocalDatetime}, - {"2006-01-02", LocalDate}, - {"15:04:05.999999999", LocalTime}, + {"2006-01-02T15:04:05.999999999", internal.LocalDatetime}, + {"2006-01-02", internal.LocalDate}, + {"15:04:05.999999999", internal.LocalTime}, } func (p *parser) valueDatetime(it item) (interface{}, tomlType) {