Search code examples
goprotocol-buffers

Parsing a date from a mongoDB with golang time.Now()


I am creating a date using Go via time.Now() and it store it in the mongoDB with no issue. The date looks like 2023-02-28T20:10:46.140+00:00.

However when I try to retrieve it I get an error that reads:

{{"code":2, "message":"parsing time \"2023-02-28 20:10:46.14 +0000 UTC\" as \"2006-01-02T15:04:05Z07:00\": cannot parse \" 20:10:46.14 +0000 UTC\" as \"T\"", "details":[]}

It is coming from this piece of code.

createdAt, err := time.Parse(time.RFC3339, blog.CreatedAt.String())
if err != nil {
    return nil, err
}
updatedAt, err := time.Parse(time.RFC3339, blog.UpdatedAt.String())
if err != nil {
    return nil, err
}

tempBlog := &api.Blog{
    Id: blog.ID,
    CreatedAt: timestamppb.New(createdAt),
    UpdatedAt: timestamppb.New(updatedAt),

I found some useful documentation here and here and added the times parsed into Mongo manually, but I still run into this issue.

I have tried all of the time formats but it just results in a different error that is not able to parse.

Advice?


Solution

  • If you store time.Time MongoDB will auto retrieve it for you. The retrieved time is on UTC, if you want change to your local timezone, use time.Local().

    package date_test
    
    import (
        "context"
        "github.com/stretchr/testify/require"
        "go.mongodb.org/mongo-driver/bson"
        "go.mongodb.org/mongo-driver/mongo"
        "go.mongodb.org/mongo-driver/mongo/options"
        "os"
        "testing"
        "time"
    )
    
    type Something struct {
        Name       string    `json:"name" bson:"name"`
        CreateTime time.Time `json:"createTime" bson:"createTime"`
    }
    
    func TestDate(t *testing.T) {
        raw := Something{Name: "demo", CreateTime: time.Now()}
        t.Logf("raw: %v", raw)
        ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
        defer cancel()
        client, err := mongo.Connect(ctx, options.Client().ApplyURI(os.Getenv("URI")))
        require.NoError(t, err)
        collection := client.Database("test").Collection("demo")
        _, err = collection.InsertOne(ctx, raw)
        require.NoError(t, err)
        var res Something
        err = collection.FindOne(ctx, bson.D{{"name", raw.Name}}).Decode(&res)
        require.NoError(t, err)
        t.Logf("res: %v", res)
        t.Logf("local time: %v", res.CreateTime.Local())
    }
    

    Run the test code it will print something like this

    $ URI="mongodb://127.0.0.1:27017/" go test -v ./date_test.go
    === RUN   TestDate
        date_test.go:21: raw: {demo 2023-03-07 10:26:22.433473 +0800 CST m=+0.009080292}
        date_test.go:32: res: {demo 2023-03-07 02:26:22.433 +0000 UTC}
        date_test.go:33: local time: 2023-03-07 10:26:22.433 +0800 CST
    --- PASS: TestDate (0.01s)
    PASS
    ok      command-line-arguments  0.912s
    

    the mongo store the time like this

    > db.demo.find().pretty()
    {
        "_id" : ObjectId("6406a0ce4cfff0411ca8d98b"),
        "name" : "demo",
        "createTime" : ISODate("2023-03-07T02:26:22.433Z")
    }
    

    source code is here https://gist.github.com/alex-x-crypto/14c15d4921f1ece2962302cce87c97a8