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.
Output: