I have this very old code block from PROD (>7 years) to be debugged. There's one point I couldnt understand.
A section in the code does a calculation of next time a task will run and for tasks who need to run specifically on sunday, monday it uses Calendar.SUNDAY. But there's one statement whose behaviour I cannot interpret even after reading the docs multiple times
Calendar cal = Calendar.getInstance();
cal.set(Calendar.DAY_OF_WEEK, 0);
since the days are numbered from 1-7 (Calendar.SUNDAY to Calendar.SATURDAY) that can be interpreted, but how does zero work here and why there is no exception?
why there is no exception?
It is because you haven't set the lenient mode to false and it is true by default.
Demo:
import java.util.Calendar;
public class Main {
public static void main(String[] args) {
Calendar cal = Calendar.getInstance();
cal.setLenient(false);
cal.set(Calendar.DAY_OF_WEEK, 0);
System.out.println(cal.getTime());
}
}
Output:
Exception in thread "main" java.lang.IllegalArgumentException: DAY_OF_WEEK
The documentation says:
Any out of range values are either normalized in lenient mode or
detected as an invalid value in non-lenient mode
As part of the normalization, the value are rolled over e.g. the following code sets the value equivalent to cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY - 1):
cal.set(Calendar.DAY_OF_WEEK, 0);
Similarly, the following code sets the value equivalent to cal.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY - 2):
cal.set(Calendar.DAY_OF_WEEK, -1);
By trying it out in a "test bench", I found this:
It looks the "calendar set" adjust value/integer when number 1-7 is "overflown".
I can see this pattern:
Day Of Week: 1 2 3 4 5 6 7 | 1 2 3 4 5 6 7 | 1 2 3 4 5 6 7 | ...
Value of calendar: -6 -5 -4 -3 -2 -1 0 | 1 2 3 4 5 6 7 | 8 9 10 11 12 13 14 | ...
Test bench:
public static void main(String[] args) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.DAY_OF_WEEK, -6);
System.out.println("Calendar value -6 returns: " + cal.get(Calendar.DAY_OF_WEEK));
cal.set(Calendar.DAY_OF_WEEK, 0);
System.out.println("Calendar value 0 returns: " + cal.get(Calendar.DAY_OF_WEEK));
cal.set(Calendar.DAY_OF_WEEK, 1);
System.out.println("Calendar value 1 returns: " + cal.get(Calendar.DAY_OF_WEEK));
cal.set(Calendar.DAY_OF_WEEK, 7);
System.out.println("Calendar value 7 returns: " + cal.get(Calendar.DAY_OF_WEEK));
cal.set(Calendar.DAY_OF_WEEK, 8);
System.out.println("Calendar value 8 returns: " + cal.get(Calendar.DAY_OF_WEEK));
cal.set(Calendar.DAY_OF_WEEK, 14);
System.out.println("Calendar value 14 returns: " + cal.get(Calendar.DAY_OF_WEEK));
}
Output:
Calendar value -6 returns: 1
Calendar value 0 returns: 7
Calendar value 1 returns: 1
Calendar value 7 returns: 7
Calendar value 8 returns: 1
Calendar value 14 returns: 7
Output is according to "pattern".
java.time
I recommend that you use java.time, the modern Java date and time API, for your date and time work. For example:
LocalDate ld = LocalDate.now(ZoneId.systemDefault())
.with(DayOfWeek.TUESDAY);
System.out.println(ld);
When I ran this code today, Saturday, June 5, the output was:
2021-06-01
And yes, June 1 was Tuesday. Since we are passing an enum constant to with(), there is really no possibility of passing an out-of-range value. DayOfWeek is an enum holding 7 values for the 7 days of the week. Only trouble we can get ourselves into is by passing null, which will throw a NullPointerException, which I think you wanted.
If we do insist on passing the day of week as a number, that is possible, though. java.time numbers the days of the week from Monday = 1 through Sunday = 7.
LocalDate ld = LocalDate.now(ZoneId.systemDefault())
.with(ChronoField.DAY_OF_WEEK, 2);
So far the output is 2021-06-01 as before. But what if we pass 0?
.with(ChronoField.DAY_OF_WEEK, 0);
Exception in thread "main" java.time.DateTimeException: Invalid value
for DayOfWeek (valid values 1 - 7): 0
Not only do we get the exception you asked for, we are also getting a clear and helpful exception message, IMHO.
How does day of week zero work here?
With Calendar day of week 0 works the same as 7 = Saturday. It seems that at least a lenient old-fashioned GregorianCalendar performs a kind of modulo 7 operation on the day of week to bring it inside the interval 1 through 7. I did not find this documented. GregorianCalendar is probably the concrete subclass of Calendar that you are dealing with. I tried with different numbers that are all equivalent to 7 modulo 7:
int[] dows = { 0, 7, -7, 14, -14, -98 };
for (int dow : dows) {
Calendar cal = new GregorianCalendar(2021, Calendar.JUNE, 2);
Date dateBefore = cal.getTime();
cal.set(Calendar.DAY_OF_WEEK, dow);
System.out.format("%s and day of week %3d yields %s%n", dateBefore, dow, cal.getTime());
}
Output:
Wed Jun 02 00:00:00 CEST 2021 and day of week 0 yields Sat Jun 05 00:00:00 CEST 2021
Wed Jun 02 00:00:00 CEST 2021 and day of week 7 yields Sat Jun 05 00:00:00 CEST 2021
Wed Jun 02 00:00:00 CEST 2021 and day of week -7 yields Sat Jun 05 00:00:00 CEST 2021
Wed Jun 02 00:00:00 CEST 2021 and day of week 14 yields Sat Jun 05 00:00:00 CEST 2021
Wed Jun 02 00:00:00 CEST 2021 and day of week -14 yields Sat Jun 05 00:00:00 CEST 2021
Wed Jun 02 00:00:00 CEST 2021 and day of week -98 yields Sat Jun 05 00:00:00 CEST 2021
Tutorial link
Oracle tutorial: Date Time explaining how to use java.time.
Related
If I give 04-Mar-2019 as 1st day of 1st Quarter, I want start and end dates of all Quarters from 04-Mar-2019 to 03-Mar-2020. How can I do this in Java?
Thanks in advance.
Input - 1st day of 1st Quarter (04-Mar-2019)
Output -
Q1 - 04-Mar-2019 to ....
Q2 -
Q3 -
Q4 - ... to 03-Mar-2020
java.time
LocalDate quarterStart = LocalDate.of(2019, Month.MARCH, 4);
for (int q = 1; q <= 4; q++) {
System.out.println("Q" + q + " begins on " + quarterStart);
quarterStart = quarterStart.plusMonths(3);
System.out.println(" - ends on " + quarterStart.minusDays(1));
}
This loop prints:
Q1 begins on 2019-03-04
- ends on 2019-06-03
Q2 begins on 2019-06-04
- ends on 2019-09-03
Q3 begins on 2019-09-04
- ends on 2019-12-03
Q4 begins on 2019-12-04
- ends on 2020-03-03
For very many purposes you don’t want to make the end dates explicit. Everyone knows that each quarter ends when the next quarter begins. So consider leaving out the second System.out.println call, it’s just redundant.
Be aware that you don’t want a quarter to start on the 29, 30 or 31 of a month, or strange things will happen when you hit a month that doesn’t have that many days.
Link: Oracle tutorial: Date Time explaining how to use java.time.
Yes , did it myself...
import java.util.Calendar;
import java.util.Date;
public class MyClass {
public static void main(String []args){
Date date = new Date();
for (int i = 0; i < 4; i++) {
Calendar startDate = Calendar.getInstance();
startDate.setTime(date);
startDate.add(Calendar.MONTH, (i*3));
Calendar endDate = Calendar.getInstance();
endDate.setTime(startDate.getTime());
endDate.add(Calendar.MONTH, 3);
endDate.add(Calendar.DATE, -1);
System.out.println();
System.out.println("Start Date of Quarter "+ (i+1) + " : " + new Date(startDate.getTime().getTime()));
System.out.println("End Date of Quarter "+ (i+1) + " : "+ new Date(endDate.getTime().getTime()));
System.out.println();
System.out.println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
}
}
}
OUTPUT :
Start Date of Quarter 1 : Thu Aug 08 04:08:33 GMT 2019
End Date of Quarter 1 : Thu Nov 07 04:08:33 GMT 2019
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Start Date of Quarter 2 : Fri Nov 08 04:08:33 GMT 2019
End Date of Quarter 2 : Fri Feb 07 04:08:33 GMT 2020
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Start Date of Quarter 3 : Sat Feb 08 04:08:33 GMT 2020
End Date of Quarter 3 : Thu May 07 04:08:33 GMT 2020
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Start Date of Quarter 4 : Fri May 08 04:08:33 GMT 2020
End Date of Quarter 4 : Fri Aug 07 04:08:33 GMT 2020
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
This code doesnt work as expected in startDate is initialized to 29th or 30th Nov. In this case, it messes up in Q2 due to less no. of days in Feb.
I am working in it. Basically , I need to decide end date of quarter based on start date of next quarter.
What is the difference between Calendar.HOUR and Calendar.HOUR_OF_DAY ?
When to use Calendar.HOUR and Calendar.HOUR_OF_DAY ?
I am confused sometime Calendar.HOUR this works fine and othertime Calendar.HOUR_OF_DAY this works fine. What they return in the form of int?
I have read this documentation but not understood the difference.
Any suggestions
Thanks.
From http://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html#HOUR:
Calendar.HOUR = Field number for get and set indicating the hour of the morning or afternoon. HOUR is used for the 12-hour clock. E.g., at 10:04:15.250 PM the HOUR is 10.
Calendar.HOUR_OF_DAY = Field number for get and set indicating the hour of the day. HOUR_OF_DAY is used for the 24-hour clock. E.g., at 10:04:15.250 PM the HOUR_OF_DAY is 22.
This code will help you understand better
import java.util.Calendar; import java.util.GregorianCalendar;
public class test{ public static void main(String[] args) {
GregorianCalendar gc = new GregorianCalendar(2013, 8, 15, 21, 69,55);
//minutes = 69 is equal to 1 hour and 09 minutes. This hour will add to Hour place (21+1 = 22)//Sun Sep 15 22:09:55 IST 2013
p(gc, Calendar.YEAR); //gives year
p(gc, Calendar.MONTH); // gives month staring at 0 for January
p(gc, Calendar.DATE); // date
p(gc, Calendar.DAY_OF_WEEK);// Sunday=1, Monday=2, .....Saturday -7
p(gc, Calendar.WEEK_OF_MONTH);//what week its running in week ,whether its first or second;
p(gc, Calendar.DAY_OF_WEEK_IN_MONTH);//In this case, How may times does Sunday is repeating in the month = 3;
p(gc, Calendar.DAY_OF_YEAR);//count of the day in the year
p(gc, Calendar.HOUR);//12 hour format. if the time is 22:09:55, answer would be (22-12)=10
p(gc, Calendar.HOUR_OF_DAY);// hour of day that is 22 (24h format)
p(gc, Calendar.MINUTE);// 09
p(gc, Calendar.SECOND);// 55
System.out.println();
System.out.println(gc.getTime());
}
static void p(Calendar c, int type) {
System.out.print(c.get(type) + "-");
}
}
*output :
2013-8-15-1-3-3-258-10-22-9-55-
Sun Sep 15 22:09:55 IST 2013
*
output Date visualization
This question already has answers here:
What is the use of "lenient "?
(7 answers)
Closed 7 years ago.
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
String dateStr = "35/35/1985";
Date date = sdf.parse(dateStr);
i was expecting run time exception like date parse exception but returned date object is Sat Dec 05 00:00:00 IST 1987
By what logic string 35/35/1985 parsed to date Sat Dec 05 00:00:00 IST 1987?
update:- If I set the setLenient(false), it throws exception. But if I make it true
By what logic string 35/35/1985 parsed to date Sat Dec 05 00:00:00 IST 1987?
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy");
String dateStr = "35/35/1985";
Date date = sdf.parse(dateStr);
To answer your "logic behind" question: Well, it will be parsed as
xx.xx.1985
-> set / add 35 Months (xx.35.1982 -> xx.11.1987)
-> set / add 35 Days (35.11.1987 -> 05.12.1987)
If you don't want this behaviuor, set lenient to false:
http://docs.oracle.com/javase/7/docs/api/java/text/DateFormat.html#setLenient%28boolean%29
To keep track of time, Java counts the number of milliseconds from the start of January 1, 1970. This means, for example, that January 2, 1970, began 86,400,000 milliseconds later. (...) The Java Date class keeps track of those milliseconds as a long value. Because long is a signed number, dates can be expressed before and after the start of January 1, 1970.
From JavaWorld.com
Basically, Java's engine does not know what a Date is, so a date is nothing but a reference to how many milliseconds have passed since the "Beginning" and it will then be converted to a nice MM/DD/YYYY format. Same thing in the other direction. So technically, 35/35/1985 is not a mistake, it simply means "substract 34 months, 34 days and 1985 years to 0 months, 0 days and 1970 years".
This can be useful if you are calculating Loans for example where people tend to reference 5 years as "60 months". See the point?
In you above code
you mentioned
year => 1985
month=> 35
day =>35
now first, year is 1985. if month is 12 then it will be 1985 after that when month is 24 it will be 1986. above 24, year will be 1987 and for month 35 it is Nov 1987. now your date is 35 which is above 30 so it will go to December 5 with adding one year i.e 1987.
so finally Dec 5 1987.
I was just trying out the java.util.Calendar method getActualMaximum() to see if I can get the maximum number of days in a month given the year. Here's my code:
public static void main(String[] args) {
Calendar c = Calendar.getInstance(); // today is July 29, 2012
System.out.println(c.get(Calendar.MONTH) + " " + c.getActualMaximum(Calendar.DATE) + " " + c.get(Calendar.YEAR));
c.set(Calendar.MONTH, Calendar.FEBRUARY); // set to February 2012
System.out.println(c.get(Calendar.MONTH) + " " + c.getActualMaximum(Calendar.DATE) + " " + c.get(Calendar.YEAR));
c.set(Calendar.YEAR, 2011); // set year to 2011, now February 2011
System.out.println(c.get(Calendar.MONTH) + " " + c.getActualMaximum(Calendar.DATE) + " " + c.get(Calendar.YEAR));
}
The output I'm expecting is:
6 31 2012 // last day of July 2012 is 31
1 29 2012 // last day of Feb 2012 is 29
1 28 2011 // last day of Feb 2011 is 28
However, this is what I'm getting:
6 31 2012
1 29 2012
2 31 2011 // HUH?
(In java.util.Calendar, the month values start from 0 to 11 for January to December, while the days of the months themselves start with 1.)
Why was the month suddenly set to Calendar.MARCH? What's going on here, and what can I do to get the last days of a given month and year correctly? I'm exploring the method because I don't want to set up my own array of booleans where it's true for indices that represent 31-day months and false for not.
I believe the calendar is remembering how many days into the year you are. in 2012 you were on day 31 + 29 = Feb 29. In 2011 that was March 1. Then you asked for the actual maximum of that month, which (for March) is 31.
Calendar API is horrible.
You should just set the year and month directly before asking for the actual maximum in your use-case.
It's happening because one year before February 29th, 2012 is March 1st, 2011.
There is no 29th day in February 2011 só the classe automatically adjusts for the first valid date. It believes that you walt the first day after February 28th, which is March 1st.
This question already has answers here:
Why is January month 0 in Java Calendar?
(18 answers)
Closed 3 years ago.
According to doc, calendar set() is:
http://docs.oracle.com/javase/1.5.0/docs/api/java/util/Calendar.html#set%28int,%20int,%20int%29
set(int year, int month, int date)
Sets the values for the calendar fields YEAR, MONTH, and DAY_OF_MONTH.
code:
Calendar c1 = GregorianCalendar.getInstance();
c1.set(2000, 1, 30); //January 30th 2000
Date sDate = c1.getTime();
System.out.println(sDate);
output:
Wed Mar 01 19:32:21 JST 2000
Why it's not Jan 30 ???
1 for month is February. The 30th of February is changed to 1st of March.
You should set 0 for month. The best is to use the constant defined in Calendar:
c1.set(2000, Calendar.JANUARY, 30);
Months in Calendar object start from 0
0 = January = Calendar.JANUARY
1 = february = Calendar.FEBRUARY
Selected date at the example is interesting. Example code block is:
Calendar c1 = GregorianCalendar.getInstance();
c1.set(2000, 1, 30); //January 30th 2000
Date sDate = c1.getTime();
System.out.println(sDate);
and output Wed Mar 01 19:32:21 JST 2000.
When I first read the example i think that output is wrong but it is true:)
Calendar.Month is starting from 0 so 1 means February.
February last day is 28 so output should be 2 March.
But selected year is important, it is 2000 which means February 29 so result should be 1 March.