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

Changes to the system time zone are not visible in macOS #145

Open
kathoum opened this issue Jan 3, 2025 · 4 comments
Open

Changes to the system time zone are not visible in macOS #145

kathoum opened this issue Jan 3, 2025 · 4 comments
Labels
Tier-1 Rust Tier-1 platform

Comments

@kathoum
Copy link

kathoum commented Jan 3, 2025

In macOS, if the system time zone changes while the current process is running, get_timezone() returns the previous time zone instead of the current time zone.

Reproduction

Run the following program:

fn main() {
  loop {
    println!("{}", iana_time_zone::get_timezone().unwrap());
    std::thread::sleep(std::time::Duration::from_secs(2));
  }
}

While the program is running, change the system time zone (from the Settings UI or using sudo systemsetup -settimezone).

In MacOS, the programs keeps printing the old time zone.
In Windows and in Linux, the program output reflects the change in system settings.

Proposed fix

diff --git a/src/tz_macos.rs b/src/tz_macos.rs
index 70c39e8..a90aced 100644
--- a/src/tz_macos.rs
+++ b/src/tz_macos.rs
@@ -32,7 +32,9 @@ mod system_time_zone {
     //! create a safe wrapper around `CFTimeZoneRef`
 
     use core_foundation_sys::base::{CFRelease, CFTypeRef};
-    use core_foundation_sys::timezone::{CFTimeZoneCopySystem, CFTimeZoneGetName, CFTimeZoneRef};
+    use core_foundation_sys::timezone::{CFTimeZoneCopySystem, CFTimeZoneGetName, CFTimeZoneRef, CFTimeZoneResetSystem};
 
     pub(crate) struct SystemTimeZone(CFTimeZoneRef);
 
@@ -46,7 +48,10 @@ mod system_time_zone {
     impl SystemTimeZone {
         pub(crate) fn new() -> Option<Self> {
             // SAFETY: No invariants to uphold. We'll release the pointer when we don't need it anymore.
-            let v: CFTimeZoneRef = unsafe { CFTimeZoneCopySystem() };
+            let v: CFTimeZoneRef = unsafe {
+                CFTimeZoneResetSystem();
+                CFTimeZoneCopySystem()
+            };
             if v.is_null() {
                 None
             } else {
@lopopolo
Copy link
Collaborator

lopopolo commented Jan 4, 2025

It seems most idiomatic for iOS and macOS apps to use NSNotificationCenter and listen for NSSystemTimeZoneDidChangeNotification to trigger a call to CFTimeZoneResetSystem.

This crate intentionally only binds to CoreFoundation and it seems inappropriate to automatically set up an event handler in this low level library.

Additionally, it doesn't feel great to intentionally subvert the caching put in place by CoreFoundation.

Can you provide more context on the problem you're trying to solve and why invalidating the cache in some other way is not appropriate? Why do we need to add this logic in iana-time-zone crate?

@lopopolo
Copy link
Collaborator

lopopolo commented Jan 4, 2025

Thanks for raising this bit of nuance! My inclination is to not accept this proposed diff and to instead add some platform specific caveats to the docs for iOS, macOS, and tvOS.

@Kijewski
Copy link
Collaborator

Kijewski commented Jan 4, 2025

Maybe the NSSystemTimeZoneDidChangeNotification listener could be implemented in its own crate that could be pulled in with a feature flag?

It looks like reading an uncached timezone value could be quite time consuming: CFTimeZone.c. (The file mixes tabs and spaces for indentation, which is not displayed properly in github.)

@Kijewski Kijewski added the Tier-1 Rust Tier-1 platform label Jan 4, 2025
@kathoum
Copy link
Author

kathoum commented Jan 4, 2025

I noticed this while debugging a service that checks the current timezone when some event happens; since the caching behaviour is different from the other platforms I tested on, I thought it was not intentional. In my case there are no performance concerns, so I can add a call to CFTimeZoneResetSystem to invalidate the cache just before calling the function.

If caching is expected on Apple platforms, I agree with your proposal to document the platform-specific bits.

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

No branches or pull requests

3 participants