-
-
Notifications
You must be signed in to change notification settings - Fork 281
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
Feature: Offer tz-rs implementation #493
Comments
Chrono is also explicitly ignoring the ability for the If this were implemented, it would require parsing the full tzdb on every invocation to ensure correctness. This would be far too much overhead for what I hope is obvious reasons. I think it's worth keeping in mind that what time is doing is not actually unsound. We're relying on the guarantee that |
Thanks for the detailed response, very insightful. Maybe then the feature could be to provide a lock so it can work on multiple threads like some implementations are doing if the user is aware that they must not use the call outside the lib. I am really just trying to find a solution that is as safe as possible but works on multi-thread too... |
The standard library uses a lock. The problem is that not everything uses a lock, and when they do, it's not the same lock. This is an extremely difficult problem to solve. Don't get me wrong — I appreciate the desire to make things work — but it's something that's been under discussion for a long time. It goes back to a |
Make sense, I guess I will disable the thread count check then. We just had a problem in our latest release on macos aarch64 as it looks like the lib cant count the threads on that platform. So it is definitely an issue for our users. And we dont use setenv so that should be fine. |
Yeah, as long as you can guarantee with absolute certainty that nowhere in your dep tree is mutating the environment, then using |
Considering we were using chrono before that I imagine did call |
Not necessarily. Even when put in a loop, it takes a number of iterations before the reproduction actually triggers the error. Ultimately this is a decision that was made by me. I believe avoiding a segmentation fault is far more important than getting the system's UTC offset. The bug wasn't discovered via an audit, but by a user running into it in a real-world situation. |
For reference, I replaced the usage of the use std::cell::RefCell;
use time::{OffsetDateTime, UtcOffset};
thread_local! {
static TZ_NAME: RefCell<Option<Option<String>>> = Default::default();
}
pub fn current_local_offset() -> Option<UtcOffset> {
let now = OffsetDateTime::now_utc();
local_offset_at(now)
}
pub fn local_offset_at(datetime: OffsetDateTime) -> Option<UtcOffset> {
match get_timezone() {
Some(tz_name) => match tzdb::tz_by_name(&tz_name) {
Some(tz) => match tz.find_local_time_type(datetime.unix_timestamp()) {
Ok(tm) => match UtcOffset::from_whole_seconds(tm.ut_offset()) {
Ok(offset) => Some(offset),
Err(e) => {
log::warn!(
"Failed to convert seconds ({}) to utc offset: {}",
tm.ut_offset(),
e
);
None
}
},
Err(e) => {
log::warn!("Failed to convert unix time to local time: {}", e);
None
}
},
None => {
log::warn!("Unknown timezone: {}", tz_name);
None
}
},
None => None,
}
}
fn get_timezone() -> Option<String> {
// TODO: We should make this unblock / async since it can read from disk
// TODO: We should check the TZ environment variable too
TZ_NAME.with(|cached| {
cached
.borrow_mut()
.get_or_insert_with(|| match iana_time_zone::get_timezone() {
Ok(tz_name) => Some(tz_name),
Err(e) => {
log::error!("Failed to get timezone: {}", e);
None
}
})
.clone()
})
} |
this required a small rework, because it's not possible to obtain completely sound local time offset value in multithreaded environment - time-rs/time#427 - time-rs/time#500 - time-rs/time#493
I do not foresee myself using When I do get around to #193, I likely won't be using |
In case you didnt know, Tzdb crate is based on tz-rs. It is just a statically linked version of the timezone data. As per caching it is an acceptable tradeoff IMO. Did you see the implementation I did? I dont think it would be super complex to generalize to the library, let me know if you need help or want to bounce ideas. |
When I say tzdb, I mean the actual tzdb, as in the raw data. I have no intent of relying on a
Not if you need accurate data. It is more than reasonable that a user expects a value returned to be accurate, even if the value has changed since the last call. Caching data violates this expectation, and the measures necessary to invalidate the cache for every potential way the value could change is far more effort than it's worth. You're free to use the implementation you provided, and I encourage you to do so if it works for your use case. But there are the drawbacks that I've stated, and I don't see the situation changing to the extent that I would be comfortable adding |
Hi!
The current implementation for
local_offset_at
for unix platforms uses the libclocaltime_r
which is problematic due to race conditions withsetenv
and currently can only be used for single threaded applications. Chrono moved to using tz-rs and it would be nice to offer a feature for time that also uses this crate. Happy to participate to an implementation if that is of any interest.Thanks :)
The text was updated successfully, but these errors were encountered: