golang timezone daylight savings time doesn't work - go

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.

Related

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>

Parsing time in Golang

I'm trying to create a Time struct based on some input called dateAdded. My code is like this:
dateAdded := "November 25, 2016"
layout := "September 9, 2016"
t, err := time.Parse(layout, dateAdded)
if err != nil {
fmt.Println(err)
} else {
fmt.Println(t)
}
And I get the following error: parsing time "November 25, 2016" as "September 9, 2016": cannot parse "November 25, 2016" as "September 9, "
I assume the Parse function cannot parse every layout, but I'm curios what's the usual way of reading dates and parse them into time objects.
The layout, if you're not using one of the pre-included constant layout that comes with the time module, must be formed from the exact timestamp Mon Jan 2 15:04:05 -0700 MST 2006. Notice that each element of it is unique, so each numeric identifier can be automatically parsed. it's basically 1 (month), 2 (day), 3 (hour), 4 (minute), 5 (second), 6 (year), 7 (time zone) etc.
It's better to use one of the pre-defined standard layouts that are included with the library:
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"
)
Your layout date is wrong. Should be "January 2, 2006". As the specs say:
The layout defines the format by showing how the reference time,
defined to be Mon Jan 2 15:04:05 -0700 MST 2006 would be interpreted
if it were the value
You should treat it as an example which you provide to time.Provide. And it should be of concrete value described in the documentation.
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
A playground with correct variant.

Go parse string to time

I've got the following string:
Sun, 03 Jan 2016 10:00:07 CET
Id like to parse it into time, but cannot seem to figure out how to write the format.
This is what I've got so far:
layout := "Mon, 01 Jan 03:04:05"
t, _ := time.Parse(layout, "Sun, 03 Jan 2016 10:00:07 CET")
fmt.Println(t)
Output I get is:
0001-01-01 00:00:00 +0000 UTC
First of all: You're silently ignoring the error this is returned as second return value of time.Parse. I'd suggest handling the error appropriately, instead.
Secondly, let's have a look at the documentation of time.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 would be interpreted if it were the value; it serves as an example of the input format. The same interpretation will then be made to the input string.
The time.Parse function expects its layout parameter to represent a fixed example date. So, in order to parse the date Sun, 03 Jan 2016 10:00:07 CET, the appropriate example layout string should be Mon, 02 Jan 2006 15:04:05 MST:
layout := "Mon, 02 Jan 2006 15:04:05 MST"
t, err := time.Parse(layout, "Sun, 03 Jan 2016 10:00:07 CET")
if err != nil {
// handle the error somehow!
}
fmt.Println(t)

How to parse non-standard date / time in Go ? Mitteleuropäische Sommerzeit

I'm trying to parse dates received in email headers. Recently I've got stuck on this one Thu, 7 Aug 2014 14:03:05 +0200 (Mitteleuropäische Sommerzeit). What kind of layout am I supposed to use ? Mon, 02 Jan 2006 15:04:05 -0700 (MST) doesn't do the trick.
I've also tried the workaround below but it still doesn't work. I'm not sure why Mitt... is not being replaced.
if strings.Contains(d, "Mitteleuropäische Sommerzeit") {
d = strings.Replace(d, "Mitteleuropäische Sommerzeit", "CEST", 1)
}
The Mitteleuropäische Sommerzeit part is indeed not recognized by the time package. But it works perfectly when you replace it by CEST:
var d = "Thu, 7 Aug 2014 14:03:05 +0200 (Mitteleuropäische Sommerzeit)"
_, err := time.Parse("Mon, _2 Jan 2006 15:04:05 -0700 (MST)", d)
if err != nil {
fmt.Println(err) // There is indeed an error
}
d = strings.Replace(d, "Mitteleuropäische Sommerzeit", "CEST", 1)
t, err := time.Parse("Mon, _2 Jan 2006 15:04:05 -0700 (MST)", d)
if err != nil {
fmt.Println(err) // No error this time
}
fmt.Println(t) // 2014-08-07 14:03:05 +0200 CEST
On playground.
Do not forget to write _2 instead of 2 in your layout, so that days with two figures can be parsed too.
It is redundant to try and parse the parenthesized timezone name when you already know the correct numeric offset:
Thu, 7 Aug 2014 14:03:05 +0200 (Mitteleuropäische Sommerzeit)
is equally specific as
Thu, 7 Aug 2014 14:03:05 +0200
The only additional information you get out of the first representation is that it was summer when the email was sent and that the region from which the email's author comes from is central Europe (literally "central Europe summertime").
This will not, however, affect the time.Time value's representation in contrast to the second string because the daylight saving adjustment is already reflected in the numerical timezone representation +0200 which would be +0100 during winter.
In other words, in this case you can ignore the spelled-out timezone specification.

What is the purpose of the "Handy time stamps" in the time package?

Reference:
I am trying to figure out what the "Handy Time Stamp" are used for in the time package.
I can parse dates just fine using the other constants such as RFC
t, _ := time.Parse(time.RFC822, "02 Jan 06 15:04 MST")
fmt.Println(t.Unix())
Output 1136214240
vs
t, _ := time.Parse(time.Stamp, "Jan _2 15:04:05")
fmt.Println(t.Unix())
Output: -62135596800
The last output is wrong. What am I missing here? How are these timestamps useful?
Below is the Godoc for 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"
)
The last output is wrong. What am I missing here? How are these timestamps useful?
You are definitely missing an error check here, let's add it
t, err := time.Parse(time.Stamp, "Jan _2 15:04:05")
fmt.Println(err)
fmt.Println(t.Unix())
Output:
parsing time "Jan _2 15:04:05" as "Jan _2 15:04:05": cannot parse "_2
15:04:05" as "_2"
-62135596800
The correct string would be "Jan 2 15:04:05" (note the double space between Jan and 2). About underscore from the docs:
Within the format string, an underscore _ represents a space that may
be replaced by a digit if the following number (a day) has two digits;
for compatibility with fixed-width Unix time formats.
Then, why it's representations as UNIX time is negative, let's check:
t, err := time.Parse(time.Stamp, "Jan 2 15:04:05")
fmt.Println(err)
fmt.Println(t)
Output:
<nil>
0000-01-02 15:04:05 +0000 UTC
So it's negative because the year is 0000.
And finally, where it can be useful? For example, to measure duration of time-consuming operations. You can output to logs current time in one of Stamp formats along with some messages like "Started doing this", "Finished doing that". Then, because it's fixed-width format and without unnecessary year information - it's easy to read the logs, easy to parse such logs.
This format is actually used in "syslog" in *nix.

Resources