Getting error while parsing timestamp string - go

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

Related

Timezone parsing from date in string gives empty string

I want to parse a date (having timezone) represented by a string into Time.
I tried the below code:
package main
import (
"fmt"
"time"
)
func main() {
dateString := "Sat Jan 02 15:04:05 -0700 2021"
dateTime, _ := time.Parse("Mon Jan 02 15:04:05 -0700 2006", dateString)
zoneName, _ := dateTime.Zone()
fmt.Println("Zone Name is "+ zoneName)
loc, _ := time.LoadLocation(zoneName)
fmt.Println(loc)
}
On running the code I am getting the zoneName as empty string which eventually transforms into UTC whereas I should be getting a valid time zone? What mistake have I done to parse the date?

parse string returns month out of range error

I am going to parse ps -eo pid,lstart,cmd output to get process start time
the shell output date format is like this:
Mon Dec 17 16:20:07 2018
here is my code,
package main
import (
"fmt"
"time"
)
func main () {
myDateString := "Mon Dec 17 16:20:07 2018"
myDate, err := time.Parse("Mon Jan 02 15:04:05 2016", myDateString)
if err != nil {
fmt.Println(err)
}
fmt.Println(myDate)
}
go out
parsing time "Mon Dec 17 16:20:07 2018": month out of range
0001-01-01 00:00:00 +0000 UTC
is there any wrong in my usage?
It should be
myDate, err := time.Parse("Mon Jan 02 15:04:05 2006", myDateString)
instead of
myDate, err := time.Parse("Mon Jan 02 15:04:05 2016", myDateString)

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))
}

PST to UTC parsing of time in Golang

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

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