[Feature Request] add months in NumTimeExtension
alfinbi opened this issue ยท 17 comments
please add months in NumTimeExtension
I think we can use clampDayOfMonth method from package:quiver/time.dart and implement it as extension
yeah I was just thinking about it, its hard to implement in duration extension, but I think it can be implemented in DateTime extension, for instance,
final now = DateTime.now();
final expiryDate = now.addMonths(3);
final anotherDate = now.substractYears(1);
it will be useful for backend to calculate paid user expiry date. just like I have been done.
Got swamped with daily work. Thinking about this, considering what @shinriyo already said, 1.month
is a bit meaningless as it it be either 28, 29, 30 or 31 which can in no way be determined automagically. I would rather this task be left on the developer level. I may be wrong.
It would be possible to create a new class for Month() and then allow addition for DateTime + Month.
It ties in to overloading the +
operator as you suggested earlier. In my head, I didn't want to introduce new types.
DateTime(2013, 1) + 6.months
-> DateTime(2013, 1) + Month(6)
Where Month
can stay as a hidden detail
Hi guys I have a proposal and a test case. Let's take the example of generating sales reports, for example, you need to iterate through months then weeks (4 in a month) then weekdays (can be 28,29, etc). I propose to introduce two enums (or more if you have other cases in mind) and their associated extensions:
main() {
final dates = [
DateTime(2020, 01, 31),
DateTime(2020, 01, 31),
DateTime(2020, 01, 31),
DateTime(2020, 01, 31),
DateTime(2020, 01, 31),
DateTime(2020, 01, 31),
DateTime(2020, 03, 15)
];
final now = DateTime.now();
for (var month in Month.values) {
final sales = salesForMonth(dates, month.forYear(now.year));
print("$sales sales in month ${month.toStr()}");
print("details : ");
for (var week in [1, 2, 3, 4]) {
for (var weekDay in WeekDay.values) {
final sales =
salesForWeekDay(dates, weekDay.forMonth(month.forYear(now.year)));
print(
"$sales sales in week $week of month ${month.toStr()} day ${weekDay.toStr()}");
}
}
}
}
int salesForWeekDay(List<DateTime> dates, DateTime day) =>
(List<DateTime>.from(dates)..retainWhere((d) => d.sameWeekDay(day))).length;
int salesForMonth(List<DateTime> dates, DateTime month) =>
(List<DateTime>.from(dates)..retainWhere((d) => d.sameMonth(month))).length;
extension DateHelpers on DateTime {
bool sameYear(DateTime other) {
return other.year == this.year;
}
bool sameMonth(DateTime other) {
return sameYear(other) && other.month == this.month;
}
bool sameWeekDay(DateTime other) {
return sameMonth(other) && other.weekday == this.weekday;
}
}
enum Month {
january,
february,
march,
april,
may,
july,
august,
september,
october,
november,
december,
}
extension MonthValue on Month {
DateTime forYear(int year) {
final y = DateTime(year);
final month = DateTime(
y.year,
<Month, int>{
Month.january: DateTime.january,
Month.february: DateTime.february,
Month.march: DateTime.march,
Month.april: DateTime.april,
Month.may: DateTime.may,
Month.july: DateTime.july,
Month.august: DateTime.august,
Month.september: DateTime.september,
Month.october: DateTime.october,
Month.november: DateTime.november,
Month.december: DateTime.december,
}[this]);
return month;
}
String toStr() => <Month, String>{
Month.january: "january",
Month.february: "february",
Month.march: "march",
Month.april: "april",
Month.may: "may",
Month.july: "july",
Month.august: "august",
Month.september: "september",
Month.october: "october",
Month.november: "november",
Month.december: "december",
}[this];
}
enum WeekDay {
monday,
tuesday,
wednesday,
thursday,
friday,
saturday,
sunday,
}
extension DayValue on WeekDay {
DateTime forMonth(DateTime month) {
final day = DateTime(
month.year,
month.month,
<WeekDay, int>{
WeekDay.monday: DateTime.monday,
WeekDay.tuesday: DateTime.tuesday,
WeekDay.wednesday: DateTime.wednesday,
WeekDay.thursday: DateTime.thursday,
WeekDay.friday: DateTime.friday,
WeekDay.saturday: DateTime.saturday,
WeekDay.sunday: DateTime.sunday,
}[this]);
return day;
}
String toStr() => <WeekDay, String>{
WeekDay.monday: "monday",
WeekDay.tuesday: "tuesday",
WeekDay.wednesday: "wednesday",
WeekDay.thursday: "thursday",
WeekDay.friday: "friday",
WeekDay.saturday: "saturday",
WeekDay.sunday: "sunday",
}[this];
}
It should output this result :
6 sales in month january
details :
0 sales in week 1 of month january day monday
0 sales in week 1 of month january day tuesday
6 sales in week 1 of month january day wednesday
....
Some cons here are the toStr() which isn't ideal for translations but work great for debugging. And the naming conventions need some love
Tell me what you think @jogboms and I make the PR.
Would love this to be added please!
add, please.
or marge mine ;>
I would pick this up again this weekend. I believe it aged well.
add, please.
or marge mine ;>
I use yours @shinriyo thank you very much for sharing it!
Hey @sachaarbonel
A lot of time has passed so I don't know if you are still interested on a quick PR. I am available for review. I feel its a new feature compared to this issue as #26 aims to solve this.
With lastDayOfMonth
you could potentially do something like
extension AddMonth on DateTime {
DateTime addMonths([int amount = 1]) {
final plusXMonths = DateTime(year, month + amount, day);
final xMonthsAhead = DateTime(year, month + amount);
if (xMonthsAhead.lastDayOfMonth.compareTo(plusXMonths).isNegative) {
return xMonthsAhead.lastDayOfMonth;
} else {
return plusXMonths;
}
}
}
After some time and thinking, I don't believe this is the best approach anymore. I think this actually could be still confusing.
Considering my PR #53 gets in, if not we could implement it here, maybe something like this instead would be better (maybe a better name but I couldn't think of one):
static DateTime clampMonthLength(int year, int month, int day) {
final firstDay = DateTime(year, month);
return firstDay.copyWith(day: day).clamp(
min: firstDay,
max: firstDay.lastDayOfMonth,
);
}
I also think there could be another method that would return a list of DateTimes with that day clamped to the end of the months, but that one is even harder for me to name and I'm not sure about if it would be a good fit and what it's signature would be.