Detect invalid date on Calendar.set() - java

I have this method that returns me a Date() changed by one of it's "fields" (DAY, MONTH, YEAR).
public static Date getDateChanged(Date date, int field, int value) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.set(field, value);
return cal.getTime();
}
However, cal.set() is unable to give an exception when the field we are trying to set is not compatible with the date in question. So, in this case:
Date date = new Date();
date = getDateChanged(date, Calendar.DAY_OF_MONTH, 29);
date = getDateChanged(date, Calendar.MONTH, 1); // feb
date is, in the end, 01/03/15, because Calendar.set() detects that February can't be set with day 29, so automatically set's date to the next possible day (I thinks this is how the routine works).
This is not so bad, however, in my case,
I want to detect that the date I'm trying to build is impossible and then start decrementing the day, so in this case what I'm trying to achieve is 28/02/15, how can I do this?
Example:
29/02/15 ===> 28/02/15

You can use cal.getActualMaximum(Calendar.DAY_OF_MONTH) to find the maximum days in the given month for your calendar instance.
This way, you can handle the case you mentioned above yourself.
Also see the answer here: Number of days in particular month of particular year?

You can use:
public void setLenient(boolean lenient)
Specifies whether or not date/time interpretation is to be lenient.
With lenient interpretation, a date such as "February 942, 1996" will
be treated as being equivalent to the 941st day after February 1,
1996. With strict (non-lenient) interpretation, such dates will cause an exception to be thrown. The default is lenient.
Parameters:
lenient - true if the lenient mode is to be turned on; false if it is to be turned off.
See Also:
isLenient(), DateFormat.setLenient(boolean)
This way you get exception when you pass something wrong :)

You can check the maximum value with getActualMaximum:
public static Date getDateChanged(Date date, int field, int value) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
int maximum = calendar.getActualMaximum(field);
if (value > maximum) {
value = maximum;
}
cal.set(field, value);
return cal.getTime();
}

May be this solution will help you
public static Date getDateChanged(Date date, int field, int value) {
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.set(field, value);
if (field == Calendar.MONTH && cal.get(Calendar.MONTH) != value) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int month = (cal.get(Calendar.MONTH) - 1) < 0 ? 0 : (cal.get(Calendar.MONTH) - 1);
calendar.set(Calendar.DATE, calendar.getActualMinimum(Calendar.DATE));
calendar.set(Calendar.MONTH, month);
calendar.set(Calendar.DATE, calendar.getActualMaximum(Calendar.DATE));
return calendar.getTime();
}
return cal.getTime();
}

Related

Java Calendar get() method is not working

I build an android calendar example, but I am weird when I worked with it.
I tried to get Monday this week which I set. However, within this code
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.DATE, day);
calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
int start = calendar.get(Calendar.DAY_OF_MONTH);
I cannot get right activity. A symptom is I can get right Monday of this week
but last week also gave me this monday, so I tried another code which is
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.DATE, day);
int start = calendar.get(Calendar.DATE);
calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
start = calendar.get(Calendar.DATE);
Then I can get right activity what I want.
However I do not know why it is working and difference between these two codes.
Thanks for reading and helping!
First importan info,calendar has two modes for interpreting the calendar fields, lenient and non-lenient.
When a Calendar is in lenient mode, it accepts a wider range of calendar field values than it produces. When a Calendar recomputes calendar field values for return by get(), all of the calendar fields are normalized. For example, a lenient GregorianCalendar interprets MONTH == JANUARY, DAY_OF_MONTH == 32 as February 1.
When a Calendar is in non-lenient mode, it throws an exception if there is any inconsistency in its calendar fields. For example, a GregorianCalendar always produces DAY_OF_MONTH values between 1 and the length of the month. A non-lenient GregorianCalendar throws an exception upon calculating its time or calendar field values if any out-of-range field value has been set.
Another important info,calendar set method is only set the field value,but not update time and compute every fields(like year,month,day and so on) until you use any get method.
When Calendar run in lenient mode,here is code:
Calendar calendar = Calendar.getInstance();
calendar.setLenient(true);
calendar.set(Calendar.DATE, 1);
calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
System.out.println(calendar.get(Calendar.DAY_OF_MONTH));
code run result is 10.
After call two set mothed, begin call get Calendar.DAY_OF_MONTH,now calendar begin to update time , Date 1 and DAY_OF_WEEK of MONDAY confuse , but Calendar is in lenient mode, final calculate the date 2016-10-10,so get result is 10.
same code in non-lenient mode:
Calendar calendar = Calendar.getInstance();
calendar.setLenient(false);
calendar.set(Calendar.DATE, 1);
calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
System.out.println(calendar.get(Calendar.DAY_OF_MONTH));
throws java.lang.IllegalArgumentException: DAY_OF_MONTH exception.
last code:
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.DATE, 1);
int start = calendar.get(Calendar.DATE);
calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
start = calendar.get(Calendar.DATE);
code run result is 26.
when first call get Calendar.DATE,this call will updatetime and compute every fields . calculate date is 2016-10-01 .then call set(Calendar.DAY_OF_WEEK, Calendar.MONDAY), after this call get method,calculate date is 2016-09-26,so result is 26.

Java Date Comparison [duplicate]

This question already has answers here:
Comparing two java.util.Dates to see if they are in the same day
(14 answers)
How to know if a Date is within the same day of other date [duplicate]
(2 answers)
Closed 6 years ago.
According to Java API public boolean before(Date when)
true if and only if the instant of time represented by this Date
object is strictly earlier than the instant represented by when; false
otherwise.
Now I have to check if date input by user is greater than current date then only it will accept the input otherwise throw exception so i tried below
if(userInputDate.before(new Date())){
throw new Exception("Some Message");
}
But if both date are same then also it going to inside if statement .Do it mean it will calculate time and then check rather than comparing date? If yes how to resolve my issue ?
Can any one tell me how to add check for this?
The method before in the class Date is comparing the millisecond between the dates, so it's not comparing just the day, it is comparing the instant of time.
You could create a method to check if the dates are not in the same day and the first date is before the second one
public static boolean isBeforeDate(Date date1, Date date2) {
SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMdd");
boolean areTheSameDay = fmt.format(date1).equals(fmt.format(date2));
return !areTheSameDay && date1.before(date2);
}
If you can use the new time api In Java8 instead of the old Date class, you can use the class LocalDate and the method compareTo:
boolean isBefore = myLocalDate.compareTo(myOtherLocalDate) < 0
All methods on java.util.Date that allow one to separate the time of day from the day of the year are deprecated. Therefore it is better to use java.util.Calendar. Additionally one should consider that there is typically one hour in each year that is in two days when summer time ends.
Here are two ways you can do it:
public static boolean isBeforeDay(Date date1, Date date2) {
// convert date1 to noon on the same day
Calendar day1 = Calendar.getInstance(TimeZone.getDefault());
day1.setTime(date1);
day1.set(Calendar.HOUR_OF_DAY, 12);
day1.set(Calendar.MINUTE, 0);
day1.set(Calendar.SECOND, 0);
day1.set(Calendar.MILLISECOND, 0);
// convert date2 to noon on the same day
Calendar day2 = Calendar.getInstance(TimeZone.getDefault());
day2.setTime(date2);
day2.set(Calendar.HOUR_OF_DAY, 12);
day2.set(Calendar.MINUTE, 0);
day2.set(Calendar.SECOND, 0);
day2.set(Calendar.MILLISECOND, 0);
return day1.before(day2);
}
public static boolean isBeforeDay(Date date1, Date date2) {
// get yyyymmdd value from date1
Calendar day1 = Calendar.getInstance(TimeZone.getDefault());
day1.setTime(date1);
int ymd1 = 10000*day1.get(Calendar.YEAR) + 100*day1.get(Calendar.MONTH) + day1.get(Calendar.DAY_OF_MONTH);
// get yyyymmdd value from date2
Calendar day2 = Calendar.getInstance(TimeZone.getDefault());
day2.setTime(date2);
int ymd2 = 10000*day2.get(Calendar.YEAR) + 100*day2.get(Calendar.MONTH) + day2.get(Calendar.DAY_OF_MONTH);
return ymd1 < ymd2;
}

How to get all the dates in a month using calender class?

Here I want to display dates like
2013-01-01,
2013-01-02,
2013-01-03,
.
.
...etc
I can get total days in a month
private int getDaysInMonth(int month, int year) {
Calendar cal = Calendar.getInstance(); // or pick another time zone if necessary
cal.set(Calendar.MONTH, month);
cal.set(Calendar.DAY_OF_MONTH, 1); // 1st day of month
cal.set(Calendar.YEAR, year);
cal.set(Calendar.HOUR, 0);
cal.set(Calendar.MINUTE, 0);
Date startDate = cal.getTime();
int nextMonth = (month == Calendar.DECEMBER) ? Calendar.JANUARY : month + 1;
cal.set(Calendar.MONTH, nextMonth);
if (month == Calendar.DECEMBER) {
cal.set(Calendar.YEAR, year + 1);
}
Date endDate = cal.getTime();
// get the number of days by measuring the time between the first of this
// month, and the first of next month
return (int)((endDate.getTime() - startDate.getTime()) / (24 * 60 * 60 * 1000));
}
Does anyone have an idea to help me?
If you only want to get the max number of days in a month you can do the following.
// Set day to one, add 1 month and subtract a day
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.set(Calendar.DAY_OF_MONTH, 1);
cal.add(Calendar.MONTH, 1);
cal.add(Calendar.DAY_OF_MONTH, -1);
return cal.get(Calendar.DAY_OF_MONTH);
If you actually want to print every day then you can just set the day of month to 1 and keep adding a day in a loop until the month changes.
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.set(Calendar.DAY_OF_MONTH, 1);
int myMonth=cal.get(Calendar.MONTH);
while (myMonth==cal.get(Calendar.MONTH)) {
System.out.print(cal.getTime());
cal.add(Calendar.DAY_OF_MONTH, 1);
}
Modern answer: Don’t use Calendar. Use java.time, the modern Java date and time API.
YearMonth ym = YearMonth.of(2013, Month.JANUARY);
LocalDate firstOfMonth = ym.atDay(1);
LocalDate firstOfFollowingMonth = ym.plusMonths(1).atDay(1);
firstOfMonth.datesUntil(firstOfFollowingMonth).forEach(System.out::println);
Output (abbreviated):
2013-01-01
2013-01-02
2013-01-03
…
2013-01-30
2013-01-31
datesUntil gives us a stream of dates until the specified end date exclusive, so when we give it the 1st of the following month, we get exactly all the dates of the month in question. In this example case up to and including January 31.
Link: Oracle tutorial: Date Time explaining how to use java.time.
This will give you all days of a month.
Calendar cal = Calendar.getInstance();
cal.set(Calendar.MONTH, 1);
cal.set(Calendar.DAY_OF_MONTH, 1);
int maxDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
System.out.print(df.format(cal.getTime()));
for (int i = 1; i < maxDay; i++) {
cal.set(Calendar.DAY_OF_MONTH, i + 1);
System.out.print(", " + df.format(cal.getTime()));
}
The first date is printed outside of loop for comma separated output.
A couple of comments...
Firstly, "... Calendar objects are particularly expensive to create." (J. Bloch, Effective Java, 2nd Ed.). If this is a method that you are going to be calling frequently, consider that you do not need to create a new Calendar object every time you call it.
Consider using a Calendar object held in a private static field that is initialized with a static initializer block. This presumes a single-threaded solution and would require synchronization in a concurrent environment. Otherwise, it really ought to be possible to reuse the same Calendar for your calculations.
Secondly, while you can find that greatest value for the DAY_OF_MONTH by iterating over the possible valid values, I think you can let the API do it for you. Consider using the getMaximum(DAY_OF_MONTH) or getGreatestMaximum(DAY_OF_MONTH) methods of the Calendar class.
Write a common method like that if you are using kotlin-
fun getAllDateOfMonth(year: Int, month: Month): List<LocalDate> {
val yearMonth= YearMonth.of(year, month)
val firstDayOfTheMonth = yearMonth.atDay(1)
val datesOfThisMonth = mutableListOf<LocalDate>()
for (daysNo in 0 until yearMonth.lengthOfMonth()){
datesOfThisMonth.add(firstDayOfTheMonth.plusDays(daysNo.toLong()))
}
return datesOfThisMonth
}
And call it like that -
getAllDateOfMonth(2021,Month.MAY):

How to set some days on Calendar.DAY_OF_WEEK

I need to set some days in method set. I try to use:
c.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
c.set(Calendar.DAY_OF_WEEK, Calendar.WEDNESDAY);
but with this way set only Wednesday.
Thank you and sorry for my english :)
The Calendar does not function as you expect it to. From the JavaDoc:
The Calendar class is an abstract class that provides methods for
converting between a specific instant in time and a set of calendar
fields such as YEAR, MONTH, DAY_OF_MONTH, HOUR, and so on, and for
manipulating the calendar fields, such as getting the date of the next
week. An instant in time can be represented by a millisecond value
that is an offset from the Epoch, January 1, 1970 00:00:00.000 GMT
(Gregorian).
Notice that the documentation states a specific instant in time. This implies the Calendar can only be based off of one point in time from epoch.
When you use the set method you are adjusting the specific instant in time through each call. So first it gets set to Monday then Wednesday.
You could use a List<Calendar> to store multiple Calendar instances set to your desired days.
public class CalendarTest {
public static void main(String[] args) {
Calendar cal1 = Calendar.getInstance();
Calendar cal2 = Calendar.getInstance();
cal1.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
cal2.set(Calendar.DAY_OF_WEEK, Calendar.WEDNESDAY);
List<Calendar> calendars = Arrays.asList(cal1, cal2);
}
}
public static String getDay(String day,String month,String year){
int mm = Integer.parseInt(month);
int dd = Integer.parseInt(day);
int yy = Integer.parseInt(year);
LocalDate dt = LocalDate.of(yy, mm, dd);
return dt.getDayOfWeek().toString().toUpperCase();
}

Date picking and finding difference

I am a novice to Java programming using Netbeans. I have added jCalendar to my GUI to pick a date.
I have entered this line in Events -> "property change" code of jCalendar button,
Date date=jcalendar1.getDate();
So that I get the date immediately when it is changed. Am I right?
The purpose:
I want to find the difference in milliseconds from the afternoon (12:00 pm) of this date above to NOW (current date and time).
There are several programs showing the date difference but all have dates hardcoded and being a newbie i do not know how to replace it with the date that is picked. (also i am confused between the objects Date and Calendar, not able to understand the difference between them). For example, a piece from here:
http://www.java2s.com/Code/Java/Data-type/ReturnsaDatesetjusttoNoontotheclosestpossiblemillisecondoftheday.htm
if (day == null) day = new Date();
cal.setTime(day);
cal.set(Calendar.HOUR_OF_DAY, 12);
cal.set(Calendar.MINUTE, cal.getMinimum(Calendar.MINUTE));
cal.set(Calendar.SECOND, cal.getMinimum(Calendar.SECOND));
cal.set(Calendar.MILLISECOND, cal.getMinimum(Calendar.MILLISECOND));
return cal.getTime();
Here day is a Date object. How is cal (a calendar object) linked to it to enter the time. How should the cal object be defined first? How can I use this or anything else in your opinion for my program. A piece of code with detail comments will be more helpful
thanks!
Instead of using :
Date day = new Date();
Use:
Calendar cal = Calendar.getInstance();
cal.set (...);
Date date = new Date(cal.getTimeInMillis());
Worth abstracting this stuff out to a DateUtils class or similar, with something like the following:
public static Date create(int year, int month, int day, int hour, int minute, int second) {
return new Date(getTimeInMillis(year, month, day, hour, minute, second));
}
public static long getTimeInMillis(int year, int month, int day, int hour, int minute, int second, int milliseconds) {
Calendar cal = Calendar.getInstance();
cal.clear();
cal.set(year, month, day, hour, minute, second);
cal.set(Calendar.MILLISECOND, milliseconds);
return cal.getTimeInMillis();
}

Categories