Hi I have something weird happening. I am simply taking a calendar object, converting it to its individual parts, and putting it back into a calendar (with or without any change
I suggest that you use java.time, the modern Java date and time API, for your date and time work. For example:
ZonedDateTime start = ZonedDateTime.now(ZoneId.systemDefault());
ZonedDateTime end = start;
System.out.println("Start: " + start);
System.out.println("End: " + end);
Output when I ran the code in my time zone just now:
Start: 2020-06-24T19:24:04.811+02:00[Europe/Copenhagen] End: 2020-06-24T19:24:04.811+02:00[Europe/Copenhagen]
A ZonedDateTime
is a date and time of day in some time zone. It’s the closest we come to a modern equivalent of GregorianCalendar
(the subclass of Calendar
that your code gave you). Which modern class to use varies with more precise requirements, so sometimes you will prefer to use for example LocalDate
, OffsetDateTime
or even LocalTime
.
To truncate the values to whole minutes (setting seconds and fraction of second to 0):
ZonedDateTime start = ZonedDateTime.now(ZoneId.systemDefault())
.truncatedTo(ChronoUnit.MINUTES);
Start: 2020-06-24T19:24+02:00[Europe/Copenhagen]
ZonedDateTime
and the other classes of java.time offer plenty of ways to modify the values obtained. For example:
ZonedDateTime end = start.plusDays(2).withHour(13);
End: 2020-06-26T13:24+02:00[Europe/Copenhagen]
If you want to create the end time manually using only selected fields from the start time:
ZonedDateTime end = ZonedDateTime.of(
2021, start.getMonthValue(), start.getDayOfMonth(),
start.getHour(), 30, 0, 0, start.getZone());
End: 2021-06-24T19:30+02:00[Europe/Copenhagen]
Part of the answer is already in the other answers: The set
methods of Calendar
set only the fields they promise to set and leave other fields unchanged where possible. While this is probably expected from the set(int field, int value)
method, it often surprises with the set(int year, int month, int date)
method and even more with set(int year, int month, int date, int hourOfDay, int minute)
and set(int year, int month, int date, int hourOfDay, int minute, int second)
. In general while well intended the Calendar
class and its subclasses are poorly and confusingly designed and cumbersome to work with. This is the main reason why I recommend java.time above.
The other part of the answer is that Calendar
calculates its fields leniently. So when you look at the Calendar
object in your debugger after calling set
, it will contain a lot of garbage values. Calling getTime()
forces the Calendar
to compute its fields, so after that call the way it looks in the debugger should make more sense. Again it’s confusing behaviour, and it can also sometimes be observed without using the debugger.
java.time works nicely on both older and newer Android devices. It just requires at least Java 6.
org.threeten.bp
with subpackages.java.time
was first described.java.time
to Java 6 and 7 (ThreeTen for JSR-310).