[GODRIVER-564] bson.EC.Time does not treat the zero time.Time value the same as the encoder Created: 17/Sep/18  Updated: 28/Oct/23  Resolved: 11/Oct/18

Status: Closed
Project: Go Driver
Component/s: None
Affects Version/s: None
Fix Version/s: 0.0.16

Type: Bug Priority: Major - P3
Reporter: Mathew Robinson (Inactive) Assignee: Mathew Robinson (Inactive)
Resolution: Fixed Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

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.



 Comments   
Comment by Githook User [ 11/Oct/18 ]

Author:

{'name': 'Mathew Robinson', 'email': 'chasinglogic@gmail.com', 'username': 'chasinglogic'}

Message: GODRIVER-564 Use same time.Time conversion in Encoder and ElementConstructor
Branch: master
https://github.com/mongodb/mongo-go-driver/commit/ca78baa2ff3177d42b9c2555c1b61b03b2b21adc

Generated at Thu Feb 08 08:34:29 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.