# HG changeset patch # User Henry Precheur # Date 1576968191 28800 # Sat Dec 21 14:43:11 2019 -0800 # Node ID af8893e5c388495251e0106c7c9c5548a54829d0 # Parent 2dc983957c1a920830f043dbf349635461b2fcfb wip diff --git a/episode11/README.md b/episode11/README.md --- a/episode11/README.md +++ b/episode11/README.md @@ -30,9 +30,9 @@ [ep7]: http://henry.precheur.org/scratchpad/20180527_114309 [ep8]: http://henry.precheur.org/scratchpad/20180604_083306 [ep9]: http://henry.precheur.org/scratchpad/20190419_114828 -[ep10]: ... +[ep10]: http://henry.precheur.org/scratchpad/20191103_102445 [rfc7049]: https://tools.ietf.org/html/rfc7049 -[repo]: https://bitbucket.org/henry/cbor/src/default/episode9/ +[repo]: https://bitbucket.org/henry/cbor/src/default/episode11/ ---- @@ -47,3 +47,74 @@ 2. Introduce epoch base timestamp 3. Optimize: rfc3339 for time.Time w/ timezone, epoch for time.Time w/o 3. Fix old RFC3339 example + +We implemented all the Go native types, now we’ll implement a custom stype: +time.Time, a timestamp type. According the the [CBOR spec][rfc7049] + +FIXME find link to section + +There are 3 types of timestamps supported by CBOR: + +1. RFC3339 string like "2019-02-01T17:45:23Z" +2. floating point value ... +3. integer value ... + +We'll start with the RFC3339 string, lookup the example in the spec and add our +first test: + + func TestTimestamp(t *testing.T) { + var rfc3339Timestamp, _ = time.Parse(time.RFC3339, "2013-03-21T20:04:00Z") + + var cases = []struct { + Value time.Time + Expected []byte + }{ + { + Value: rfc3339Timestamp, + Expected: []byte{ + 0xc0, 0x74, 0x32, 0x30, 0x31, 0x33, 0x2d, 0x30, 0x33, 0x2d, + 0x32, 0x31, 0x54, 0x32, 0x30, 0x3a, 0x30, 0x34, 0x3a, 0x30, + 0x30, 0x3a, + }, + }, + } + + for _, c := range cases { + t.Run(fmt.Sprintf("%v", c.Value), func(t *testing.T) { + testEncoder(t, c.Value, c.Expected) + }) + } + } + +How can we detect if we have a time.Time object in the encoder? Looking at +[time.Time’s definition](https://godoc.org/time#Time) we see that it’s a struct, +a kind of object we already handle in the encoder. The reflect package lets us +query the type of a value, so what we have to check is the struct’s type is +time.Time when we have a struct. + +First we’ll set a variable to be time.Time’s type: + + var typeTime = reflect.TypeOf(time.Time{}) + +And in the main switch block we add a branch in the reflect.Struct case to +handle time.Time if we have a value with that type: + + case reflect.Struct: + if x.Type() == typeTime { + return ErrNotImplemented + } + return e.writeStruct(x) + +Let’s add a new function to write timestamps as CBOR values: writeTime. First +we’ll implement RFC3339 string timestamps, and support other timestamp types +after. + +The [CBOR spec][rfc7049] + + func (e *Encoder) writeTime(v reflect.Value) error { + if err := e.writeHeader(majorTag, minorTimeString); err != nil { + return err + } + var t = v.Interface().(time.Time) + return e.writeUnicodeString(t.Format(time.RFC3339)) + }