Dev Learning Lab

The labs on this site need JavaScript to run. The same content is written out below.

Learn › Java › Commonly used classes

Dates and times

What date do you get when you add one month to January 31?

Like a String, the date and time objects of java.time (LocalDate, ZonedDateTime, and so on) do not change their contents. A method such as plusMonths returns a new object, and because the months have different numbers of days, the result of "one month later" is sometimes not what you expect. The same instant is written as a different date and time in each time zone, and the amount of time between two points in time is measured separately in date-based units (Period) and in time-based units (Duration).

Checked against real execution · The 135 combinations (11 distinct cases) were run on JDK 21 and checked against the results

Concepts in this lab

java.time (Date-Time API)
This is the set of date and time classes that has been part of Java since Java 8. It includes LocalDate, which holds only a date; LocalDateTime, which holds a date and a time; ZonedDateTime, which holds a time zone as well; and Instant, which holds a single point in time that does not depend on any time zone. All of these objects are immutable, so methods such as plusDays and plusMonths do not change the original object. They return a new object. You therefore have to assign the return value to a variable to use the result. When the result of adding months is a date that is not in the calendar (for example, February 31), no exception is thrown, and the date is adjusted to the last day of that month.
Time zone and UTC
UTC is the time that the whole world uses as its reference, and a time zone is the set of rules for how far the time used in a region differs from UTC. Korea (Asia/Seoul) is 9 hours ahead of UTC. The same instant is written as a different time in each time zone, and sometimes the date is different as well. In a region that uses daylight saving time, the offset from UTC changes with the season, so it is safer to specify a time zone by a region name such as America/New_York than by a fixed offset. The usual practice is to store a point in time as a value that does not depend on a time zone (an Instant) and to convert it to the time zone of the viewer when it is displayed.
Period and Duration
These are the two classes in java.time that represent the amount of time between two points in time. A Period expresses the amount in calendar years, months, and days, as in "1 year, 2 months, and 3 days", and a Duration expresses the length of the elapsed time in seconds, as in "90 minutes". The length of a month differs from month to month, so a Period cannot be converted to a fixed length of time, and a Duration has no unit such as a month or a year. The getDays() method of Period returns only the value of the days part, not the total number of days, so get the total number of days with ChronoUnit.DAYS.between. Duration.between must be given values that have a time, and passing LocalDate values, which have only a date, throws an exception at run time.
Immutable object
This is an object whose state does not change after it is created. Because its value never changes, it is safe for several threads to use at the same time, you can pass it to other code without worrying that it will be changed, and it is well suited for caching or for use as a key in a hash collection. Declare the fields private final, provide no methods that change the state, and make the class final so that a subclass cannot change its behavior. If a field refers to a mutable object (such as a List or a Date), the constructor and the getters pass copies in and out (defensive copying) so that outside code cannot change the internals.

Try these

Running with the default settings

  1. LocalDate d = LocalDate.of(2024, 1, 31): A date object that represents January 31, 2024 is created, and d refers to it. A LocalDate holds only a date, with no time and no time zone.
  2. LocalDate first = d: first refers to the same object as well. first is kept so that you can see later whether the first object changes.
  3. d = d.plusMonths(1): One month after January 31 should be February 31, but there is no such day. In this case the date is adjusted to the last day of that month. February 2024 has 29 days, so the result is 2024-02-29. d refers to this new object.
  4. System.out.println(d): The line 2024-02-29 is printed.
  5. System.out.println(first): The line 2024-01-31 is printed. The contents of the first object did not change.
  6. d == first: d refers to the newly created object and first refers to the first object, so the result is false.

Result of this run

Code

LocalDate d = LocalDate.of(2024, 1, 31);
LocalDate first = d;                 // remember the first object

d = d.plusMonths(1);

System.out.println(d);
System.out.println(first);
System.out.println(d == first);      // same object?

Assumptions of this model

The output of the 135 combinations (11 distinct cases, because each topic uses only one of the settings) was checked against the results of running the same code on JDK 21 on this PC. The code uses only fixed dates and time zones specified by name, so it gives the same result regardless of the current date or the time zone setting of the PC, and running it with the default time zone of the PC changed to other values confirmed that the output is the same. The time in each time zone follows the time zone data included in the JDK. New York being 5 hours behind UTC applies to this date (winter), and the difference is 4 hours during daylight saving time. Calculations for the days on which daylight saving time starts or ends are not covered by this model. Results for years that are not leap years (for example, February 28) are not within the range that was run and checked.

Previous lab: String, StringBuilder · Next lab: Optional

Concepts in this lab

What this lab shows

Settings

Code


      
    

Diagram

Run comparison

Try these