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

Supporting normalising dates/times #1416

Open
curiousdannii opened this issue Feb 7, 2024 · 4 comments
Open

Supporting normalising dates/times #1416

curiousdannii opened this issue Feb 7, 2024 · 4 comments

Comments

@curiousdannii
Copy link

I'm porting code which makes use of the normalisation features of C's timegm)

The original values of the tm_wday and tm_yday components of the structure are ignored, and the original values of the other components are not restricted to their normal ranges, and will be normalized if needed. For example, October 40 is changed into November 9, a tm_hour of -1 means 1 hour before midnight, tm_mday of 0 means the day preceding the current month, and tm_mon of -2 means 2 months before January of tm_year. (A positive or zero value for tm_isdst causes mktime() to presume initially that summer time (for example, Daylight Saving Time) is or is not in effect for the specified time, respectively. A negative value for tm_isdst causes the mktime() function to attempt to divine whether summer time is in effect for the specified time. The tm_isdst and tm_gmtoff members are forced to zero by timegm(.))

I couldn't see anything in the current Chrono API which looks suitable for this, though it looks like I could manually do it by calling checked_add_months, checked_add_days, etc (though as negative values are possible I'd need to test and call the sub functions too.)

Is there a part of the API that I missed, or does anyone know of another Rust library that can handle this?

@curiousdannii
Copy link
Author

curiousdannii commented Feb 7, 2024

Okay, here's what I ended up with. It's not the worst, but a helper function would still be appreciated:

    let mut normalised_date = NaiveDate::from_ymd_opt(year, 1, 1).unwrap();
    let months = month - 1;
    if months > 0 {
        normalised_date = normalised_date.checked_add_months(chrono::Months::new(months as u32)).unwrap();
    }
    if months < 0 {
        normalised_date = normalised_date.checked_sub_months(chrono::Months::new(months as u32)).unwrap();
    }
    let mut normalised_date = NaiveDateTime::from(normalised_date);
    let duration = Duration::days(day as i64 - 1)
        + Duration::hours(hour as i64)
        + Duration::minutes(minute as i64)
        + Duration::seconds(second as i64)
        + Duration::nanoseconds(microsec as i64 * 1000);
    normalised_date = normalised_date.checked_add_signed(duration).unwrap();

@djc
Copy link
Contributor

djc commented Feb 7, 2024

Other than trying to come up with an exact match for time_gm()'s semantics, what is your code trying to achieve? What is the use case? I'd like to avoid the XY problem here.

@curiousdannii
Copy link
Author

curiousdannii commented Feb 7, 2024

I'm porting a library from C to Rust which basically wraps timegm. I have to normalise the dates or I don't pass the unit tests. Rejecting invalid dates like the _opt functions probably does make more sense, but the API isn't up to me.

That said, my code seems to be working, so if you want you can just close this feature request.

Using libc's wrapper of timegm would be another option (albeit it's an unsafe function.)

@djc
Copy link
Contributor

djc commented Feb 10, 2024

It sounds like #1290 might address your use case?

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