time: Implement function returning the local UTC offset
As was previously possible in time 0.1 and as requested by multiple people in #197, I would like to add a function allowing the user to obtain their local UTC offset. This information would necessarily come from the operating system.
I do not have sufficient experience with C, let alone interaction with system APIs, so I am requesting this be implemented by those that know better than myself. libc and winapi should suffice as conditional dependencies to cover Linux, MacOS, and Windows. Support for Redox would be nice, but is not essential.
When implementing, the following signature should be used.
impl UtcOffset {
fn local() -> Self;
}
I can put together docs and tests; it’s the implementation itself where assistance is needed. The relevant file is src/utc_offset.rs. Replacing #![forbid(unsafe)] with #![deny(unsafe)] and #[allow]ing the relevant bits is, of course, allowed in this situation.
If you’re interested, please leave a comment!
About this issue
- Original URL
- State: closed
- Created 4 years ago
- Reactions: 1
- Comments: 48 (23 by maintainers)
Commits related to this issue
- Implement `UtcOffset::loca()` for windows. See time-rs/time#203. — committed to hroi/time by hroi 4 years ago
- Implement `UtcOffset::local()` for windows. See time-rs/time#203. — committed to hroi/time by hroi 4 years ago
- Implement `UtcOffset::local_offset_at()` for windows. See time-rs/time#203. — committed to hroi/time by hroi 4 years ago
@hroi Off chance you could write a snippet using that API ^^?
This is what I now have for Unix:
I’m also providing the following helper function for anyone that just wants the current offset.
Some issues I see with this approach:
On Unix, local time offset depends on the UTC time you want to convert from (to account for DST). That’s why
localtimeandlocaltime_rhave atimerargument. BTWtimezonedoesn’t account for DST.Example showing this
In PDT this yields:
Solution: change the signature to
but see below.
localtimeandlocaltime_rcan fail withEOVERFLOW.time 0.1panics in this case: https://github.com/time-rs/time/blob/6d96f0c7dbf9c430e10d90e41d9bea52be4d685d/src/sys.rs#L434, but IMO this is a hidden attack vector.Solution: return a
Result:or
localtimeisn’t thread-safe.localtime_ris, but isn’t required to update new timezone info from system. See chronotope/chrono#272.Solution: use
localtime_rinstead oflocaltime, and calltzset()before each call tolocaltime_r.localtimeandlocaltime_r: https://pubs.opengroup.org/onlinepubs/9699919799/functions/localtime.html@jhpratt Thanks for the info. In that case I think I will change my own code to not expose DST info. This way I can at least start upgrading to time 0.2. Thanks!
@YorickPeterse That functionality has not been added. It likely will be eventually, but the edge cases are plentiful.
The simplest way to check this now is likely to use
UtcOffset::local_offset_at(OffsetDateTime::unix_epoch())andUtcOffset::local_offset_at(OffsetDateTime::unix_epoch() + 180.days()), which will obtain the “standard” and “summer” offsets. Note that either can be larger, as the southern hemisphere has DST in January, not July. You could then checkUtcOffset::current_local_offset()and compare that to see which one it is.This will likely work for a majority of cases. However, the dates for DST change on occasion (see: EU likely dropping it next year), and some countries like Morocco have even intricate rules revolving around Ramadan. To work around that, short of having full tzdb support, you’d need yet another syscall to probe a date such that one of them is guaranteed to not be Ramadan.
I’m fairly certain there are even crazier cases than this, so at least for now, it’ll stay out of the time crate.
I wrote one with libc and is POSIX compatible. Feel free to use it in any way. Note
tm_gmtoffis an extension and doesn’t seem to exist on Solaris.EDIT: minor code fix
You can see how it behaves with DST and changing timezone:
Code
(NB: everything after Y2038 will be
UtcOffset::UTCon 32bit system since you don’t want to returnErr.)On windows.
Return values, currently (Jan 2020):