Cannot parse time as T when parsing RFC3339 string to time - go

I have a string from db , say
dbString := "2020-03-16 14:46:13 +0530 IST"
My requirement is to insert this string as Timestamptz into another table
I am trying to convert dbString into Time
timeToBeInserted := time.Parse(time.RFC3339,t.VO.DateLastModified)
I see the below error
+0000 UTC parsing time "2020-03-16 14:46:13 +0530 IST" as "2006-01-02T15:04:05Z07:00": cannot parse " 14:46:13 +0530 IST" as "T"

Your date string does not match RFC3339 format:
RFC3339 = "2006-01-02T15:04:05Z07:00"
You should use a custom format. The following one works with your string:
dbString := "2020-03-16 14:46:13 +0530 IST"
fmt.Println(time.Parse("2006-01-02 15:04:05 -0700 MST", dbString))
// Output:
// 2020-03-16 14:46:13 +0530 IST <nil>

Your time string isn't in RFC3339 format, so don't tell time.Parse that it is. Instead use
time.Parse("2006-01-02 15:04:05 -0700 MST", t.VO.DateLastModified)

Related

How to parse "2021-01-19T16:20:04+0000" as time.Time

I've tried the following format which should catch the +0000 timezone offset as I read https://golang.org/pkg/time/#pkg-constants:
ts, err := time.Parse("2006-01-02T15:04:05-0700", "2021-01-19T16:20:04+0000")
But that looks rather strange when the result ist printed (no error):
2021-01-19 16:47:00 +0000 +0000
UPDATE
Running https://play.golang.org/p/wHBYz7iKnLT locally (OSX 11.1) gives the strange result:
❯ gor time.go
2021-01-19 16:20:04 +0000 +0000 <nil>
What you see is the "default" formatting, e.g. when printed like fmt.Println(ts), which is the result of Time.String(). Quoting from Time.String():
String returns the time formatted using the format string
"2006-01-02 15:04:05.999999999 -0700 MST"
As you can see, it contains the zone offset and the zone name in the end.
Also note that you used time.Parse() which documents that:
In the absence of a time zone indicator, Parse returns a time in UTC.
When parsing a time with a zone offset like -0700, if the offset corresponds to a time zone used by the current location (Local), then Parse uses that location and zone in the returned time. Otherwise it records the time as being in a fabricated location with time fixed at the given zone offset.
Since on the Go Playground the local time is set to UTC whose offset matches the offset of the time you parse, that zone will be used, so printing it on the Go Playground you'll see UTC.
When you parse it locally (on your computer) and the local time zone is not UTC or another zone that has 0 offset, as per the doc, that location is recorded as a fabricated location with the name having the offset.
So when you parse and print that time locally, since the default format includes both the zone offset and the zone name, and since both are +0000, you'll see +0000 printed twice.
Worry not, the parsed time is of course correct:
ts, err := time.Parse("2006-01-02T15:04:05-0700", "2021-01-19T16:20:04+0000")
if err != nil {
panic(err)
}
fmt.Println(ts)
fmt.Println(ts.Format("2006-01-02 16:04:05 -0700"))
fmt.Println(ts.Format("2006-01-02 16:04:05 MST"))
This outputs on the Go Playground:
2021-01-19 16:20:04 +0000 UTC
2021-01-19 16:20:04 +0000
2021-01-19 16:20:04 UTC
Locally (having CET zone) it outputs:
2021-01-19 16:20:04 +0000 +0000
2021-01-19 16:20:04 +0000
2021-01-19 16:20:04 +0000
Note that if you'd parse a time with a different zone offset (not being 0), you'll see the same on the Go Playground too. For example:
ts, err := time.Parse("2006-01-02T15:04:05-0700", "2021-01-19T16:20:04+1100")
if err != nil {
panic(err)
}
fmt.Println(ts)
fmt.Println(ts.Format("2006-01-02 16:04:05 -0700"))
fmt.Println(ts.Format("2006-01-02 16:04:05 MST"))
This outputs both on the Go Playground and locally for me (with CET zone):
2021-01-19 16:20:04 +1100 +1100
2021-01-19 16:20:04 +1100
2021-01-19 16:20:04 +1100

Format datetime to HH:MM, AM/PM

If I have a string in datetime in this format 2020-11-03T06:30:00.000Z
how to get only HH:MM AM/PM out of it like 06:30 AM
You can parse string value use time.Parse(layout, value string) and then parsed.Format(layout string) the result (look at src/time/format.go, src/time/format_test.go)
date := "2020-11-03T06:30:00.000Z"
parsed, err := time.Parse(time.RFC3339, date)
fmt.Println(parsed)
fmt.Println(parsed.Format("15:04 PM"))
0utput 👇🏼
2020-11-03 06:30:00 +0000 UTC
06:30 AM
PLAYGROUND

Golang Time parse issue

I am executing below code to parse a time
var time_format = "2006-01-02T15:04:05.000+0700"
var s = "2018-08-23T14:10:31.692+0700"
p, _ := time.Parse(time_format, s)
fmt.Println(p.String())
The output of above program is as below.
2018-08-23 14:10:31.692 +0000 UTC
It is the same time in UTC while I am parsing a time which is +0700 ahead of UTC so as expeceted result should be
2018-08-23 7:10:31.692 +0000 UTC
Can anyone tell what is the issue here.
It's because your format string is not correct. The timezone indication must be -0700 (not +0700). time.Parse():
The layout defines the format by showing how the reference time, defined to be
Mon Jan 2 15:04:05 -0700 MST 2006
With that change it works:
var format = "2006-01-02T15:04:05.000-0700"
var s = "2018-08-23T14:10:31.692+0700"
p, err := time.Parse(format, s)
fmt.Println(p.String(), err)
This will output (try it on the Go Playground):
2018-08-23 14:10:31.692 +0700 +0700 <nil>

golang timezone daylight savings time doesn't work

I know that on 26 Oct, 2014 02:00am the clock should go backwards 1 hour, but I can't reproduce this using a simple golang program
const timeFormat = "2 Jan, 2006 3:04pm"
loc, err := time.LoadLocation("Europe/Moscow")
log.Print(loc, err)
testz , _ := time.ParseInLocation( timeFormat, "26 Oct, 2014 01:59am", loc)
fmt.Println( testz , testz.UTC())
testz = testz.Add( time.Minute )
fmt.Println( testz , testz.UTC())
testz = testz.Add( time.Minute )
fmt.Println( testz , testz.UTC())
outputs
2014-10-26 01:59:00 +0300 MSK 2014-10-25 22:59:00 +0000 UTC
2014-10-26 02:00:00 +0300 MSK 2014-10-25 23:00:00 +0000 UTC
2014-10-26 02:01:00 +0300 MSK 2014-10-25 23:01:00 +0000 UTC
go 1.6, linux
Given your output, it looks like this line:
testz , _ := time.ParseInLocation(timeFormat, "26 Oct, 2014 01:59am", loc)
... is actually giving you the later of the two occurrences of 1:59am, given that it's showing an offset of +3. In other words, you're looking at three minutes of time an hour later than you want to be - starting nearly an hour after the daylight saving transition.
You can change your code to start with an unambiguous value like this:
testz, _ := time.ParseInLocation(timeFormat, "26 Oct, 2014 00:59am", loc)
testz = testz.Add(time.Hour)
I'd expect that to then show
2014-10-26 01:59:00 +0400 MSK 2014-10-25 21:59:00 +0000 UTC
2014-10-26 01:00:00 +0300 MSK 2014-10-25 22:00:00 +0000 UTC
2014-10-26 01:01:00 +0300 MSK 2014-10-25 22:01:00 +0000 UTC
(I haven't tried this, as I don't have Go installed - but I'd expect it to work.)
It's not because your code has error,just for time.UTC() will print UTC time,that is timezone 0 time,and from your code time.LoadLocation("Europe/Moscow") we can know maybe you are in Moscow,which belongs to east timezone 3,so the time will be earlier than utc time by three hours,meaning that <your time>=<utc time>+3.

convert YYYYMMDD string to a valid date in Go

I want to convert a string "20101011" to a valid date (2010-10-11), but could not figure our how to do it.
I tried:
now := time.Now()
date := now.Format("20101011")
and
date, _ := time.Parse("20101011", "20101011")
neither one worked.
Package time
import "time"
Constants
const (
ANSIC = "Mon Jan _2 15:04:05 2006"
UnixDate = "Mon Jan _2 15:04:05 MST 2006"
RubyDate = "Mon Jan 02 15:04:05 -0700 2006"
RFC822 = "02 Jan 06 15:04 MST"
RFC822Z = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
RFC850 = "Monday, 02-Jan-06 15:04:05 MST"
RFC1123 = "Mon, 02 Jan 2006 15:04:05 MST"
RFC1123Z = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
RFC3339 = "2006-01-02T15:04:05Z07:00"
RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
Kitchen = "3:04PM"
// Handy time stamps.
Stamp = "Jan _2 15:04:05"
StampMilli = "Jan _2 15:04:05.000"
StampMicro = "Jan _2 15:04:05.000000"
StampNano = "Jan _2 15:04:05.000000000"
)
These are predefined layouts for use in Time.Format and Time.Parse.
The reference time used in the layouts is the specific time:
Mon Jan 2 15:04:05 MST 2006
which is Unix time 1136239445. Since MST is GMT-0700, the reference
time can be thought of as
01/02 03:04:05PM '06 -0700
To define your own format, write down what the reference time would
look like formatted your way; see the values of constants like ANSIC,
StampMicro or Kitchen for examples. The model is to demonstrate what
the reference time looks like so that the Format and Parse methods can
apply the same transformation to a general time value.
Use the time format string "20060102" for YYYYMMDD. Use the time format string "2006-01-02" for YYYY-MM-DD.
For example,
package main
import (
"fmt"
"time"
)
func main() {
now := time.Now()
fmt.Println(now)
date := now.Format("20060102")
fmt.Println(date)
date = now.Format("2006-01-02")
fmt.Println(date)
date2, err := time.Parse("20060102", "20101011")
if err == nil {
fmt.Println(date2)
}
}
Output:
2009-11-10 23:00:00 +0000 UTC
20091110
2009-11-10
2010-10-11 00:00:00 +0000 UTC
You can do the following:
dateStr := "20210131" // date in 'String' data type
dateValue, _ := time.Parse("20060102", dateStr) // convert 'String' to 'Time' data type
fmt.Println(dateValue) // output: 2021-01-31 00:00:00 +0000 UTC
dateStr = dateValue.Format("2006-01-02") // Format return a 'string' in your specified layout (YYYY-MM-DD)
fmt.Println(dateStr) // Output: 2021-01-31
If you don't mind another library, Google's civil package has a nice ParseDate() which skips the interim time.Time conversion. It can be used like so:
func ParseDate(s string) (Date, error) {
date, err := civil.ParseDate(s)
return Date{date}, err
}

Resources