Parse Date dynamically - date

I have a case in which I can have both Date alone or with Date + Time Zone . So when I parse it with TimeZone like this
dateString := "2021-03-11T00:00:00Z"
time1, _ := time.Parse(time.RFC3339,dateString);
fmt.Println(time1);
It gives accurate answer but when I dynamically It gets Date like
dateString := "2021-03-11"
time1, _ := time.Parse(time.RFC3339,dateString);
fmt.Println(time1); //gives this 0001-01-01 00:00:00 +0000 UTC
while In both cases I just want date like this "2021-03-11". what is best way to achieve this

To parse just the date, you can use "2006-01-02" as the layout to time.Parse.
See the official docs for how these layouts are handled and what time.Parse expects.
As #zerkms says in a comment, if you check the error from time.Parse you'll know whether it succeeded or not, so you can try something else. Rough code sketch:
dateString := "2021-03-11"
time1, err := time.Parse(time.RFC3339, dateString)
if err != nil {
time1, err = time.Parse("2006-01-02", dateString)
if err != nil {
log.Fatal("cannot parse using either layout:", err)
}
}
fmt.Println(time1)
In real life I'd probably wrap it in a function that tries parsing both ways before it gives up and returns an error.

Related

Search documents using $gt filter with go-mongodb driver

I'm stuck at a probably simple problem: If I filter this in mongodb compass (filter {dateTime:{$gt: new Date("2020-11-23T12:31:38")}}):
It returns 556 documents.
Trying to create a cursor in Go that have those documents is proving to be quite hard!
I've this right now:
cursor, err := coll.Find(context.Background(), bson.M{"dateTime": bson.M{"$gt": "new Date("+ date + ")"}}, opt)
if err != nil {
fmt.Println("Err creting database: ", err)
return nil, err
}
if cursor.Next(context.Background()) {
fmt.Println("Cursor0!")
cursor.Next(context.Background())
}
cursor1, err := coll.Find(context.Background(), bson.M{}, opt)
if err != nil {
fmt.Println("Err creting database: ", err)
return nil, err
}
if cursor1.Next(context.Background()) {
fmt.Println("Cursor1!")
cursor.Next(context.Background())
}.
I've tried, along other different tries, to put the filter just as bson.M{"dateTime": bson.M{"$gt": date}}, along other similar tryes, but they also returned 0 documents. The date variable have exacly the date used in the mongodb compass filter.
I created another cursor, with no filter, just to control if the connection with mongo is ok, and to see if it returns any documents when it has no filter, and it does return documents. Does anyone knows the answer to this one?
Thanks!!
new Date("2020-11-23T12:31:38") is JavaScript syntax. You need to use the proper Go syntax for creating timestamps.
The problem was that I was dealling with more than 1 Collection, and in one the date was saved as string, and in the other, as date. In the one that the date s saved as string, no surprise, we have to send the date as string too, some logic to when date is in mongo as Date

Parse UTC date string and convert to different format

Go newcomer here.
I have a date string 2018-06-07T16:16:57Z and I want to convert it to something like this mm/dd/yyyy hh:mm.
This seems to be a frequently asked question, but I can't seem to find any previous questions that work for me.
I'm reading in a time field and trying to convert like this
time := row["Date & Time"]
fmt.Println(time)
t, _ := time.Parse("2006-01-02 15:04:05 -0700 UTC", time)
fmt.Println(t)
But I think the issue is that I don't have a correct format string. I've tried a few resources to no success.
When I print t as is, I get 0001-01-01 00:00:00 +0000 UTC as a result, which is obviously incorrect.
What I'd like to do is convert the time I'm reading in like this
newTime := currentDate.Format("01/02/2006 hh:mm")
You have two issues.
First, you should not name the variable time as that is the name of a built-in package. I suppose you knew that and this is just a copy paste error.
Next, the string you pass to time.Parse() is a format string that should describe the format of the time string from your database. You already know what the format is: 2018-06-07T16:16:57Z, so just use that replacing the value with Go's reference time.
Here is working variant:
package main
import (
"fmt"
"time"
)
func main() {
tm := "2018-06-07T16:16:57Z"
fmt.Println(tm)
t, err := time.Parse("2006-01-02T15:04:05Z", tm)
if err != nil {
panic(err)
}
fmt.Println(t)
}
Run in playground
What's more the time format database uses is often described as RFC3339, which is also available as the time.RFC3339 constant in Go.
So using that simplifies your code even further:
package main
import (
"fmt"
"time"
)
func main() {
tm := "2018-06-07T16:16:57Z"
fmt.Println(tm)
t, err := time.Parse(time.RFC3339, tm)
if err != nil {
panic(err)
}
fmt.Println(t)
}
Run in playground
And if you prefer, you could also let the database driver convert the time for you by scanning it to a time.Time variable.
For example:
var tm time.Time
if err = row.Scan(&tm); err != nil {
panic(err)
}
fmt.Print(tm)
As #mkopriva describes the layout should be matched. Understand the layout which is 2006-01-02T15:04:05Z, go through Golang spec for layout use to convert the string to date
Parse parses a formatted string and returns the time value it
represents. The layout defines the format by showing how the reference
time, defined to be
Mon Jan 2 15:04:05 -0700 MST 2006
and then use returned time value to Format the date according to your requirement.
package main
import (
"fmt"
"time"
)
func main() {
layout1 := "2006-01-02T15:04:05Z"
t, err := time.Parse(layout1, "2018-06-07T16:16:57Z")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(t.Format("01/02/2006 15:04"))
}
Check it on Go Playground

How to convert YYYY-MM-DD string format to timestamp in Golang?

I'm sorry if this is a trivial question. This is currently what I have.
snapshot = "2017-07-25"
snapshotFilter := " AND cdate = %s"
snapshot, err := time.Parse(time.RFC3339, snapshot)
if err != nil {
log.Fatal(err)
}
queryFilter = queryFilter + fmt.Sprintf(snapshotFilter, pq.FormatTimestamp(snapshot))
This is the output
2017/09/12 09:59:34 parsing time "2017-07-25" as "2006-01-02T15:04:05Z07:": cannot parse "" as "T".
I'm trying to get snapshot in the correct format to insert it into a postgres query.
I'm using the
"database/sql"
"time"
"github.com/gorilla/mux"
"github.com/lib/pq"
EDIT: is seemed that this was more of an issue with postgres and the 2017-07-25 just needed to be in quotes and put inside the postgres query string.
As already suggested, use this:
package main
import (
"fmt"
"log"
"time"
)
const layout = "2006-01-02"
func main() {
snapshot := "2017-07-25"
t, err := time.Parse(layout, snapshot)
if err != nil {
log.Fatal(err)
}
fmt.Println(t)
}
As you can see in the documentation of constants for the time package there is a reference date
Layout = "01/02 03:04:05PM '06 -0700" // The reference time, in numerical order.
which is used to specify date/time strings layout. So you provide a string and every occurrence of 3 gets replaced by the hour in 12h am/pm notation of your point in time and every occurrence of 15 gets replaced by the hour in 24h representation for example.
All the wrinkles and problems of such an approach are explained in some sample code in the documentation.

Golang/mgo : How can I store ISODate by GMT+8 Time Zone in mongodb?

If I store ISODate in mongodb,the ISODate is always GMT+0
type StoreTime struct {
storeTime time.Time `bson:"testTime" json:"testTime,omitempty"`
}
...
t := StoreTime {
storeTime : time.Now(),
}
....
c.Insert(t)
The result is :
{
"_id" : ObjectId("578b43e5feaa0deb6a94b1d0"),
"storeTime" : ISODate("2016-07-17T08:38:25.316+0000")
}
How can I change the time zone?
You came across an intricacy of mgo.v2/bson, which converts Since the BSON specification states that all times shall be stored as
UTC milliseconds since the Unix epoch
mgo.v2/bson converts all time.Time values to UTC. So even when you explicitly set the location info of a time returned by time.Now() or companions, this local time is converted to UTC.
So in order to display time correctly for any given time zone, you should do the following:
When saving a time.Time value, you should use the time as returned by time.Time.In(*time.Location) if the time zone differs from your (the servers) local time.
When displaying the returned value in UTC, make sure you use time.Time.UTC()
When displaying the returned value in a given local time, make sure you use time.Time.In(*time.Location) again.
To be a more clear on that, please have a look at the example below:
package main
import (
"fmt"
"time"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
const (
myLoc = "Europe/Berlin"
ny = "America/New_York"
)
// We define those vars here, as you might want to make them
// package-global
var (
berlin *time.Location
nyc *time.Location
)
// StoreTime is just a dummy struct
type StoreTime struct {
// Unexported fields are not (un-)marshalled by encoding/json
// and mgo.v2/bson, so the field name has to be uppercase
StoreTime time.Time `bson:"testTime"`
}
func main() {
var (
sess *mgo.Session
err error
)
// Connect to MongoDB
if sess, err = mgo.Dial("localhost:27017"); err != nil {
panic("Could not connect to MongoDB: " + err.Error())
}
// Make sure the session is closed when main exits for whatever reason
defer sess.Close()
// Clear the collection for demo purposes
if err = sess.DB("test").C("timezones").Remove(bson.M{}); err != nil && err != mgo.ErrNotFound {
panic("Could not clean test collection: " + err.Error())
}
// Load the desired TZ by location
if berlin, err = time.LoadLocation(myLoc); err != nil {
panic("Error loading '" + myLoc + "' as timezone location: " + err.Error())
}
// Create a new StoreTime with the local time of the desired timezone.
// Note that mgo.v2/bson still converts it to Zulu time, but with the
// appropriate offset.
st := &StoreTime{StoreTime: time.Now().In(berlin)}
// Save the document for further reference
if err = sess.DB("test").C("timezones").Insert(st); err != nil {
panic("Error inserting sample document into MongoDB: " + err.Error())
}
// Load the saved document,...
res := &StoreTime{}
if err = sess.DB("test").C("timezones").Find(nil).One(&res); err != nil {
panic("Unable to load just recently stored document: " + err.Error())
}
// ... and another TZ for displaying,...
if nyc, err = time.LoadLocation(ny); err != nil {
panic("Error loading '" + ny + "' as timezone location: " + err.Error())
}
// ...and display the time from the document in UTC and the local time
// of both Berlin and NYC.
fmt.Println(res.StoreTime.UTC())
// The next two are identical for _me_, as I happen to live in the according TZ.
// Unless you do, too, you should have different values
fmt.Println(res.StoreTime.In(Berlin))
fmt.Println(res.StoreTime)
fmt.Println(res.StoreTime.In(nyc))
}
time.Now should return local time. Is your system time setup properly? What do you get on running the date command (on linux based system)?
You can try using In method on you time object with a time.Location value:
l, _ := time.LoadLocation("Local") // or the name of your time zone
t : time.Now()
t := StoreTime {
storeTime : t.In(l),
}

Golang/mgo : How can I store Date (not ISODate) in mongodb?

If I store current time like this:
type Test struct {
Id string `bson:"id" json:"id,omitempty"`
TestTime time.Time `bson:"testTime" json:"testTime,omitempty"`
}
...
t := Test {
Id : "TEST0001",
TestTime : time.Now(),
}
...
c.Insert(t)
Then I use mongochef to search it :
{
"_id" : ObjectId("576bc7a48114a14b47920d60"),
"id" : "TEST0001",
"testTime" : ISODate("2016-06-23T11:27:30.447+0000")
}
So, mgo store ISODate by default, how can I store Date not ISODate ?
mgo automagically converts time.Time into a Mongo internal date data type (source, actually it's just a timestamp with no timezone info and it's always corrected to UTC). Any other functionaly has to be manually implemented by you.
You can force mgo to correctly (de)serialize your types by implementing the Getter and Setter interfaces from package mgo/bson thought it's pretty low-level so be careful.
You should define a custom struct that saves the timezone like this.
The you can define a custom Unmarshal that changes the location of the date on loading.
func (t *TimeWithTimezone) Unmarshal(in []byte, out interface{}) (err error) {
type decode TimeWithTimezone
var d decode
if err := bson.NewDecoder(in).Decode(&d); err != nil {
return err
}
loc, err := FixedZone(d.Timezone, d.Timezone)
if err != nil {
return fmt.Errorf("Invalid Timezone: %s", d.Timezone)
}
t.Time = d.Time.In(loc)
t.Timezone = d.Timezone
return nil
}
Something like this should do the trick, it's not tested, just to give you an idea!