-2

Hi can any one explain why such abnormal behavior from Calendar .after method

Calendar cal = Calendar.getInstance();
Calendar cal1 = Calendar.getInstance();

cal.set(Calendar.HOUR, 14);
cal1.set(Calendar.HOUR, 13);

System.out.println(cal.after(cal1)+" Cal "+cal.getTime()+" cal1 "+cal1.getTime());      

cal.set(Calendar.DATE, Calendar.getInstance().get(Calendar.DATE));
System.out.println(cal.after(cal1)+" Cal "+cal.getTime()+" cal1 "+cal1.getTime());

Output:

true Cal Tue Oct 01 02:55:16 IST 2019 cal1 Tue Oct 01 01:55:16 IST 2019
true Cal Wed Oct 30 02:55:16 IST 2019 cal1 Tue Oct 01 01:55:16 IST 2019

but I did not get why cal is after cal1 even if i have set cal1's date to current date,

so if cal is today, I assigned the time as 14 hr it mover to next date then i set the date as current date in cal while for cal1 i did not.

So why still cal.after(cal1) is showing true in second syso while my cal1 is clearly 1 day greater than cal?

Pshemo
  • 122,468
  • 25
  • 185
  • 269
  • any suggestion to resolve such problem. – Atul Singh Rathore Sep 30 '19 at 07:41
  • 2
    I am not getting your problem. 1) 02:55h is _after_ 01:55h. 2) Oct 30 is _after_ Oct 01. So both outputs are correct! Unclear ... – Seelenvirtuose Sep 30 '19 at 07:45
  • 1
    What other results did you expect to get *from that code*? Why? – Pshemo Sep 30 '19 at 08:07
  • 1
    I recommend you don’t use `Calendar`. That class is poorly designed and long outdated. Instead use `ZonedDateTime` from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Sep 30 '19 at 09:07

4 Answers4

1

any suggestion to resolve such problem? Use java.time

I agree with you that there are some surprises in your code. You may have intended this:

    ZoneId zone = ZoneId.of("Asia/Kolkata");
    ZonedDateTime zdt = ZonedDateTime.now(zone);
    ZonedDateTime zdt1 = ZonedDateTime.now(zone);

    zdt = zdt.withHour(14);
    zdt1 = zdt1.withHour(13);

    System.out.println(zdt.isAfter(zdt1) + " zdt " + zdt + " zdt1 " + zdt1);

    zdt = zdt.withDayOfMonth(ZonedDateTime.now(zone).getDayOfMonth());
    System.out.println(zdt.isAfter(zdt1) + " zdt " + zdt + " zdt1 " + zdt1);

Output when I ran the code just now:

true zdt 2019-09-30T14:44:13.630029+05:30[Asia/Kolkata] zdt1 2019-09-30T13:44:13.630362+05:30[Asia/Kolkata]
true zdt 2019-09-30T14:44:13.630029+05:30[Asia/Kolkata] zdt1 2019-09-30T13:44:13.630362+05:30[Asia/Kolkata]

I get true both times just as you got from your code, which shouldn’t be surprising. As others have said, 02:55h is after 01:55h, and Oct 30 is after Oct 01. Also, referring to my result, 14:44 is after 13:44. In both lines these two times are compared.

I am using java.time, the modern Java date and time API.

What went wrong in your code?

The surprises in your code stem from the Calendar class being poorly designed and often behaving differently from what we would immediately expect.

  1. Why when you set the hour to 14, you get Tue Oct 01 02:55:16 IST 2019? The date has changed into the following month, and the hour of day is 2, not 14.
  2. Why when you set the date to today’s date, September 30, you get October 30?

For 1., Calendar.HOUR refers to hour within AM or PM from 0 through 11. So setting it to 14 we should have expected an exception. A Calendar with standard settings doesn’t care. Since the time was already in PM, it extrapolates, so 14 PM becomes 2 AM on the next day. Since today is the last day of September, you get October 1.

For 2., Calendar.DATE doesn’t refer to the full date, but to the day of month. Since current day of month is 30 and we already had October1, we get October 30.

Long story short: Avoid the Calendar class. Use ZonedDateTime and/or other classes form java.time, the modern Java date and time API. They are so much nicer to work with and give far fewer surprises like the ones you experienced.

Link

Oracle tutorial: Date Time explaining how to use java.time.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
0

Java docs for - Calendar.after()

public boolean after(Object when) {
    return when instanceof Calendar && compareTo((Calendar)when) > 0;
}
        //By definition :- true if the time of this Calendar is after the time represented by when; false otherwise.

        System.out.println(cal.after(cal1)+" Cal "+cal.getTime()+" cal1 "+cal1.getTime());
        //true Cal Tue Oct 01 02:17:46 IST 2019 cal1 Tue Oct 01 01:17:46 IST 2019

        cal.set(Calendar.HOUR, 13);
        cal1.set(Calendar.HOUR, 14);

        System.out.println(cal.after(cal1)+" Cal "+cal.getTime()+" cal1 "+cal1.getTime());
        //false Cal Tue Oct 01 01:16:55 IST 2019 cal1 Tue Oct 01 02:16:55 IST 2019

        cal.set(Calendar.DATE, Calendar.getInstance().get(Calendar.DATE));
        System.out.println(cal.after(cal1)+" Cal "+cal.getTime()+" cal1 "+cal1.getTime());
        //true Cal Wed Oct 30 13:17:46 IST 2019 cal1 Tue Oct 01 14:17:46 IST 2019
SSP
  • 2,650
  • 5
  • 31
  • 49
  • Sorry you got in wrong way I don't want to change Cal because its is coming a specific time from some string which parsed to 14:00:00 for example and the cal1 has to be compares whether its greater or lesser than cal,idid that for example to ask question – Atul Singh Rathore Sep 30 '19 at 08:05
  • So if I do cal.set(Calendar.HOUR, 14); cal1.set(Calendar.HOUR, 13); cal1.add(Calendar.DATE, 1); still the cal.after(cal1) wil give true while my cal1 is almost 2 day ahead than cal – Atul Singh Rathore Sep 30 '19 at 08:06
  • 1
    cal1 is not greate than cal. cal is 30 oct but cal1 is 1 oct. its true by logic. got it ? – SSP Sep 30 '19 at 08:08
0
         System.out.println(cal.after(cal1)+" Cal "+cal.getTime()+" cal1 "+cal1.getTime()); 
        //true Cal Tue Oct 01 02:25:19 MMT 2019 cal1 Tue Oct 01 01:25:19 MMT 2019  
    cal.set(Calendar.DATE, Calendar.getInstance().get(Calendar.DATE));
    System.out.println(cal1.after(cal)+" Cal "+cal.getTime()+" cal1 "+cal1.getTime());
   //false Cal Wed Oct 30 02:25:19 MMT 2019 cal1 Tue Oct 01 01:25:19 MMT 2019
0

Using

cal.setTime((Calendar.getInstance()).getTime());

instead of

cal.set(Calendar.DATE, Calendar.getInstance().get(Calendar.DATE));

gives the desired result.

Imal
  • 481
  • 1
  • 6
  • 14