Discrepancy in Java Calendar set Day Of Month vs G

2019-09-21 16:23发布

I am setting a Calendar day of month with an int value but when I check the value again the day of month from the created calendar it is 1 more than I set it to. And I am not sure why?

Here is an example:

System.out.println("DEBUG: Reminder day of month = " + reminder.getReminderDayofMonth());

calendar.set(Calendar.YEAR, reminder.getReminderYear());                   
calendar.set(Calendar.MONTH, reminder.getReminderMonth());
calendar.set(Calendar.DAY_OF_MONTH, reminder.getReminderDayofMonth());
calendar.set(Calendar.HOUR, reminder.getReminderHour());
calendar.set(Calendar.MINUTE, reminder.getReminderMinute());

System.out.println("DEBUG: Calendar day of month = " + calendar.get(Calendar.DAY_OF_MONTH));

I did the println so you can see the value in and the value out. I would expect that calling calander.get(Calander.DAY_OF_MONTH) would return the same value as I put into it. But it doesn't, I get:

DEBUG: Reminder day of month = 18
DEBUG: Calendar day of month = 19

I am sure it is probably something simple but I have no idea why they would be different and I can't find anything in the docs to explain the discrepancy

What is the problem?

Thanks for your help

1条回答
够拽才男人
2楼-- · 2019-09-21 16:54

TL:DR

LocalDateTime ldt = LocalDateTime.of(
    reminder.getReminderYear(),
    reminder.getReminderMonth() + 1,  // Add one to adjust from zero-based counting.
    reminder.getReminderDayofMonth(),
    reminder.getReminderHour(),
    reminder.getReminderMinute()
);

java.time

I suggest you put an end to using the very old and long outmoded Calendar class. Today we have so much better in java.time, the modern Java date and time API also known as JSR-310. The above code gives you the equivalent of what I think you were trying. I assumed getReminderMonth() returned 0-based month, so added 1 since the modern API numbers months from 1 just as humans do. If you can, I recommend you use an OffsetDateTime or ZonedDateTime to make the point on the time line unambiguous.

Question: Can I use the modern API with my Java version?

If using at least Java 6, you can.

  • In Java 8 and later the new API comes built-in.
  • In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR-310; link below).
  • On Android, use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. See the linked question below.

What went wrong in your code

I think the observed date increment happens when both of the following conditions are met:

  • Your code is running in the afternoon, that is at 12 noon or later in the Calendar’s time zone (typically the JVM’s time zone, in turn typically your local time zone).
  • getReminderHour() returns an hour in the afternoon, that is, 12 or later.

I cannot be 100 % sure since you haven’t shown us the code that produced your bug. But very likely your Calendar instance was created with the current time (Calendar.getInstance() and new GregorianCalendar(), for example, do this). In the afternoon it is obviously created with a time in PM. Then when you call calendar.set(Calendar.HOUR, reminder.getReminderHour()), this tries to set the hour within PM, but since the hour is 12 or greater, this overflows into AM of the following day. An hour of 14 (PM), for example, becomes 2 AM the next day.

If I am correct, the problem may seem solved not because you moved the creation of the calendar object inside your if statement, but because either you ran your program in the morning or the reminder hour was in the morning (before 12 noon). And your bug may surface again next time both the above-mentioned conditions apply,

Links

查看更多
登录 后发表回答