-
Type: Bug
-
Resolution: Fixed
-
Priority: Major - P3
-
Affects Version/s: None
-
Component/s: None
-
None
When storing structs in a collection which have a time.Time field that is
uninitialized and therefore zero value for time.Time we see:
{"time" : ISODate("0001-01-01T00:00:00Z")}
Which is what we want. When stored this way they will decode back to the zero
time so that the time.Time.IsZero() will still return True. However when trying
to query out these values you would naturally think to do:
var zeroTime time.Time query := bson.NewDocument( bson.EC.Time("time", zeroTime, )
This unintuitively produces different BSON than the encoder:
// query.String() // bson.Document{bson.Element{[UTC datetime]"time": 1754-08-30 17:43:41.129 -0500 EST}}
If you try to use the DateTime constructor you of course get an element for the Unix epoch time:
var zeroTime time.Time query := bson.NewDocument( bson.EC.DateTime("time", zeroTime.Unix()), ) // query.String() // bson.Document{bson.Element{[UTC datetime]"time": 1968-01-12 15:06:43.2 -0500 EST}}
Looking at the encoder code we find that this is because when given a time.Time
there is additional changes being made to the time.Time from our struct:
// bson/encode.go L534 case time.Time: elems = append(elems, EC.DateTime(key, convertTimeToInt64(t)))
Which points us to the function convertTimeToInt64:
// bson/encode.go L125 func convertTimeToInt64(t time.Time) int64 { return t.Unix()*1000 + int64(t.Nanosecond()/1e6) }
If we then apply this same math to our attempted query it now produces the
expected BSON:
var zeroTime time.Time query := bson.NewDocument( bson.EC.DateTime("completeddate", zeroTime.Unix()*1000+int64(zeroTime.Nanosecond()/1e6)), ) // query.String() // bson.Document{bson.Element{[UTC datetime]"completeddate": 0000-12-31 19:00:00 -0500 EST}}
From a user perspective this is unexpected and unintuitive. I would expect the
ElementConstructor which takes a higher level type to automatically perform any
necessary transformations and produce the same result as encoding a struct.