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

Leap year and last day of month #29

Closed
gwenn opened this issue Mar 21, 2015 · 4 comments
Closed

Leap year and last day of month #29

gwenn opened this issue Mar 21, 2015 · 4 comments

Comments

@gwenn
Copy link

gwenn commented Mar 21, 2015

Would you mind adding something like:

fn is_leap_year(year: i32) -> bool {
    return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)
}

fn last_day_of_month(year: i32, month: u32) -> u32 {
    match month {
        1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
        4 | 6 | 9 | 11 => 30,
        2 => if is_leap_year(year) { 29 } else { 28 },
        _ => panic!("invalid month: {}" , month),
    }
}

?
Thanks.

@lifthrasiir
Copy link
Contributor

While Chrono is inherently tied to the proleptic Gregorian calendar, I don't think such specific functions are not a good fit for general purpose library. If you only care about the correct answer (and not the performance), the following can be used:

fn is_leap_year(year: i32) -> bool {
    NaiveDate::from_ymd_opt(year, 2, 29).is_some()
}

fn last_day_of_month(year: i32, month: 32) -> u32 {
    NaiveDate::from_ymd_opt(year, month + 1, 1).unwrap_or(NaiveDate::from_ymd(year + 1, 1, 1)).pred().day()
}

I think JodaTime does have methods like is_leap, but mostly for supporting different calendar systems with varying leap definitions.

@westy92
Copy link

westy92 commented Apr 16, 2023

You can add this functionality for your project with:

trait NaiveDateExt {
    fn days_in_month(&self) -> i32;
    fn days_in_year(&self) -> i32;
    fn is_leap_year(&self) -> bool;
}

impl NaiveDateExt for chrono::NaiveDate {
    fn days_in_month(&self) -> i32 {
        let month = self.month();
        match month {
            1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
            4 | 6 | 9 | 11 => 30,
            2 => if self.is_leap_year() { 29 } else { 28 },
            _ => panic!("Invalid month: {}" , month),
        }
    }

    fn days_in_year(&self) -> i32 {
        if self.is_leap_year() { 366 } else { 365 }
    }

    fn is_leap_year(&self) -> bool {
        let year = self.year();
        return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)
    }
}

@sshine
Copy link

sshine commented Sep 5, 2023

such specific functions are not a good fit for general purpose library

I apologize for necroposting, but could you explain why?

A safe variation of the last_day_of_month() posted earlier,

pub fn last_of_month(year: i32, month: u32) -> Option<chrono::NaiveDate> {
    chrono::NaiveDate::from_ymd_opt(year, month + 1, 1)
        .or_else(|| chrono::NaiveDate::from_ymd_opt(year + 1, 1, 1))?
        .pred_opt()
}

@pitdicker
Copy link
Collaborator

I have seen this request more than once, and I also think it is reasonable and useful to add.

#1247 includes NaiveDate::leap_year, and #69 is the open issue for adding something like last_day_of_month(). I used the same workaround as you in a number of cases.

I am not sure yet about the best API for something like last_day_of_month(). In one case (the NaiveDate::diff_months_days() method in #1247) it was not enough for me to know the number of days in the current month, it needed the number in the previous month. #69 (comment) suggests adding a type such as YearMonth and implementing the method on that would be more flexible, and #203 also requests such a type.

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

5 participants