Convert timestamp and timezone into RFC3339 format - go

I am taking timestamp from the user like this
2015-05-28T17:00:00
And a timezone "America/Los_Angeles"
Now I want convert the date into something like
2015-05-28T17:00:00-07:00
Is that possible in go ,Please help me out in this ,if you have any links which you can share

You can use ParseInLocation to parse datetime in specific location.
package main
import (
"fmt"
"time"
)
func main() {
loc, err := time.LoadLocation("America/Los_Angeles")
if err != nil {
panic(err)
}
// Note: without explicit zone, returns time in given location.
const shortForm = "2015-05-28T17:00:00"
t, err := time.ParseInLocation("2006-01-02T15:04:05", shortForm, loc)
if err != nil {
panic(err)
}
fmt.Println(t)
}
Its output is:
2015-05-28 17:00:00 -0700 PDT

"timezone" translates to time.Location in go. To load a location by name:
loc, err := time.LoadLocation("America/Los_Angeles")
Parsing:
to interpret the string as "that timestamp in that location":
t, err := time.ParseInLocation("2006-01-02T15:04:05", input, loc)
to interpret the string as "that timestamp in UTC":
t, err := time.Parse("2006-01-02T15:04:05", input)
Formatting:
to format t according to RFC3339 :
fmt.Println(t.Format(time.RFC3339))
t carries its own time.Location, you can also translate that timestamp to the timezone you see fit:
fmt.Println(t.In(loc).Format(time.RFC3339))
fmt.Println(t.UTC().Format(time.RFC3339))
https://go.dev/play/p/g2BgfdYGxU_I

Related

Parsing a UTC ISO8601 time format in Golang

I'm being sent a date in the following format:
2021-05-09T12:10:00+01:00
Which is apparently a valid date format: https://en.wikipedia.org/wiki/ISO_8601
I'm attempting to parse that date in Go:
pt, err := time.Parse("2006-01-02T15:04:05+00:00", dt)
I've also tried to use time.RFC3339
But neither seem to pick up the timezone. In this case I get:
2021/05/10 21:02:02 http: panic serving [::1]:62125: parsing time "2021-05-09T12:10:00 01:00" as "2006-01-02T15:04:05+00:00": cannot parse " 01:00" as "+00:00"
The problem is your layout parameter,
"2006-01-02T15:04:05+00:00"
Instead of +00:00 you should have -07:00
This should help,
package main
import (
"fmt"
"time"
)
func main() {
date := "2021-05-09T12:10:00+01:00"
layout := "2006-01-02T15:04:05-07:00"
t, err := time.Parse(layout, date)
if err != nil {
fmt.Println(err)
}
fmt.Println(t)
}
Output: 2021-05-09 12:10:00 +0100 +0100
Playground: https://play.golang.org/p/UcrIDfJRcNV
Don't get confused as to why the timezone is showing up twice.
It's explained in this answer,
Golang time - time zone showing twice
The special layout parameter only accepts a certain set of valid numbers.
You can refer them here,
https://yourbasic.org/golang/format-parse-string-time-date-example/
You need to relay the timezone via the number -7:00 (not +1:00):
// pt, err := time.Parse("2006-01-02T15:04:05+1:00", dt) // not this
pt, err := time.Parse("2006-01-02T15:04:05-07:00", dt) // this
https://play.golang.org/p/n697vKUHSjD

Incorrect time-conversion in Go

I am trying to convert the time string "2020-02-01T12:30:00+01:00" (from the google calendar API) to time.Time format in Go, for some reason it keeps giving me "2020-01-01 12:30:00 +0000 UTC" as output (which is first of January, instead of first of February). Any idea what I'm doing wrong?
Thanks in advance!
package main
import (
"fmt"
"time"
"log"
)
func main() {
input := "2020-02-01T12:30:00+01:00"
output, err := StrToTime(input)
if err != nil{
log.Fatal(err)
}
fmt.Println(output)
}
func StrToTime(strDateTime string) (time.Time, error) {
layout := "2006-01-02T15:04:05+01:00"
t, err := time.Parse(layout, strDateTime)
if err != nil {
return time.Time{}, fmt.Errorf("could not parse datetime: %v", err)
}
return t, nil
}
It happens because you've specified the time offset portion wrong, it should be -07:00 not +01:00.
As of now it treats 01 as month portion, the second time, and overwrites the originally correctly parsed 02 as 01 (but not from the time offset part of the input).

How to convert a date with timezone to Javascript ISO format?

I am trying to convert this date string ("2018-10-29T11:48:09.180022-04:00") to ISO format in Go. But not able to do. Can anyone help?
package main
import (
"fmt"
"time"
)
func main() {
l,_ := time.Parse("2006-01-02T15:04:05Z07:00", "2018-10-29T15:18:20-04:00")
fmt.Println(l, time.Now(), time.Now().UTC().Format("2006-01-02T15:04:05Z07:00"))
}
Output:
2018-10-29 15:18:20 -0400 -0400 2009-11-10 23:00:00 +0000 UTC m=+0.000000001 2009-11-10T23:00:00Z
https://play.golang.org/p/gXw39_Y-hpR
Note that your input string is valid ISO 8601 format.
However, for JSON serialization, JavaScript uses a slightly different (but still completely valid) style of ISO 8601 date format in which only 3 digits are used for fractional seconds (giving millisecond resolution) and the timezone is adjusted to Coordinated Universal Time (UTC), (aka GMT+0, or "Zulu" timezone) designated with a Z.
// JavaScript
JSON.stringify(new Date()); // => "2018-10-30T15:22:30.293Z"
// Millisecond resolution ─────────────────────────────┺┻┛┃
// "Zulu" (UTC) time zone ────────────────────────────────┚
You can convert your timestamp into the JavaScript style by first parsing the input string, then converting to Zulu time via the UTC() method, then formatting with the desired output format.
For example (Go Playground):
const (
INPUT_FORMAT = "2006-01-02T15:04:05.999999999-07:00"
OUTPUT_FORMAT = "2006-01-02T15:04:05.000Z"
)
func timestampToJavaScriptISO(s string) (string, error) {
t, err := time.Parse(INPUT_FORMAT, s)
if err != nil {
return "", err
}
return t.UTC().Format(OUTPUT_FORMAT), nil
}
func main() {
s := "2018-10-29T11:48:09.180022-04:00"
s2, err := timestampToJavaScriptISO(s)
if err != nil {
panic(err)
}
fmt.Println(s2)
// 2018-10-29T15:48:09.180Z
}
you can just convert it by using the RFC3339 format:
unitTimeInRFC3339 :=time.Now().Format(time.RFC3339)

Hour out of range on time.parse in golang

I am trying to parse a date time string in go. I pass the exact string as the format and get and error parsing time "01/31/2000 12:59 AM": hour out of range.
I am getting that string from an input. How can I make this work?
Here is the code (https://play.golang.org/p/Kg9KfFpU2z)
func main() {
layout := "01/31/2000 12:59 AM"
if t, err := time.Parse(layout, "01/31/2000 12:59 AM"); err == nil {
fmt.Println("Time decoded:", t)
} else {
fmt.Println("Failed to decode time:", err)
}
}
Based on your shared code, you should change the layout to 01/02/2006 03:04 AM to fix it:
Note:
If you have 24 hours format, you should change the hour part in layout to 15 instead of 03 and also to get rid of AM part e.g. 01/02/2006 15:04
package main
import (
"fmt"
"time"
)
func main() {
layout := "01/02/2006 03:04 AM"
if t, err := time.Parse(layout, "01/31/2000 12:59 AM"); err == nil {
fmt.Println("Time decoded:", t)
} else {
fmt.Println("Failed to decode time:", err)
}
}
Here is a good article that would help you to understand different layouts.
Your format needs to use a very specific date and time, see the docs:
https://golang.org/pkg/time/#example_Parse
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
So you need https://play.golang.org/p/c_Xc_R2OHb

TimeZone to Offset?

I want to get the offset in seconds from a specified time zone. That is exactly what tz_offset() in Perl's Time::Zone does: "determines the offset from GMT in seconds of a specified timezone".
Is there already a way of doing this in Go? The input is a string that has the time zone name and that's it, but I know that Go has LoadLocation() in the time package, so string => offset or location => offset should be fine.
Input: "MST"
Output: -25200
This should do the trick:
location, err := time.LoadLocation("MST")
if err != nil {
panic(err)
}
tzName, tzOffset := time.Now().In(location).Zone()
fmt.Printf("name: [%v]\toffset: [%v]\n", tzName, tzOffset)
Will print:
name: [MST] offset: [-25200]
Go Playground: https://play.golang.org/p/GVTgnpe1mB1
Here is the code, that calculates current offset between local and specified timezones. I agree with Ainar-G's comment that offset makes sense only with relation to specified moment in time:
package main
import (
"fmt"
"time"
)
func main() {
loc, err := time.LoadLocation("MST")
if err != nil {
fmt.Println(err)
}
now := time.Now()
_, destOffset := now.In(loc).Zone()
_, localOffset := now.Zone()
fmt.Println("Offset:", destOffset-localOffset)
}

Resources