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)
}
Related
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
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).
RFC-3339 Section 4.3 (https://www.rfc-editor.org/rfc/rfc3339#section-4.3) defines the -00:00 offset as the following, which is different than Z or +00:00.
4.3. Unknown Local Offset Convention
If the time in UTC is known, but the offset to local time is unknown,
this can be represented with an offset of "-00:00". This differs
semantically from an offset of "Z" or "+00:00", which imply that UTC
is the preferred reference point for the specified time. RFC2822
[IMAIL-UPDATE] describes a similar convention for email.
However, I'm not sure how to represent this in Go. When I parse a time with -00:00 and format it, I get a Z offset. For example:
Input: 2018-01-01T00:00:00-00:00
Output: 2018-01-01T00:00:00Z
Here's some example code (https://play.golang.org/p/CVmNnhaSiiT):
package main
import (
"fmt"
"time"
)
func main() {
t := "2018-01-01T00:00:00-00:00"
fmt.Println("Input " + t)
p, err := time.Parse(time.RFC3339, t)
if err != nil {
fmt.Println(err)
} else {
t2 := p.Format(time.RFC3339)
fmt.Println("Output " + t2)
}
}
Package time
import "time"
RFC3339, RFC822, RFC822Z, RFC1123, and RFC1123Z are useful for
formatting; when used with time.Parse they do not accept all the time
formats permitted by the RFCs.
Go does not accept all the time formats permitted by the RFCs.
The Go time.Time type uses integers which, unlike floating-point, have no concept of plus and minus zero. The results for parsing offsets of -00:00 and +00:00 are identical.
For example,
package main
import (
"fmt"
"time"
)
func main() {
var err error
var minus, plus time.Time
t := "2018-01-01T00:00:00-00:00"
minus, err = time.Parse(time.RFC3339, t)
if err != nil {
fmt.Println(err)
}
t = "2018-01-01T00:00:00+00:00"
plus, err = time.Parse(time.RFC3339, t)
if err != nil {
fmt.Println(err)
}
fmt.Println(minus, plus, minus.Equal(plus), minus == plus)
}
Playground: https://play.golang.org/p/Urf8VlKYoMH
Output:
2018-01-01 00:00:00 +0000 UTC 2018-01-01 00:00:00 +0000 UTC true true
PeterSO's answer is perfect IMHO. If you need to act differently based on the information that the offset is unknown, then this might help you.
You can build your own time data type:
type MyTime struct {
// based on time.Time so we can do all normal time.Time stuff
time.Time
offsetUnknown bool
}
func ParseRFC3339(s string) (MyTime, error) {
time, err := time.Parse(time.RFC3339, s)
if err != nil {
return MyTime{}, err
}
return MyTime{
Time: time,
// maybe this condition needs improvement in case of false positives
offsetUnknown: strings.Contains(s, "-00:00"),
}, nil
}
Any functions you need to behave differently based on offsetUnknown you can then override on the MyTime struct. Here one example:
func (s MyTime) Format(layout string) string {
out := s.Time.Format(layout)
// again this is probably not the best solution
if layout == time.RFC3339 && s.offsetUnknown {
out = strings.Replace(out, "+00:00", "-00:00", -1)
}
return out
}
I want to show some RFC3339 time as seconds. I found how to parse times string, but it not that
t, _ := time.Parse(time.RFC3339, "2012-11-01T22:08:41+00:00")
For example,
package main
import (
"fmt"
"time"
)
func main() {
t, err := time.Parse(time.RFC3339, "2012-11-01T22:08:41+00:00")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(t)
// Unix returns t as a Unix time,
// the number of seconds elapsed since January 1, 1970 UTC.
fmt.Println(t.Unix())
}
Playground: https://play.golang.org/p/LG6G4lMIWt
Output:
2012-11-01 22:08:41 +0000 UTC
1351807721
Does anyone know how to check for a file access date and time? The function returns the modified date and time and I need something that compares the accessed date time to the current date and time.
You can use os.Stat to get a FileInfo struct which also contains the last access time (as well as the last modified and the last status change time).
info, err := os.Stat("example.txt")
if err != nil {
// TODO: handle errors (e.g. file not found)
}
// info.Atime_ns now contains the last access time
// (in nanoseconds since the unix epoch)
After that, you can use time.Nanoseconds to get the current time (also in nanoseconds since the unix epoch, January 1, 1970 00:00:00 UTC). To get the duration in nanoseconds, just subtract those two values:
duration := time.Nanoseconds() - info.Atime_ns
By casting os.FileInfo to *syscall.Stat_t:
package main
import ( "fmt"; "log"; "os"; "syscall"; "time" )
func main() {
for _, arg := range os.Args[1:] {
fileinfo, err := os.Stat(arg)
if err != nil {
log.Fatal(err)
}
atime := fileinfo.Sys().(*syscall.Stat_t).Atim
fmt.Println(time.Unix(atime.Sec, atime.Nsec))
}
}
Alternatively, after the Stat you can also do
statinfo.ModTime()
Also you can use Format() on it, should you need it eg for a webserver
see https://gist.github.com/alexisrobert/982674
For windows
syscall.Win32FileAttributeData
info, _ := os.Stat("test.txt")
fileTime := info.Sys().(*syscall.Win32FileAttributeData).LastAccessTime
aTime := time.Unix(0, fileTime.Nanoseconds())
Example
package main
import (
"fmt"
"log"
"os"
"syscall"
"time"
)
func main() {
info, _ := os.Stat("./test.txt")
fileTime := info.Sys().(*syscall.Win32FileAttributeData).LastAccessTime
// _ = info.Sys().(*syscall.Win32FileAttributeData).CreationTime
// _ = info.Sys().(*syscall.Win32FileAttributeData).LastWriteTime
fileAccessTime := time.Unix(0, fileTime.Nanoseconds())
// Compare
// t2, _ := time.Parse("2006/01/02 15:04:05 -07:00:00", "2023/02/08 13:18:00 +08:00:00")
now := time.Now()
log.Println(fileAccessTime)
log.Println(now.Add(-20 * time.Minute))
if fileAccessTime.After(now.Add(-20 * time.Minute)) {
fmt.Println("You accessed this file 20 minutes ago.")
}
}
Linux
see this answer