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

Setting the time zone via the TZ variable has no effect #118

Open
teythoon opened this issue Sep 7, 2023 · 7 comments
Open

Setting the time zone via the TZ variable has no effect #118

teythoon opened this issue Sep 7, 2023 · 7 comments

Comments

@teythoon
Copy link

teythoon commented Sep 7, 2023

On POSIX systems, the timezone can be overridden on a per-process basis by setting the TZ environment variable:

Unfortunately, this has no effect on this crate.

@astraw
Copy link
Member

astraw commented Sep 8, 2023

What platform are you on? How do you test this? On my PC:

andrew@pc iana-time-zone % cargo build --example get_timezone        
   Compiling iana-time-zone v0.1.57 (/Users/andrew/Documents/src/iana-time-zone)
    Finished dev [unoptimized + debuginfo] target(s) in 3.16s
andrew@pc iana-time-zone % target/debug/examples/get_timezone  
Europe/Berlin
andrew@pc iana-time-zone % TZ=EDT target/debug/examples/get_timezone 
America/New_York

@teythoon
Copy link
Author

teythoon commented Sep 8, 2023

I'm on Debian/Linux, mostly Bookworm (i.e. current stable):

% target/debug/examples/get_timezone
Europe/Berlin
% TZ=EDT target/debug/examples/get_timezone
Europe/Berlin
% TZ=Africa/Nairobi target/debug/examples/get_timezone
Europe/Berlin
% TZ=:Africa/Nairobi target/debug/examples/get_timezone
Europe/Berlin

@astraw
Copy link
Member

astraw commented Sep 9, 2023

This crate developed organically and had no unifying concept behind handling the TZ environment variable. So thanks for bringing this up. I have now dug into this a bit.

According to the POSIX specification, there are two options for the TZ environment variable. First is :characters, which is handled in an "implementation-defined" manner. Second is a time zone rule literal, which defines the (bidirectional) mapping between Universal Time and the user's local time. We cannot convert a rule literal into an IANA time zone, so it seems there's nothing we can do there and I don't consider it further here. So, let's focus on the "implementation-defined" situation like TZ=:Africa/Nairobi.

It seems glibc, musl, Android, and macOS (at least) all follow a similar convention in which the local IANA time zone can be specified in the TZ environment variable:

In current behavior of this crate is as follows. On some platforms (e.g. macOS) we use a function call to a system library to get the time zone name for us. In the case of macOS, this will handle the TZ environment variable for us (although see below). In the case of linux, we examine the /etc/localtime symlink as our default first step and then try /etc/timezone as a first fallback.

Should we handle the TZ environment variable uniformly across platforms (potentially deviating from platform-standard behavior), or we should handle TZ on a per-platform basis? Or should we keep the status quo?

Other notes:

In testing, I found that in macOS 13.5.1, the function CFTimeZoneCopySystem -- which we use -- handles TZ=Africa/Nairobi (no :) to set the time zone to Nairobi but TZ=:Africa/Nairobi (with :) is ignored. (For the case with no :, this seems in contradiction to POSIX as thus should be a rule literal.) However, /bin/date in macOS handles TZ with and without : to set the time zone. In glibc, the localtime function defined in time.h handles both TZ=:Africa/Nairobi and TZ=Africa/Nairobi to set the time zone to Nairobi. So, setting TZ to the time zone with no : is handled the same by macOS and glibc (although contradictory to POSIX).

Apparently C++20 has added std::chrono::current_zone()->name() which will return the IANA time zone name: https://stackoverflow.com/a/37992725

I have not yet attempted to figure out what Windows does with the TZ environment variable. I did find this https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/tzset?view=msvc-170.

@teythoon
Copy link
Author

I concur with your analysis. Personally, I think this crate should strive for consistency with the platform, so that applications built on top of it behave like "native" applications, i.e. avoid surprising the user.

@lopopolo
Copy link
Collaborator

Hey folks, can y'all help me understand how making this behavior change would not be the same as reintroducing https://rustsec.org/advisories/RUSTSEC-2020-0159.html to the ecosystem?

@astraw
Copy link
Member

astraw commented Sep 20, 2023

@lopopolo I think if we use rust's std to get the environment variable, we should be OK (see time-rs/time#293 (comment)). That said, I'm not an expert in this.

@jscptman
Copy link

I have the same problem, my work environment is Debian:bookworm (both docker image and wsl2), I found set TZ variable has no effect on my code, my code and my test step as follows:

The 'date' command can return the right timezone.

ls -l /etc/localtime; # /etc/localtime -> /usr/share/zoneinfo/Etc/UTC
echo "TZ='Asia/Shanghai';export TZ;" >> ~/.profile;
source ~/.profile;
echo $TZ; # Asia/Shanghai
date; # Sun Nov 24 10:31:17 PM CST 2024

My rust code could not.

use chrono::{Local, TimeZone};
use chrono_tz::Tz;
fn main() {
   let tz = iana_time_zone::get_timezone().unwrap();
   println!("🚀 {:?}", tz); // 🚀 "Etc/UTC"
   let tz = tz.parse::<Tz>().unwrap();
   // let tz = Tz::Asia__Shanghai; // my real TZ
   let dt = tz.from_local_datetime(&Local::now().naive_local()).unwrap();
   println!("{}", dt.format("%a %b %e %r %Z %Y").to_string()); // Sun Nov 24 10:27:33 PM UTC 2024
}

I will subscribe this issue and have a good day.

jscptman added a commit to jscptman/apue that referenced this issue Nov 24, 2024
jscptman added a commit to jscptman/apue that referenced this issue Nov 24, 2024
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

4 participants