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

Converting from NaiveDate to DateTime<Tz> is currently hard #948

Closed
Ekleog opened this issue Jan 27, 2023 · 1 comment
Closed

Converting from NaiveDate to DateTime<Tz> is currently hard #948

Ekleog opened this issue Jan 27, 2023 · 1 comment

Comments

@Ekleog
Copy link
Contributor

Ekleog commented Jan 27, 2023

This issue is for documentation, and would be fixed by #883.

It is currently hard to convert from NaiveDate to DateTime, due to timezone shifts possibly occurring. The following code seems reasonable:

fn midnight_on(date: chrono::NaiveDate, tz: chrono_tz::Tz) -> chrono::DateTime<chrono_tz::Tz> {
    let datetime = date.and_hms_opt(0, 0, 0).unwrap();
    datetime.and_local_timezone(tz).unwrap()
}

but fails when passed for instance:

fn main() {
    let date = chrono::NaiveDate::from_ymd_opt(2064, 11, 2).unwrap();
    let tz = chrono_tz::Tz::America__Havana;
    println!("{:?}", midnight_on(date, tz));
}

with the error

thread 'main' panicked at 'Ambiguous local time, ranging from 2064-11-02T00:00:00CDT to 2064-11-02T00:00:00CST', /home/ekleog/.cargo/registry/src/github.com-1ecc6299db9ec823/chrono-0.4.23/src/offset/mod.rs:189:17

Waiting until #883 makes it in, the best bet I currently found as a workaround is to extract the implementation from there:

pub fn midnight_on<Tz>(date: chrono::NaiveDate, tz: &Tz) -> chrono::DateTime<Tz>
where
    Tz: Clone + std::fmt::Debug + chrono::TimeZone,
{
    let base = chrono::NaiveTime::MIN;
    for multiple in 0..=24 {
        let start_time = base + chrono::Duration::minutes(multiple * 15);
        match date.and_time(start_time).and_local_timezone(tz.clone()) {
            chrono::LocalResult::None => continue,
            chrono::LocalResult::Single(dt) => return dt,
            chrono::LocalResult::Ambiguous(dt1, dt2) => {
                if dt1.naive_utc() < dt2.naive_utc() {
                    return dt1;
                } else {
                    return dt2;
                }
            }
        }
    }

    panic!(
        "Unable to calculate start time for date {} and time zone {:?}",
        date, tz
    )
}
This was referenced Jan 27, 2023
@pitdicker
Copy link
Collaborator

In my opinion the problem is that we have no way to resolve a local time that falls inside a timezone transition gap (with LocalResult::None as result) to something useful. Fixing this requires a breaking change to LocalResult.

#716 is the issue to track that.

@pitdicker pitdicker closed this as not planned Won't fix, can't repro, duplicate, stale Sep 27, 2023
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