Recurring for month and week in Flutter - flutter

I am trying to create a feature where I can transfer money by scheduling, so for that, I need a recurring option for the month and weak, And the problem that I face is, that if a user chooses the 31st of a month every month doesn't have the 31st, so the transaction should happen in that particular month's end date.
for example: If I start recurring date is 31st May 2022
no of transactions: 3
Current Output: Dates of transactions => 1st July 2022, 31st July 2022, 31st August 2022,
Correct Output: 30th June 2022, 31st July 2022, 31st August 2022,

Maybe something like I proposed here:
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;
}
}
}
This proposition is based on this code that I created a PR for:
extension DateTimeLastFirstDay on DateTime {
/// Returns the Monday of this week
DateTime get firstDayOfWeek =>
isUtc ? DateTime.utc(year, month, day + 1 - weekday) : DateTime(year, month, day + 1 - weekday);
/// Returns the Sunday of this week
DateTime get lastDayOfWeek =>
isUtc ? DateTime.utc(year, month, day + 7 - weekday) : DateTime(year, month, day + 7 - weekday);
/// Returns the first day of this month
DateTime get firstDayOfMonth => isUtc ? DateTime.utc(year, month, 1) : DateTime(year, month, 1);
/// Returns the last day of this month (considers leap years)
DateTime get lastDayOfMonth => isUtc ? DateTime.utc(year, month + 1, 0) : DateTime(year, month + 1, 0);
/// Returns the first day of this year
DateTime get firstDayOfYear => isUtc ? DateTime.utc(year, 1, 1) : DateTime(year, 1, 1);
/// Returns the last day of this year
DateTime get lastDayOfYear => isUtc ? DateTime.utc(year, 12, 31) : DateTime(year, 12, 31);
}
Using the time package you could create a similar code for weeks.

Related

Flutter check last day in the month (List of datetime)

I have a List of different DateTime where for each month of the year there are from 7-15 days with an interval of a couple of days. For example: 01.07, 04.07, 09.07, 14.07, 20.07..., 04.08, 10.08 Question: How do I check if the date is the last for the given month? For example, the date 23.07 may be the last date for the month number 07. Thanks
I need to get a function to check. As input I get a DateTime which is augmented by a Bloc, so I need a check function.
Just add one to the date, and see if it's in the next month:
void main(List<String> arguments) {
for (final w
in '2022-01-01 2022-01-30 2022-01-31' ' 2022-02-01 2022-02-28 2024-02-28'
.split(' ')) {
// print(w);
final wd = DateTime.parse(w);
final isLastDay = isLastDayOfMonth(wd);
print('$w is last day of month? $isLastDay');
}
}
bool isLastDayOfMonth(DateTime when) {
return DateTime(when.year, when.month, when.day + 1).day == 1;
}
### output:
2022-01-01 is last day of month? false
2022-01-30 is last day of month? false
2022-01-31 is last day of month? true
2022-02-01 is last day of month? false
2022-02-28 is last day of month? true
2024-02-28 is last day of month? false
I would filter for the month, sort the list and take the first entry:
void main() {
List<DateTime> list = [DateTime(2000,06,23), DateTime(2000,06,21),DateTime(2000,06,22)];
list = list.where((date) => (date.month == 6)).toList();
list.sort((a,b) => b.day.compareTo(a.day));
print(list[0]);
}

Find the day before today's date and after today's date

I have created a financial app and I want the app to show the financial month to the user. The financial months represents usually the day when the user gets the salary or the biggest income. That day could be the first of the month, the last day of the month, or simply the 15th every month.
This value is configurable in the settings.
I tried to run two methods that are called in my ViewModel, getFirstDayOfMonth and getLastDayOfMonth
To understand better the context, here are some examples, we will take as a reference today's date. 9th September 2020. The Input value is the value I read from settings, which the user can select from, is a number from 1 to 31 inclusive.
Examples: Input: 5 Output: 5th September 2020 at 00:00 for start and 4th October 2020 at 23:59:59 for end
================
Input: 31 Output: 31th August 2020 00:00 for start and 30 September 2020 at 23:59:59
The catch is that if the month does not have that day, it will get the closest one on the left, for example, if 31 is selected as the first day and the month has 30 days, 30 will be calculated as the first day, and also for the end date, if 31 is selected and we are in february and it has only 28 days, 28 it will be selected.
Until now I have this code but I feel it can be improved, also it's not working as expected.
fun getFirstDayOfMonth(date: LocalDateTime): Long {
var tempDate = date
val firstDayOfMonth = lastDay?.filter { it.isDigit() }!!.toInt()
if (firstDayOfMonth < tempDate.dayOfMonth) {
tempDate = tempDate.withDayOfMonth(firstDayOfMonth)
} else if (firstDayOfMonth > tempDate.dayOfMonth) {
tempDate = tempDate.minusMonths(1)
if (tempDate.monthValue == 12) {
//I don't know why minusMonths does not work in the same way as plusMonths, when I write .plusMonths(1) it also change the year if I am in december, with minusMonths if I am in January it does not change the year to minus one year.
tempDate = tempDate.minusYears(1)
}
if (firstDayOfMonth > tempDate.with(TemporalAdjusters.lastDayOfMonth()).dayOfMonth) {
tempDate.withDayOfMonth(tempDate.with(TemporalAdjusters.lastDayOfMonth()).dayOfMonth)
} else {
tempDate = tempDate.withDayOfMonth(firstDayOfMonth)
}
}
return tempDate.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()
}
fun getLastDayOfMonth(date: LocalDateTime): Long {
var tempDate = date
val firstDayOfMonth = lastDay?.filter { it.isDigit() }!!.toInt()
if (firstDayOfMonth > tempDate.dayOfMonth && firstDayOfMonth <= tempDate.with(
TemporalAdjusters.lastDayOfMonth()
).dayOfMonth
) {
tempDate = tempDate.withDayOfMonth(firstDayOfMonth).minusDays(1)
} else {
tempDate = tempDate.plusMonths(1)
if (firstDayOfMonth > tempDate.with(TemporalAdjusters.lastDayOfMonth()).dayOfMonth) {
tempDate.withDayOfMonth(tempDate.with(TemporalAdjusters.lastDayOfMonth()).dayOfMonth)
} else {
tempDate = tempDate.withDayOfMonth(firstDayOfMonth).minusDays(1)
}
}
return tempDate.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli()
}
As an example, I wrote a test that runs today date and only changes the month from January to December. Here is the output of the current algorithm.
1st of the month is the date selected by the user which also defaults in the app.
Todays date 09.01.2020
Running for month January
Running for 1 st of the month
01.01.2020
31.01.2020
===========================================
Todays date 09.02.2020
Running for month February
Running for 1 st of the month
01.02.2020
29.02.2020
===========================================
Todays date 09.03.2020
Running for month March
Running for 1 st of the month
01.03.2020
31.03.2020
===========================================
Todays date 09.04.2020
Running for month April
Running for 1 st of the month
01.04.2020
30.04.2020
===========================================
Todays date 09.05.2020
Running for month May
Running for 1 st of the month
01.05.2020
31.05.2020
===========================================
Todays date 09.06.2020
Running for month June
Running for 1 st of the month
01.06.2020
30.06.2020
===========================================
Todays date 09.07.2020
Running for month July
Running for 1 st of the month
01.07.2020
31.07.2020
===========================================
Todays date 09.08.2020
Running for month August
Running for 1 st of the month
01.08.2020
31.08.2020
===========================================
Todays date 09.09.2020
Running for month September
Running for 1 st of the month
01.09.2020
30.09.2020
===========================================
Todays date 09.10.2020
Running for month October
Running for 1 st of the month
01.10.2020
31.10.2020
===========================================
Todays date 09.11.2020
Running for month November
Running for 1 st of the month
01.11.2020
30.11.2020
===========================================
Todays date 09.12.2020
Running for month December
Running for 1 st of the month
01.12.2020
31.12.2021
===========================================
Process finished with exit code 0
Also for 31 selected
Todays date 09.01.2020
Running for month January
Running for 31 th of the month
31.12.2019
30.01.2020
===========================================
Todays date 09.02.2020
Running for month February
Running for 31 th of the month
31.01.2020
30.03.2020
===========================================
Todays date 09.03.2020
Running for month March
Running for 31 th of the month
09.02.2020
30.03.2020
===========================================
Todays date 09.04.2020
Running for month April
Running for 31 th of the month
31.03.2020
30.05.2020
===========================================
Todays date 09.05.2020
Running for month May
Running for 31 th of the month
09.04.2020
30.05.2020
===========================================
Todays date 09.06.2020
Running for month June
Running for 31 th of the month
31.05.2020
30.07.2020
===========================================
Todays date 09.07.2020
Running for month July
Running for 31 th of the month
09.06.2020
30.07.2020
===========================================
Todays date 09.08.2020
Running for month August
Running for 31 th of the month
31.07.2020
30.08.2020
===========================================
Todays date 09.09.2020
Running for month September
Running for 31 th of the month
31.08.2020
30.10.2020
===========================================
Todays date 09.10.2020
Running for month October
Running for 31 th of the month
09.09.2020
30.10.2020
===========================================
Todays date 09.11.2020
Running for month November
Running for 31 th of the month
31.10.2020
30.12.2021
===========================================
Todays date 09.12.2020
Running for month December
Running for 31 th of the month
09.11.2020
30.12.2021
===========================================
Process finished with exit code 0
There are some mistakes in your calculations which you will be able to catch quite easily once you have understood the solution given below. I have put enough comments in the code which will help you understand it quickly.
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.YearMonth;
import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
public class Main {
public static void main(String[] args) {
// Test for 31
int startDay = 31;
System.out.println(Instant.ofEpochMilli(getFirstDayOfMonth(startDay, YearMonth.of(2020, Month.SEPTEMBER))));
System.out.println(Instant.ofEpochMilli(getLastDayOfMonth(startDay, YearMonth.of(2020, Month.SEPTEMBER))));
System.out.println(Instant.ofEpochMilli(getFirstDayOfMonth(startDay, YearMonth.of(2020, Month.FEBRUARY))));
System.out.println(Instant.ofEpochMilli(getLastDayOfMonth(startDay, YearMonth.of(2020, Month.FEBRUARY))));
// Test for 30
startDay = 30;
System.out.println();
System.out.println(Instant.ofEpochMilli(getFirstDayOfMonth(startDay, YearMonth.of(2020, Month.SEPTEMBER))));
System.out.println(Instant.ofEpochMilli(getLastDayOfMonth(startDay, YearMonth.of(2020, Month.SEPTEMBER))));
System.out.println(Instant.ofEpochMilli(getFirstDayOfMonth(startDay, YearMonth.of(2020, Month.FEBRUARY))));
System.out.println(Instant.ofEpochMilli(getLastDayOfMonth(startDay, YearMonth.of(2020, Month.FEBRUARY))));
// Test for 28
startDay = 28;
System.out.println();
System.out.println(Instant.ofEpochMilli(getFirstDayOfMonth(startDay, YearMonth.of(2020, Month.SEPTEMBER))));
System.out.println(Instant.ofEpochMilli(getLastDayOfMonth(startDay, YearMonth.of(2020, Month.SEPTEMBER))));
System.out.println(Instant.ofEpochMilli(getFirstDayOfMonth(startDay, YearMonth.of(2020, Month.FEBRUARY))));
System.out.println(Instant.ofEpochMilli(getLastDayOfMonth(startDay, YearMonth.of(2020, Month.FEBRUARY))));
}
static long getFirstDayOfMonth(int startDay, YearMonth ym) {
// Get last day of the month
int lastDayOfTheMonth = ym.getMonth().length(ym.isLeapYear());
// Start of the day and on the first day of the month
LocalDateTime ldt = LocalDate.of(ym.getYear(), ym.getMonth(), 1)
.atStartOfDay();
if (startDay > lastDayOfTheMonth) {
ldt = ldt.minusMonths(1) // Go back to the last month
.with(TemporalAdjusters.lastDayOfMonth()); // Adjust to the last day of the obtained month
}
return ldt.toInstant(ZoneOffset.UTC).toEpochMilli();
}
static long getLastDayOfMonth(int startDay, YearMonth ym) {
return Instant.ofEpochMilli(getFirstDayOfMonth(startDay, ym))// Get the point to start with
.plus(ym.getMonth().length(ym.isLeapYear()), ChronoUnit.DAYS)// Add the no. of days of the given month
.atOffset(ZoneOffset.UTC)// Get OffsetDateTime in order to get LocalDate
.toLocalDate()// Convert to LocalDate
.atTime(LocalTime.of(23, 59, 59))// At 23:59:59
.toInstant(ZoneOffset.UTC)// Convert to Instant
.toEpochMilli();
}
}
Output:
2020-08-31T00:00:00Z
2020-09-30T23:59:59Z
2020-01-31T00:00:00Z
2020-02-29T23:59:59Z
2020-09-01T00:00:00Z
2020-10-01T23:59:59Z
2020-01-31T00:00:00Z
2020-02-29T23:59:59Z
2020-09-01T00:00:00Z
2020-10-01T23:59:59Z
2020-02-01T00:00:00Z
2020-03-01T23:59:59Z
It seems that this LocalDateTime class has all the bells and whistles that you need built-in. Check the minusDays and plusDays methods.

Countif date includes year, month or day

I have a column containing dates in a Google sheet. How can I count the number of dates that include a specific year, month or day?
I have tried the following: =COUNTIF(G:G, YEAR(2000)) which just returns a zero, although there are multiple dates in the year 2000 in that column.
All the best!
year:
=INDEX(COUNTIF(YEAR(G:G), 2000))
month:
=INDEX(COUNTIF(MONTH(G:G), 11))
=INDEX(COUNTIFS(MONTH(G:G), 12, G:G, "<>"))
day:
=INDEX(COUNTIF(DAY(G:G), 27))
weekday:
=INDEX(COUNTIF(WEEKDAY(G:G, 1), 7))

Get the current week number in month from Date

I am currently facing a weird issue. I am trying to find out in which week of a month a given Date instance lies.
My code is the following:
var calendar : Calendar {
var calendar = Calendar(identifier: .iso8601)
calendar.timeZone = .UTC
return calendar
}
func generateDate(year: Int, month: Int, day: Int) -> Date {
let dateComponents = DateComponents(year: year, month: month, day: day)
return calendar.date(from: dateComponents)!
}
print(calendar.component(.weekOfMonth, from: Date.generateDate(year: 2019, month: 12, day: 1))) // prints "0"
print(calendar.component(.weekOfMonth, from: Date.generateDate(year: 2020, month: 1, day: 1))) // prints "1"
generateDate simply generates a Date with the help of calendar. When I print the both statements I get 0 and 1 as the result. In my opinion this is wrong. I would assume I get the same value for both since both dates should be in the first week of their respective month value.
Another example would be the 2. Dec 2019, this should give the second week as well as the 6. January 2020 should also give me the second week.
Does anyone know what could be wrong here or where my mistake could be ?
This is due to the 1st day of the month falling on a sunday, try march 01, 2020 if you want confirmation.
The first week of the month is chosen by Swift according to their own standards as ISO standards do not suggest any specific implementations so the Swift team went with this. You can ask them in their forums what their reasoning behind this is Wikipedia link
The logic for .weekOfMonth seems to be that if the "first" week is less than half a week, that is 3 days, then it is considered to be week 0 and otherwise week 1. But note that this is dependent on what locale is being used, for a country like Canada that has Sunday as first day of week there is never a week 0 when running the below code. So when the first day of week is Monday .weekOfMonth will return a value between 0 and 5 but when it is Sunday the range is 1 to 6.
This can be seen running the following code in a playground
let calendar = Calendar.current
let year = 2019
print("First day of week: \(calendar.weekdaySymbols[calendar.firstWeekday - 1])")
for month in 1...12 {
print(calendar.monthSymbols[month - 1])
let first = calendar.date(from: DateComponents(year: year, month: month, day: 1))!
if let range = calendar.range(of: .day, in: .month, for: first) {
var currentWeek = -1
for day in range {
let date = calendar.date(from: DateComponents(year: year, month: month, day: day))!
let week = calendar.component(.weekOfMonth, from: date)
if week > currentWeek {
currentWeek = week
let dayOfWeek = calendar.component(.weekday, from: date)
print("Week# \(week), weekday \(calendar.weekdaySymbols[dayOfWeek - 1])")
}
}
}
}
It seems to me if you want whatever day it is on the 1st to be the first day of weekOfMonth = 1 then you need to write your own code for this

getting Date months/ rest of days difference

is there a way to get these information from two dates:
calculate month between dates ( month for me is a complete month)
calculate rest of days between dates
here is my example:
start date:
01/01/2014
end date:
21/02/2014
i need a resualt like this : months:1 days:20
onother example:
start date:
15/01/2014
end date:
10/03/2014
i need a resualt like this : months:1 days:25
Using Java8 Date/Time API you may do it like so,
LocalDate startDate = LocalDate.of(2014, 1, 1);
LocalDate endDate = LocalDate.of(2014, 2, 21);
Period period = startDate.until(endDate);
System.out.println("months: " + period.getMonths() + " days: " + period.getDays());