Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

time zones not working correctly #158

Open
fzipp opened this issue Sep 26, 2023 · 7 comments
Open

time zones not working correctly #158

fzipp opened this issue Sep 26, 2023 · 7 comments

Comments

@fzipp
Copy link
Contributor

fzipp commented Sep 26, 2023

I start Ivy and enter:

)timezone 
	CEST 0

CEST is correct for my location, but offset 0 isn't. CEST is UTC+2, so the offset should be 7200.

Now I switch the time zone:

)timezone "CET"
	CET 7200

CET is expected, but offset 7200 isn't. CET is UTC+1, so the offset should be 3600.

Now I want to switch back to the original time zone:

)timezone "CEST"
	no such time zone: no such time zone

Even though Ivy told me this zone name at the beginning, so it should be known.

@robpike
Copy link
Owner

robpike commented Sep 27, 2023

There's a lot going on here, and some of it is caused by the peculiarities of the timezone database. I presume you're using Unix in some form, because otherwise I believe none of this will work.

One thing to understand (it's really subtle, and I am still missing some nuance; read on) is how time.Location works in Go. They are not time zones per se, they are locations in which time can be determined. Have a look:

% ivy
)timezone
AEST 36000

)timezone "EST"

)timezone
EST -14400

)timezone "EDT"

)timezone
EDT -14400

First, note that my timezone, AEST, prints correctly. That's a property of the system, somehow, and for the life of me I can't figure out where it comes from.

Second, note that it knows about EST and EDT but both print with the same offset, which is actually the current offset to UTC at the location in which EST is a valid time zone, e.g. New York. You can see this happening a bit in the test suite, which asks the time at the Unix epoch. The test has the wrong offset for that date, and will break when the US goes back to standard time. I should probably have commented that, and will return to it then.

Third, I can't explain why you see zero for CEST, but on my machine CEST is not a known zone so I can't get ivy into that state. I can do this though:

% ivy
)timezone "GMT"

)timezone
GMT 3600

)timezone "UTC"

)timezone
UTC 0

)timezone "Europe/Paris"

)timezone
Europe/Paris 7200

Try that and see what you get. You could also try setting the TZ environment variable and explore what happens then.

Despite this explanation, I do believe there are bugs, I just don't know how to deal with the inconsistencies in the timezone database and its interaction with what the local system says.

@fzipp
Copy link
Contributor Author

fzipp commented Sep 27, 2023

I'm using macOS. If you have a macOS machine you should be able to my reproduce my behavior:

System Settings -> General -> Date & Time

  • Uncheck "Set time zone automatically using your current location"
  • Set "Closest city" to "Berlin - Germany"

Now the time zone should be "Central European Summer Time" (until Oct 29).


In the following experiments I'll use this short Go program for comparison with Ivy:

package main

import (
	"fmt"
	"time"
)

func main() {
	fmt.Println(time.Now().Zone())
}

First experiment, with my system settings (location "Berlin - Germany"):

% go run main.go
CEST 7200
% ivy -e ")timezone"
CEST 0

Here, the Go program prints what I expected, because CEST is UTC+2.

In the next experiment, the time zone database doesn't seem to know about CEST and falls back to UTC if I specify TZ=CEST:

% TZ=CEST go run main.go
UTC 0
% TZ=CEST ivy -e ")timezone"
UTC 0

In the next experiment both interpret TZ=CET as a location (which I'm not a fan of, but perhaps I'll have to accept it) and switch to CEST:

% TZ=CET go run main.go    
CEST 7200
% TZ=CET ivy -e ")timezone"
CEST 0

The output of the short Go program is the consistent one.

Next experiment with TZ=GMT:

% TZ=GMT go run main.go
GMT 0
% TZ=GMT ivy -e ")timezone"
GMT 3600

In my understanding GMT is defined as UTC+0 and should always have the offset 0. However, Ivy interprets it as location "Europe/London", which is currently on British Summer Time (BST, UTC+1) rather than GMT.

@robpike
Copy link
Owner

robpike commented Sep 27, 2023

Thanks for the good report.

I know what's wrong with GMT - I have it mapped to Europe/London instead of UTC - and that's trivial to fix.

The others require more investigation.

@fzipp
Copy link
Contributor Author

fzipp commented Sep 27, 2023

The following is my understanding when looking at this table: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List

  • The TZ database maps from the column "TZ identifier" (I would have called it "Location") to the current "Time zone abbreviation" along with its "UTC Offset".

  • Some "Time zone abbreviations" (such as "CET") also live a double life as "TZ identifiers" in the TZ database, which is unfortunate in my opinion.

  • There is no general lookup mechanism from a "Time zone abbreviation" string to its corresponding "UTC Offset", at least not in Go's time package. Such a lookup is required to map "CEST" to its corresponding offset. However, Ivy attempts to perform this lookup via time.LoadLocation (which is not the right lookup mechanism for this direction) and fails, ultimately defaulting to 0.

@fzipp
Copy link
Contributor Author

fzipp commented Sep 27, 2023

There is no general lookup mechanism from a "Time zone abbreviation" string to its corresponding "UTC Offset", at least not in Go's time package.

Since this lookup direction doesn't exist in the public API, I wondered if Go manages to parse "2023-09-27 18:00:00 CEST" correctly. So I ran the following program:


import (
	"fmt"
	"log"
	"time"
)

func main() {
	t, err := time.Parse("2006-01-02 15:04:05 MST", "2023-09-27 18:00:00 CEST")
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(t)
}

The output

2023-09-27 18:00:00 +0200 CEST

is correct. Then I changed my location from "Berlin - Germany" to "New York, NY - United States" in the macOS system settings, and now the output is wrong!

2023-09-27 18:00:00 +0000 CEST

I find it surprising that Go's time parsing, when provided with an explicit time zone, is dependent on the location setting.

@robpike
Copy link
Owner

robpike commented Sep 27, 2023

Yes, you've put your finger on something that's at the heart of this. I plan to investigate with the Go team.

robpike added a commit that referenced this issue Oct 2, 2023
In config.TimeZoneAt, if an error occurs it silently set the time zone to UTC.
This is a bad idea. Instead, give an error and change nothing.

There is more to do here but let's get this cleared up now.

Update #158
robpike added a commit that referenced this issue Oct 2, 2023
Turn it into location management, that is, track locations rather than
time zones. The code is more robust now, and this fixes the output
for the zero of Unix time in New York. However, there is still some
thinking to do about time zones vs. locations in the UI. More may
come, such as changing the special command to ")location".

Update #158
@robpike
Copy link
Owner

robpike commented Oct 3, 2023

golang/go#63345

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants