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
[Proposal] Add DateTime.addYears, DateTime.addMonths, DateTime.addDays, ... #27245
Comments
I think that should be fixed with an You can already use the format There is a semantic problem with adding months and years in that "a month" and "a year" isn't a specific amount of time. Years vary by one day, months by up to three days. Adding "one month" to the 30th of January is ambiguous. We can do it, we just have to pick some arbitrary day between the 27th of February and the 2nd of March. That's why we haven't added month and year to An (We had a CL to add the |
In a subscription management system, recurring billing is the core. After charges of a period are collected, a task is scheduled to run next month, next quarter, next six months, next year, and so on. Without This is how C# handles leap years and the number of days in a month
|
I guess there is a reason many subscriptions work in increments of 30 days, not "months" :) The C# choice is not a bad one. It's one choice and it may or may not be the right choice for any particular use case. |
My company specializes in subscription commerce, so I can confirm that subscriptions are charged mostly on a monthly or yearly basis rather than every 30 days. For example, if you sign up for a monthly charged subscription on Jan 1, you'll get charged again on Feb 1, Mar 1, and so on. From Jan 1 to Feb 1 is 31 days and from Feb 1 to Mar 1 is 28 or 29 days, but those periods are all considered as one month. Below is my implementation of const _daysInMonth = const [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
bool isLeapYear(int value) =>
value % 400 == 0 || (value % 4 == 0 && value % 100 != 0);
int daysInMonth(int year, int month) {
var result = _daysInMonth[month];
if (month == 2 && isLeapYear(year)) result++;
return result;
}
DateTime addMonths(DateTime dt, int value) {
var r = value % 12;
var q = (value - r) ~/ 12;
var newYear = dt.year + q;
var newMonth = dt.month + r;
if (newMonth > 12) {
newYear++;
newMonth -= 12;
}
var newDay = min(dt.day, daysInMonth(newYear, newMonth));
if (dt.isUtc) {
return new DateTime.utc(
newYear,
newMonth,
newDay,
dt.hour,
dt.minute,
dt.second,
dt.millisecond,
dt.microsecond);
} else {
return new DateTime(
newYear,
newMonth,
newDay,
dt.hour,
dt.minute,
dt.second,
dt.millisecond,
dt.microsecond);
}
} |
I'm not saying this is the way to do it, but moment.js calculates an average: https://github.com/moment/moment/blob/b8a297c1f99b3918f44dd9e3d7bd59379a876ba6/moment.js#L3997 in dart this is something like:
|
An internal Flutter customer (customer: fast) had an issue with their shipping app last week due to using |
@jolleekin @eseidelGoogle I would be happy to contribute to a 3rd party package. Maybe that's the first step to getting native SDK support. |
Our plan is to work on improving the libraries in Q2. This issue is on our list. |
I have found that if you just add or subtract delta dart will do the rest |
Not if the date is January 31. When you add a month like you suggested, you end up with March 03 (or 02):
|
@lrhn in my view dateTime calculations should not average anything, DateTime should be aware of the yearly calendars, and be able to accurately calculate for instance a year ago as being the same day of the same month, but a year ago. and to return the difference between now and 7 years ago in days, for instance, take into account leap years, and month sizes appropriately. |
I agree that date calculations should be calendar aware, but taking leap years and month sizes into account doesn't define a unique answer for all computations. You have to say how they are handled exactly. I can absolutely guarantee that no matter which algorithm you pick, you cannot guarantee that We can definitely make some choices (I already have some ideas). We can't add it to |
And locale aware. Where you can also run into issues because we don't have a Date, just a DateTime. And it may or may not be important to a particular usage that November 4 at midnight does not exist if you're in Brazil so the best you can do is 1:00am. |
I am in trouble, not having this date&time methods. All about creating apps with flutter goes away. I need to rewrite the code from RN (momentjs) to flutter, and I was thinking that dart has all this (kind of)libs available. Now I am glad that I have some buttons, lists and images... |
Could you follow up on this please |
These operations were scheduled for Dart 2.0, but didn't make the final cut. My best guess at when something will happen is that if/when we get static extension methods, someone (perhaps even myself) will write a library which extends |
Sorry to ask again, is there any update on this issue? |
Ran into this myself. Needed clean simple way to add a month to a DateTime. |
3 years. |
There is an open issue on the Flutter repo about porting functionalities from moment.js. If DateTime changes for a future release are being discussed here maybe the analysis did by the other issuer might help. The issue in question is: flutter/flutter#31523 |
Well, the extension methods are coming "soon", so adding functionality from the outside will be an option. |
There is now a package that adds these types of extensions: https://github.com/jogboms/time.dart |
To be clear the |
This can now be done in a non-breaking way using extension methods. I'd still prefer if we had interface default methods. It seems unnecessarily complicated to have extensions on a type declared in the same library as the type. |
The best syntax for this behavior would be So we need a new name, with the same meaning as Assume we have such a name, the implementation would then be: extension DateTimeExtensions on DateTime {
/// Adds time units to the calendar date and/or clock time.
///
/// Creates a new [DateTime] object with a calendar date offset from
/// that of the the current oneby the provided number of years, months, and/or days,
/// and a wall clock time offset from that of the current one by the provided
/// hours, minutes, seconds, milliseconds and/or microseconds.
///
/// The provided time units can be positive or negative, or any combination.
/// Overflowing, say by adding more than 30 days to a any date, works like
/// in the [DateTime] constructor.
/// The resulting day and time must be withing the supported range for
/// the `DateTime` class.
///
/// The new `DateTime` object is an UTC time if [isUtc] is `true` ,
/// and it is local-time if [isUtc] is `false`.
/// If [isUtc] is not provided, the created `DateTime` object uses the same
/// UTC/local-time choice as the original.
DateTime shift({int years = 0, int months = 0, int days = 0,
int hours = 0, int minutes = 0, int seconds = 0, int milliseconds = 0, int microseconds = 0,
bool? isUtc}) =>
((isUtc ?? this.isUtc) ? DateTime.utc : DateTime.new)(
year + years,
month + months,
day + days,
hour + hours,
minute + minutes,
second + seconds,
millisecond + milliseconds,
microsecond + microseconds,
);
} That looks very much like |
And now my package due_date creates this functionality of "addMonths" in a more specific way depending on what you mean as a month (or whatever time period you want). |
Problem
It is really inconvenient to work with Dart's
DateTime
because it misses some important methods for date-time manipulation. Some good examples areDateTime
DateTime
DateTime
DateTime
DateTime
from anotherDuration
is more cumbersome thanint
ornum
Proposal
Given the limitations above, I propose adding the following methods to Dart's
DateTime
DateTime addDays(num value)
DateTime addHours(num value)
DateTime addMilliseconds(num value)
DateTime addMinutes(num value)
DateTime addMonths(int value)
DateTime addSeconds(num value)
DateTime addTicks(int value)
DateTime addYears(int value)
Duration subtractAnother(DateTime other)
Reference
C#'s DateTime has the following methods
AddDays(Double)
AddHours(Double)
AddMilliseconds(Double)
AddMinutes(Double)
AddMonths(Int32)
AddSeconds(Double)
AddTicks(Int64)
AddYears(Int32)
Subtract(DateTime)
The text was updated successfully, but these errors were encountered: