PST to UTC parsing of time in Golang - go

I am trying to convert the time from PST to UTC timezone but seeing some unexpected result, while IST to UTC is working fine:
package main
import (
"fmt"
"time"
)
func main() {
const longForm = "2006-01-02 15:04:05 MST"
t, err := time.Parse(longForm, "2016-01-17 20:04:05 IST")
fmt.Println(t, err)
fmt.Printf("IST to UTC: %v\n\n", t.UTC())
s, err1 := time.Parse(longForm, "2016-01-17 23:04:05 PST")
fmt.Println(s, err1)
fmt.Printf("PST to UTC: %v\n\n", s.UTC())
}
Output is :
2016-01-17 20:04:05 +0530 IST <nil>
IST to UTC: 2016-01-17 14:34:05 +0000 UTC
2016-01-17 23:04:05 +0000 PST <nil>
PST to UTC: 2016-01-17 23:04:05 +0000 UTC
When parsing is done for IST, it shows +0530, while for PST shows +0000 and in UTC it print same value of HH:MM:SS (23:04:05) as in PST. Am i missing anything here?

The documentation for time.Parse() says:
If the zone abbreviation is unknown, Parse records the time as being in a fabricated location with the given zone abbreviation and a zero offset. This choice means that such a time can be parsed and reformatted with the same layout losslessly, but the exact instant used in the representation will differ by the actual zone offset. To avoid such problems, prefer time layouts that use a numeric zone offset, or use ParseInLocation.
Here is how to use ParseInLocation:
IST, err := time.LoadLocation("Asia/Kolkata")
if err != nil {
fmt.Println(err)
return
}
PST, err := time.LoadLocation("America/Los_Angeles")
if err != nil {
fmt.Println(err)
return
}
const longForm = "2006-01-02 15:04:05 MST"
t, err := time.ParseInLocation(longForm, "2016-01-17 20:04:05 IST", IST)
fmt.Println(t, err)
fmt.Printf("IST to UTC: %v\n\n", t.UTC())
s, err1 := time.ParseInLocation(longForm, "2016-01-17 23:04:05 PST", PST)
fmt.Println(s, err1)
fmt.Printf("PST to UTC: %v\n\n", s.UTC())
Output:
2016-01-17 20:04:05 +0530 IST <nil>
IST to UTC: 2016-01-17 14:34:05 +0000 UTC
2016-01-17 23:04:05 -0800 PST <nil>
PST to UTC: 2016-01-18 07:04:05 +0000 UTC
Full code on the Go Playground

The documentation for time.Parse() says:
If the zone abbreviation is unknown, Parse records the time as being in a fabricated location with the given zone abbreviation and a zero offset. This choice means that such a time can be parsed and reformatted with the same layout losslessly, but the exact instant used in the representation will differ by the actual zone offset. To avoid such problems, prefer time layouts that use a numeric zone offset, or use ParseInLocation.
So, the system doesn't know what "PST" is. For me, the system also doesn't know what IST is. You can check for supported locations like so:
package main
import (
"fmt"
"time"
)
func main() {
for _, name := range []string{"MST", "UTC", "IST", "PST", "EST", "PT"} {
loc, err := time.LoadLocation(name)
if err != nil {
fmt.Println("No location", name)
} else {
fmt.Println("Location", name, "is", loc)
}
}
}
Output on my system:
Location MST is MST
Location UTC is UTC
No location IST
No location PST
Location EST is EST
No location PT

Related

Getting error while parsing timestamp string

I tried parsing
Tue Apr 07 2020 11:17:47 GMT+0530 (India Standard Time)
But got the following error
parsing time "Tue Apr 07 2020 11:17:47 GMT+0530 (India Standard Time)"
as "2006-01-02T15:04:05Z07:00": cannot parse "Tue Apr 07 2020 11:17:47
GMT+0530 (India Standard Time)" as "2006" 0001-01-01 00:00:00 +0000
UTC
From the frontend i can get timestamp in any format depending on the location or zone.But, in go lang i'm trying to parse any timestamp and convert it to UTC to store in ledger.What is the correct way to handle this case?
t, err := time.Parse(time.RFC3339, str)
if err != nil {
fmt.Println(err)
}
fmt.Println(t)
The reference time used in the Go time layouts is the specific time, Mon Jan 2 15:04:05 MST 2006. To define your own format, write down what the reference time would look like formatted your way.
Since MST is GMT-0700, use your ref string that way in the first argument.
package main
import (
"fmt"
"time"
)
func main() {
// Parsing your custom time format by using the reference time in your format.
t1, err := time.Parse(
"Mon Jan 02 2006 15:04:05 GMT-0700",
"Tue Apr 07 2020 11:17:47 GMT+0530")
if err != nil {
fmt.Println(err)
}
fmt.Println(t1.UTC())
}
The Go Playground

String to date conversion (IST with +0530)

I'm not able to convert the string "2017-12-07T20:01:33+0530" into a date format. I'm using RFC3339 and RFC3339Nano but still getting the following error:
0001-01-01 00:00:00 +0000 UTC parsing time "2016-01-17 20:04:05 +0530": hour out of range
IST to UTC: 0001-01-01 00:00:00 +0000 UTC
This is my code:
IST, err := time.LoadLocation("Asia/Kolkata")
if err != nil {
fmt.Println(err)
return
}
const longForm = "2006-01-02 15:04:05 +0530"
t, err := time.ParseInLocation(longForm, "2016-01-17 20:04:05 +0530", IST)
fmt.Println(t, err)
fmt.Printf("IST to UTC: %v\n\n", t.UTC())
The format specifier for the timezone is wrong; you have:
const longForm = "2006-01-02 15:04:05 +0530"
But the timezone is defined as -0700, not +0530. So that should be:
const longForm = "2006-01-02 15:04:05 -0700"

Use timestamp from Mysql in humanize.Time() package

I have a mariaDB database with a timestamp field. I want the values from that field being parsed to time.Time() values. This is possible by adding the ?parseTime=true to the connection string. After fetching a row, I want to use the value (which is time.Time) with humanize.Time(). Unfortunately values within the past 60 minutes are converted by humanize.Time() as 1 hour from now. When I put directly a time.Time() value into humanize.Time(), it gives me x seconds ago.
So I don't know what I'm doing wrong here. I think I need to convert 2017-04-23 14:00:16 +0000 UTC to 2017-04-23 14:00:16.370758048 +0200 CEST, but how?
package main
import (
"fmt"
"log"
"time"
humanize "github.com/dustin/go-humanize"
)
// value from database: 2017-04-23 14:00:16 +0000 UTC
// typical time.Now() value: 2017-04-23 14:00:16.370758048 +0200 CEST
func main() {
layout := "2006-01-02 15:04:05 -0700 MST"
beforeParsing := "2017-04-23 14:00:16 +0000 UTC"
t, err := time.Parse(layout, beforeParsing)
if err != nil {
log.Fatal(err)
}
fmt.Println(t)
fmt.Println(humanize.Time(t))
}

Not able to parse time properly

I'm trying to parse time for values in a template like so:
"parseDate": func(timeStamp time.Time) string {
newTime, err := time.Parse("Jan 2 2006 # 15:04:05", fmt.Sprintf("%v", timeStamp))
if err != nil {
log.Println(err)
}
return fmt.Sprintf("%v", newTime)
},
which is one of my handler funcs, but I get this error:
parsing time "2015-12-13 06:49:52 +0000 UTC" as "Jan 2 2006 # 15:04:05": cannot parse "2015-12-13 06:49:52 +0000 UTC" as "Jan"
Not sure what I'm doing wrong
You have to parse it as
t, _ := time.Parse("2006-01-02 15:04:05 -0700 MST")
For parsing you have to give the format of the date you are receiving.
Then you can format the correctly parsed time using
t.Format("Jan 2 2006 # 15:04:05")

How to parse Mon, 5 Oct 2015 00:24:08 +0800 (GMT+08:00)

I'm trying to parse a time value (received via email) but I can't find what layout I should use.
package main
import "fmt"
import "time"
func main() {
layout := "Mon, _2 Jan 2006 15:04:05 -0700 (MST-07:00)"
data := "Mon, 5 Oct 2015 00:24:08 +0800 (GMT+08:00)"
t, err := time.Parse(layout, data)
if err != nil {
panic(err)
}
fmt.Println(t)
}
Check
panic: parsing time "Mon, 5 Oct 2015 00:24:08 +0800 (GMT+08:00)" as "Mon, _2 Jan 2006 15:04:05 -0700 (MST-07:00)": cannot parse ":00)" as "-07:00"
Please read the Important note! section to get a full picture as the last part including GMT is not what it seems (that is, it is not the zone abbreviation).
Your input time string is not parsable as-is with the time package because in the last part (GMT+08:00) the zone abbreviation and the zone offset are not separated with any extra characters. And since the zone abbreviation is not limited to 3 characters, the "+08" is also treated as part of the zone abbreviation, which will only leave the rest ":00)" to match the zone offset "-07:00" hence the error message:
cannot parse ":00)" as "-07:00"
Possible workaround:
Simply cut off the extra zone offset as it is redundant (duplicate because zone offset is included twice):
func Parse(s string) (time.Time, error) {
if len(s) < 7 {
return time.Time{}, errors.New("Too short!")
}
s = s[:len(s)-7]
layout := "Mon, _2 Jan 2006 15:04:05 -0700 (MST"
return time.Parse(layout, s)
}
And using it:
data := "Mon, 5 Oct 2015 00:24:08 +0800 (GMT+08:00)"
t, err := Parse(data)
if err != nil {
panic(err)
}
fmt.Println(t)
Try it on the Go Playground.
Important note!
Although logically analyzing your input time string:
Mon, 5 Oct 2015 00:24:08 +0800 (GMT+08:00)
The last part "(GMT+08:00)" does not denote the zone abbreviation (GMT is not +0800 but +0000)! It is just a helper text to the reader explaining that the +0800 is a zone offset to be added to the GMT timezone, so most likely it will always be GMT but not because the time is specified in the GMT timezone but because it explains that the zone offset means an offset to be added to the GMT time. And as such, it is not part of the time specification and should not be parsed.
So instead cut off all the last part and parse it like this:
func Parse(s string) (time.Time, error) {
if len(s) < 12 {
return time.Time{}, errors.New("Too short!")
}
s = s[:len(s)-12]
layout := "Mon, 2 Jan 2006 15:04:05 -0700"
return time.Parse(layout, s)
}
Also note that if this is really the case (that it is not the zone abbreviation but it will always be "GMT"), you can parse the input string without truncating it by changing your layout to include the static text "GMT" instead of the zone abbreviation specifier "MST":
layout := "Mon, 2 Jan 2006 15:04:05 -0700 (GMT-07:00)"
data := "Mon, 5 Oct 2015 00:24:08 +0800 (GMT+08:00)"
t, err := time.Parse(layout, data)
Having a space between MST and - solves the panic.
layout := "Mon, _2 Jan 2006 15:04:05 -0700 (MST -07:00)"
data := "Mon, 5 Oct 2015 00:24:08 +0800 (GMT +08:00)"
This works, however it does not really solve your problem.
Why not trimming the redundant timezone part? You already have +0800 defined.
layout := "Mon, _2 Jan 2006 15:04:05 -0700"
data := "Mon, 5 Oct 2015 00:24:08 +0800"

Resources