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

Provide days_in_month() #69

Open
the-kenny opened this issue Apr 14, 2016 · 9 comments
Open

Provide days_in_month() #69

the-kenny opened this issue Apr 14, 2016 · 9 comments

Comments

@the-kenny
Copy link

For some calculations it's useful to get the number of days in the current month.

For example, I want to get the first and last day in a given month in my current project. The former is possible via .with_day(1), but the latter isn't easily possible (or at least I don't see it)

@lifthrasiir
Copy link
Contributor

Duplicate with #29. See my comment for the workaround; .pred() is a key method. I believe this is not a good fit for Chrono, as i) the calendar system is fixed and ii) other similar libraries don't seem to have such features (especially for those where the calendar system is fixed).

@adalinesimonian
Copy link

Don't mean to jump into an old issue here, but I was going to ask the same question.

@lifthrasiir I understand and respect where you're coming from, but I'm not so sure I agree that chrono wouldn't be a good place to have such a function.

First of all, other libraries across other languages do indeed provide such utilities. To list a few ones I know of:

C++ (Boost library):

date dt(y, m, d);
date eom = dt.end_of_month_day();
gregorian_calendar::is_leap_year(y);

C# (built-in):

DateTime.DaysInMonth(y, m);
DateTime.IsLeapYear(y);

Ruby on Rails (built-in):

Time.days_in_month(m, y)
Time.days_in_year(y)

Python (built-in, calendar module):

calendar.monthrange(y, m)
calendar.isleap(y)

Java (built-in):

Calendar.getInstance().getActualMaximum(Calendar.DAY_OF_MONTH);
// No equivalent for isLeapYear(y)

JavaScript (Datejs library):

Date.getDaysInMonth(y, m)
Date.isLeapYear(y)

JavaScript (moment library):

moment('yyyy-mm', 'YYYY-MM').daysInMonth()
moment([y]).isLeapYear()

However, to play devil's advocate, some languages indeed don't provide such a utility, namely Go, Swift, and Objective-C.

I did see the workaround, though you mentioned it may not perform well. I just don't know enough (still absorbing Rust!) to know how "badly" it performs. Is it really that much of a performance/memory issue?

All said, I really think that get_days_in_month(month, year) and is_leap_year(year) would be a good addition. But I have an open mind if you have a better idea. Maybe I could write my first library with only 2 functions? 😜

@quodlibetor
Copy link
Contributor

@lifthrasiir does the fact that chrono is tied to a specific calendar system make this functionality seem too trivial to be worth implementing, or does it seem wrong because it will require too much refactoring if/when it gets pluggable calendar systems?

I can imagine refactoring our Month implementation to a Month enum with a MonthLike trait that implements a variety of utility methods, including those requested here.

(In addition to the libs @vsimonian mentioned, JSR310 and JodaTime implement these methods.)

@lifthrasiir
Copy link
Contributor

@lifthrasiir does the fact that chrono is tied to a specific calendar system make this functionality seem too trivial to be worth implementing, or does it seem wrong because it will require too much refactoring if/when it gets pluggable calendar systems?

Close to the former, but more like the fact that there are plenty of helper methods that will be too trivial or too specific to be included in the generic library, and so far I have avoided them in favor of code samples in the documentation. But that is just my personal preference and this request seems to be more popular than others (e.g. Julian Days).

As you have mentioned, with a specific type like Month (I'm personally for YearMonth though) having utility methods is much more doable because the method can be applied to the correct type. Guess that this general direction will also solve #152 as well.

@quodlibetor
Copy link
Contributor

YearMonth being something like enum YearMonth { Jan(year: i32), ...}? I can see the appeal of that, it would certainly be more correct and more flexible.

On the other hand something like struct YearMonth { year: Year(i32), month: Month } might allow a more fine-grained distribution of methods?

@quodlibetor
Copy link
Contributor

We might be able to experiment with enhanced ergonomic APIs behind an unstable feature. I will say that I recently had to do a large amount of datetime manipulation using the new java 8 "time" APIs and the extensive API surface made for some very surprisingly elegant functions.

@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)
    }
}

@pitdicker
Copy link
Collaborator

I am not sure yet about the best API for something like days_in_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.

@pitdicker
Copy link
Collaborator

Related: #722.

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

6 participants