This question already has answers here:
What would be a good implementation to get all Monday and Thursday dates Between a given date range (DateX and DateY) in JAVA
(3 answers)
Closed 5 years ago.
Can someone suggest the logic to find out the no. of Mondays between two dates in Java?
Instead of looping through all the days, is there any other approach to count the no. of occurrences of Mondays between two dates in java
There’s more than one way to go. Here’s a suggestion:
public static long noOfMondaysBetween(LocalDate first, LocalDate last) {
if (last.isBefore(first)) {
throw new IllegalArgumentException("first " + first + " was after last " + last);
}
// find first Monday in interval
LocalDate firstMonday = first.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
// similarly find last Monday
LocalDate lastMonday = last.with(TemporalAdjusters.previous(DayOfWeek.MONDAY));
// count
long number = ChronoUnit.WEEKS.between(firstMonday, lastMonday);
// add one to count both first Monday and last Monday in
return number + 1;
}
For example, noOfMondaysBetween(LocalDate.of(2017, Month.JUNE, 15), LocalDate.of(2017, Month.JUNE, 15)) returns 0. It may be a little subtle that the code takes this case into account: First Monday is June 19 and last is June 12. Count of weeks between the two Mondays is -1, so when I add 1, the result is 0, which is correct. To count the Mondays in June:
System.out.println(noOfMondaysBetween(LocalDate.of(2017, Month.MAY, 31), LocalDate.of(2017, Month.JULY, 1)));
Result:
4
If you intended to include the first date in the count (if it is a Monday), use nextOrSame(DayOfWeek.MONDAY) instead of next(DayOfWeek.MONDAY). Similarly to include the second date use previousOrSame(DayOfWeek.MONDAY).
I'm not a Java coder but I'm a coder. Here's how I'd solve this:
Count the days between the two dates (aka DATESPAN). I'm sure Java has a function for that.
Get the 'Day of Week' (AS A NUMBER, assuming that Monday = 1 )of both dates. I'm sure Java has a function for this too. We need to know if either is a Monday.
If DATESPAN < 7 Use this logic:
Answer = End Date Number > DATESPAN ? 0 : 1
IF DATESPAN >=7 CONTINUE TO GET ANSWER:
Divide the DATESPAN by 7.
If there is a remainder from the division, use the floor value of the quotient for the answer.
If there is NO remainder, check the start date and end date. If either are a Monday the quotient is the answer, If not the quotient - 1 is the answer
Related
This question already has answers here:
What would be a good implementation to get all Monday and Thursday dates Between a given date range (DateX and DateY) in JAVA
(3 answers)
Closed 5 years ago.
Can someone suggest the logic to find out the no. of Mondays between two dates in Java?
Instead of looping through all the days, is there any other approach to count the no. of occurrences of Mondays between two dates in java
There’s more than one way to go. Here’s a suggestion:
public static long noOfMondaysBetween(LocalDate first, LocalDate last) {
if (last.isBefore(first)) {
throw new IllegalArgumentException("first " + first + " was after last " + last);
}
// find first Monday in interval
LocalDate firstMonday = first.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
// similarly find last Monday
LocalDate lastMonday = last.with(TemporalAdjusters.previous(DayOfWeek.MONDAY));
// count
long number = ChronoUnit.WEEKS.between(firstMonday, lastMonday);
// add one to count both first Monday and last Monday in
return number + 1;
}
For example, noOfMondaysBetween(LocalDate.of(2017, Month.JUNE, 15), LocalDate.of(2017, Month.JUNE, 15)) returns 0. It may be a little subtle that the code takes this case into account: First Monday is June 19 and last is June 12. Count of weeks between the two Mondays is -1, so when I add 1, the result is 0, which is correct. To count the Mondays in June:
System.out.println(noOfMondaysBetween(LocalDate.of(2017, Month.MAY, 31), LocalDate.of(2017, Month.JULY, 1)));
Result:
4
If you intended to include the first date in the count (if it is a Monday), use nextOrSame(DayOfWeek.MONDAY) instead of next(DayOfWeek.MONDAY). Similarly to include the second date use previousOrSame(DayOfWeek.MONDAY).
I'm not a Java coder but I'm a coder. Here's how I'd solve this:
Count the days between the two dates (aka DATESPAN). I'm sure Java has a function for that.
Get the 'Day of Week' (AS A NUMBER, assuming that Monday = 1 )of both dates. I'm sure Java has a function for this too. We need to know if either is a Monday.
If DATESPAN < 7 Use this logic:
Answer = End Date Number > DATESPAN ? 0 : 1
IF DATESPAN >=7 CONTINUE TO GET ANSWER:
Divide the DATESPAN by 7.
If there is a remainder from the division, use the floor value of the quotient for the answer.
If there is NO remainder, check the start date and end date. If either are a Monday the quotient is the answer, If not the quotient - 1 is the answer
I am creating a workaround to fix the SimpleDateFormat "clone" class of CN1 in my app.
I cannot use other classes from pure Java.
I used this instruction in my CN1 app
int dayNumber=c.get(Calendar.DAY_OF_WEEK);
for handling the u letter in the format string.
At the time of the creation of this post it's Wednesday
dayNumber happens to have value of 4.
So I replaced that instruction with
int dayNumber=c.get(Calendar.DAY_OF_WEEK)-1;
because I found in Oracle documentation
Day number of week (1 = Monday, ..., 7 = Sunday)
I would like to know if it is correct
so that I have the 7 days of the week covered so it is just as
(1 = Monday, ..., 7 = Sunday)
and I can have the right u value for Java and Android compatibility.
I understand that java.time, the modern Java date and time API, is not yet part of CodeName One, and that therefore you cannot use it in your case. Apart from special situations like yours no one should use Calendar since it is poorly designed and long outdated. Everyone should use java.time.
To get (1 = Monday, ..., 7 = Sunday) from Calendar (the numbers that you would get by default from java.time):
int dayNumber = (c.get(Calendar.DAY_OF_WEEK) + 5) % 7 + 1;
Seen under modulo 7 I am first adding 5, then 1, so 6 in total, which is the same as subtracting 1. I am using this trickery to make sure I get a number in the 1 through 7 interval (which we don’t always by simply subtracting 1 from the return value from Calendar).
I am demonstrating the edge cases and using java.time for it:
LocalDate ld = LocalDate.of(2021, Month.SEPTEMBER, 5);
ZonedDateTime startOfDay = ld.atStartOfDay(ZoneId.of("Etc/UTC"));
Calendar c = GregorianCalendar.from(startOfDay);
int dayNumber = (c.get(Calendar.DAY_OF_WEEK) + 5) % 7 + 1;
System.out.format("%s: %s = %d%n", ld, ld.getDayOfWeek(), dayNumber);
ld = ld.plusDays(1);
startOfDay = ld.atStartOfDay(ZoneId.of("Etc/UTC"));
c = GregorianCalendar.from(startOfDay);
dayNumber = (c.get(Calendar.DAY_OF_WEEK) + 5) % 7 + 1;
System.out.format("%s: %s = %d%n", ld, ld.getDayOfWeek(), dayNumber);
Output is:
2021-09-05: SUNDAY = 7
2021-09-06: MONDAY = 1
Disclaimer: I don’t know the CodeName One Calendar in particular. I strongly expect it to behave exactly the same as the original java.util.Calendar, and my answer is based on the assumption that it does.
I'm trying to write code that starts with day 1 (and whatever weekday that happens to be) and print out consecutively. For example, if Friday is 1, it should next print Saturday 2, then continue counting the days as normal but reset the dayOfTheWeek to Sunday.
My current code is:
String[] dayOfTheWeek ={“Sunday”, “Monday”, “Tuesday”, “Wednesday”, “Thursday”, “Friday”, “Saturday”};
int[] days ={31}
for(int days=1; days<32; days=days++){
for(String dayOfTheWeek=5; dayOfTheWeek<7; dayOfTheWeek=dayOfTheWeek++){
System.out.println(dayOfTheWeek" " days)
}
}
It doesn't work at all, and I don't have the experience to know where to start. If someone could point me in the right direction that would be greatly appreciated.
This is a fine exercise. Just for the bigger picture, it’s nothing one would use for production code in real life.
There are basically two ways. Both will work fine.
Use two nested loops. The outer loop will iterate over the months of the year. The inner loop will iterate over the days of the month.
Use one loop over the days of the year.
In both cases you will also need to keep track of the day of the week throughout. Edit again: If you know about enum in Java, use an enum for the months and another enum for the days of the week. If you don’t know enums, as Andreas has already mentioned, use int for each of month, day of month and day of week. Use the ints for looking up the strings in your arrays. Because an int can be incremented and because array indices are ints.
Further edit: To answer the question in your title, assuming that you are using an int index into dayOfTheWeek to represent the next day of the week. There are several ways to increment for each day printed. I find this way natural and simple:
dayOfWeekIdx++;
if (dayOfWeekIdx == dayOfTheWeek.length) { // Overflown
dayOfTheWeek = 0; // Reset
}
Some prefer this much shorter way:
dayOfTheWeek = (dayOfTheWeek + 1) % dayOfTheWeek.length;
The modulo operator, % gives you the remainder after dividing. So when dayOfTheWeek overflows, that is, becomes 7, the division is 7 divided by 7, which is 1 with a remainder of 0, so dayOfTheWeek gets reset to 0.
In the version with one loop over all the days of the years you may do similarly to four-line solution for day of week, only inside the if statement add a line for incrementing the month index.
So what would one use for production code? This is mostly for other readers. One would use LocalDate and also DateTimeFormatter, both from java.time, the modern Java date and time API. No one in their right mind would use Date nor Calendar, the classes that you mentioned in the question, since they are both poorly designed and long outdated.
Start with 3 variables:
int dayOfWeekIdx = 5/*Friday*/;
int monthIdx = 0/*January*/;
int day = 1;
Now print the first date, using the two xxxIdx variables as indexes into the daysOfTheWeek and months arrays.
Increment both dayOfWeekIdx and day. Check them for overflow and reset to 0 as needed.
If day overflowed, increment monthIdx. Exit if it overflowed.
Loop back to print the next date.
I am trying to write a code that starts with day 1 (and whatever
weekday that happens to be) and print out consecutively for example if
Friday is 1, it should next print Saturday 2, the continue counting
the days as normal but reset the dayOfTheWeek to Sunday.
Use the % operator which gives you the value of the remainder. Also, use List<String> instead of String[] to make it easier for you to process the input. List has a rich API to process an input w.r.t. the elements it contains.
import java.util.List;
public class Main {
public static void main(String[] args) {
// Test
printDaysStartingWith("Tuesday");
}
static void printDaysStartingWith(String dayName) {
List<String> dayOfTheWeek = List.of("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
"Saturday");
int index = dayOfTheWeek.indexOf(dayName);
if (index != -1) {
for (int day = index; day < 31; day++) {
System.out.println(dayOfTheWeek.get(day % 7));
}
} else {
System.out.println("Error: Wrong parameter.");
}
}
}
Output:
Tuesday
Wednesday
Thursday
...
...
...
Monday
Tuesday
I'm having a problem comparing the date range. I have to validate dates that are within a certain month and year. The month and year are integer values.
NOTE: I´m using OUTSYSTEMS aggregates using Oracle DataBase
Example for two results of a query:
Start Date End Date
1 2020-08-16 2020-10-14
2 2019-11-01 2020-08-15
Case 1
Input:
Month = 9
Year = 2020
Expected Result:
Start Date End Date
1 2020-08-16 2020-10-14
Case 2
Input:
Month = 8
Year = 2020
Expected Result:
Start Date End Date
1 2020-08-16 2020-10-14
2 2019-11-01 2020-08-15
Case 3
Input:
Month = 3
Year = 2020
Expected Result:
Start Date End Date
2 2019-11-01 2020-08-15
Case 4
Input:
Month = 10
Year = 2019
Expected Result: No Row
The selection is in Java Way. I´m using a system function like Month() and Year() to convert the rows to the integers.
Like this
((Month(StartDate) <= Month and Month(EndDate) = Month)
and
(Year(StartDate) <= Year and Year(EndDate) = Year))
or
((Month(StartDate) <= Month and Month(EndDate) = Month)
and
(Year(StartDate) <= Year and Year(EndDate) = Year))
The code above won't work. I try many combinations without success. I have no special comparison functions. For my analysis, I have four scenarios to create to bring the dates that are included in the month and year that I am researching. But I'm not getting the code to work. Someone can light the way for me
A simple approach uses arithmetics:
where year * 100 + month
between year(startdate) * 100 + month(startdate)
and year(enddate) * 100 + month(enddate)
However this probably isn't the most efficient method. In general, you want to avoid applying functions on the column you filter on. A better alternative woul be to convert the year/month parameter to a date - unfortunately you did not tag your database, and date functions are highly vendor-specific, so it is not really possible to suggest.
If you don't want between:
where year * 100 + month >= year(startdate) * 100 + month(startdate)
and year * 100 + month <= year(enddate) * 100 + month(enddate)
Does this work? Considering your inputs m for month and y for year:
StartDate <= AddDays(AddMonths(NewDate(Year(y), Month(m), 1),1)-1)
and
EndDate >= NewDate(Year(y), Month(m), 1))
The thinking is like: filter by all start dates that are lower than the last day of input month and all the end dates that are greater than the first day of input month.
Regarding performance, with this approach you don't have to do any logic/filter on the columns you're filtering on.
The vendor-independent solution
The answer by GMB is nice, I might go with it if it were me. As GMB says, it is vendor specific because the date functions are. If you want a solution that works across database vendors, do the date math in Java so you only need simple date comparisons in the database.
int month = 8;
int year = 2020;
YearMonth ym = YearMonth.of(year, month);
LocalDate monthStart = ym.atDay(1);
LocalDate monthEnd = ym.atEndOfMonth();
When you pass these dates to your query, your search condition may be put simply:
where startDate <= monthEnd and endDate >= monthStart
I am trying to calculate the difference between two LocalDate objects and the result seems to be off, but not every time.
I am using the Period construct. The below code shows one example which returns the expected result (I got that here) and another one which gives me the "wrong" result. I put that in quotes because I am not sure if that truly is wrong, or if the expected value is wrong. Note however, that if I use the online calculator from calculator.net, that gives me the result I expect.
public void manualTestPeriodBetween() {
//works fine - expected result obtained
LocalDate start = LocalDate.of(2014, 2, 14);
LocalDate end = LocalDate.of(2017, 8, 1);
Period result = Period.between(start, end);
Period expected = Period.of(3, 5, 18);
checkPeriods(expected, result);
//does not work as expected
start = LocalDate.of(2017, 5, 19);
end = LocalDate.of(2019, 7, 13);
result = Period.between(start, end);
expected = Period.of(2, 1, 25);
checkPeriods(expected, result);
}
private void checkPeriods(Period expected, Period result) {
System.out.println("expected Period = " + expected + ", resulting Period = " + result);
if (result.equals(expected)) {
System.out.println("SUCCESS - result Period matches expected");
} else {
System.out.println("FAIL - result Period not matched");
}
}
Output:
expected Period = P3Y5M18D, resulting Period = P3Y5M18D
SUCCESS - result Period matches expected
expected Period = P2Y1M25D, resulting Period = P2Y1M24D
FAIL - result Period not matched
Can someone help me figure out whether I am missing something or the expected result is wrong (both in my code and the online date calculator)? or maybe something else I am not even considering.
Here is a screenshot of the results obtained from the online date calculator:
The online date calculator you have provided may have been implemented incorrectly. From my favorite time resource, timeanddate
From and including: Friday, May 19, 2017
To, but not including Saturday, July 13, 2019
Result: 785 days
It is 785 days from the start date to the end date, but not including the end date.
Or 2 years, 1 month, 24 days excluding the end date.
Or 25 month, 24 days excluding the end date.
This is identical to the response provided by thecalculatorsite.com
I don't have the implementation for your online calculator, but the discrepancy appears to occur because May is a 31-day month.
It looks to be calculating the day-difference before the month difference, using some mathematical assumption for month length.
The Java method uses epochday to calculate the distances between two days in case of underflow, rather than adding an arbitrary value to offset a month.
if (totalMonths > 0 && days < 0) {
totalMonths--;
LocalDate calcDate = this.plusMonths(totalMonths);
days = (int) (end.toEpochDay() - calcDate.toEpochDay()); // safe
} else if (totalMonths < 0 && days > 0) {
totalMonths++;
days -= end.lengthOfMonth();
I mean, it should be 24 days depending on how you do the calculations.
If you add a month to get to june 19th, and june has 30 days- then it's only 24 days between the two dates.
https://www.wolframalpha.com/input/?i=days+between+5%2F19%2F2017+and+7%2F13%2F2019
The website you are checking it against is wrong, I can think of several ways that could happen depending on how they are implementing their date difference functions.