@@ 59,8 59,19 @@ 1. RFC3339 string like "2019-02-01T17:45
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:
+The [CBOR spec][rfc7049] has a special type of value called tags. This is used
+to represent data with additional semantics like timestamps. A tag is a major
+type with the value 6, it represents an integer number as indicated by the tag's
+integer value. That number corresponds to the tag’s type. For example URI’s are
+represented as a tagged unicode string in CBOR: first there’s the header with
+the major type 6 —indicating it’s a tag— with the value 32 —that corresponds to
+URIs—, this is followed by an UTF-8 CBOR string with the URI.
+
+Timestamps are like that, but they have two data item types: 0 for unicode
+strings encoded as a RFC3339 timestamp, or 1 for epoch-based timestamps.
+
+We'll start with RFC3339 string timestamps, 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")
@@ 92,7 103,7 @@ a kind of object we already handle in th
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:
+First we’ll set a variable to be time.Time’s representation of its type:
var typeTime = reflect.TypeOf(time.Time{})
@@ 109,9 120,23 @@ 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] indicates that
+We add a few constants required to encode our new values:
+
+ const (
+ // major types
+ ...
+ majorTag = 6
+ ...
-EXPLAIN HOW TAGS WORK
+ // major type 6: tagged values
+ minorTimeString = 0
+ minorTimeEpoch = 1
+ ...
+ )
+
+And then implement writeTime: it writes the tag’s header with minorTimeString
+to indicates an unicode string follows, and write the unicode string based on
+the timestamp’s value:
func (e *Encoder) writeTime(v reflect.Value) error {
if err := e.writeHeader(majorTag, minorTimeString); err != nil {
@@ 120,3 145,19 @@ EXPLAIN HOW TAGS WORK
var t = v.Interface().(time.Time)
return e.writeUnicodeString(t.Format(time.RFC3339))
}
+
+We hook it up to the rest of the code:
+
+ case reflect.Struct:
+ if x.Type() == typeTime {
+ return e.writeTime(x)
+ }
+ return e.writeStruct(x)
+
+We run `go test` to confirm everything works.
+
+Now we’ll handle epoch-based timestamps: those are scalar values where 0
+corresponds to the epoch (January 1, 1970), they can either be integer or
+floating point values.
+
+