@@ 30,9 30,9 @@ one:
[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 @@ 1. Implement RFC3339 first
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))
+ }