Working with Date and Times Flashcards
What we need to import to work with the modern date and time classes?
import java.time.*; // import time classes
modern date and time classes
-
LocalDate
: Contains just a date—no time and no time zone.
A good example of LocalDate is your birthday this year. It is your birthday for a full day, regardless of what time it is. -
LocalTime
: Contains just a time—no date and no time zone.
A good example of LocalTime is midnight. It is midnight at the same time every day. -
LocalDateTime
: Contains both a date and time but no time zone.
A good example of LocalDateTime is “the stroke of midnight on New Year’s Eve.” Midnight on January 2 isn’t nearly as special, making the date elatively unimportant, and clearly an hour after midnight isn’t as special either. -
ZonedDateTime
: Contains a date, time, and time zone.
A good example of ZonedDateTime is “a conference call at 9:00 a.m. EST.” If you live in California, you’ll have to get up really early since the call is at 6:00 a.m. local time!
You obtain date and time instances using a static method now()
:
System.out.println(LocalDate.now()); // 2024-05-07 System.out.println(LocalTime.now()); // 16:55:57.880929400 System.out.println(LocalDateTime.now()); // 2024-05-07T16:56:25.920557500 System.out.println(ZonedDateTime.now()); // 2024-05-07T16:56:51.549554300+08:00[Asia/Kuala_Lumpur]
The output uses T to separate the date and time when converting LocalDateTime to a String.
> [!Note]
Greenwich Mean Time is a time zone in Europe that is used as time zone zero when discussing offsets. You might have also heard of Coordinated Universal Time, which is a time zone standard. It is abbreviated as UTC, as a compromise between the English and French names. (That’s not a typo. UTC isn’t actually the proper acronym in either language!) UTC uses the same time zone zero as GMT.
Covert to GMT
2022–06–20T06:50+05:30[Asia/Kolkata] 2022–06–20T07:50-05:00[US/Eastern]
Remember that you need to add when subtracting a negative number. After converting to GMT, you can see that the U.S. Eastern time is 11 and a half hours behind the Kolkata time.
2022–06–20T06:50+05:30[Asia/Kolkata] // GMT 2022–06–20 01:20 2022–06–20T07:50-05:00[US/Eastern] // GMT 2022–06–20 12:50
> [!NOTE]
Time Zone Rules
The time zone offset can be listed in different ways: +02:00, GMT+2, and UTC+2 all mean the same thing. You might see any of them on the exam.
LocalDate
of()
method signature.
public static LocalDate of(int year, int month, int dayOfMonth) public static LocalDate of(int year, Month month, int dayOfMonth)
EX :
var date1 = LocalDate.of(2022, Month.JANUARY, 20); var date2 = LocalDate.of(2022, 1, 20);
> [!Note]
Up to now, we’ve been continually telling you that Java counts starting with 0. Well, months are an exception. For months in the new date and time methods, Java counts starting from 1, just as we humans do.
LocalTime
of()
method signatures
public static LocalTime of(int hour, int minute) public static LocalTime of(int hour, int minute, int second) public static LocalTime of(int hour, int minute, int second, int nanos)
EX :
var time1 = LocalTime.of(6, 15); // hour and minute var time2 = LocalTime.of(6, 15, 30); // + seconds var time3 = LocalTime.of(6, 15, 30, 200); // + nanoseconds
LocalDateTime
of()
method signatures
public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute) public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second) public static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanos)
take a Month
reference:
public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute) public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute, int second) public static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute, int second, int nanos)
public static LocalDateTime of(LocalDate date, LocalTime time)
EX :
var dateTime1 = LocalDateTime.of(2022, Month.JANUARY, 20, 6, 15, 30); var dateTime2 = LocalDateTime.of(date1, time1);
ZonedDateTime
In order to create a ZonedDateTime, we first need to get the desired time zone. We will use US/Eastern in our examples:
var zone = ZoneId.of("US/Eastern"); var zoned1 = ZonedDateTime.of(2022, 1, 20, 6, 15, 30, 200, zone); var zoned2 = ZonedDateTime.of(date1, time1, zone); var zoned3 = ZonedDateTime.of(dateTime1, zone);
Although there are other ways of creating a ZonedDateTime, you only need to know three for the exam:
public static ZonedDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanos, ZoneId zone) public static ZonedDateTime of(LocalDate date, LocalTime time, ZoneId zone) public static ZonedDateTime of(LocalDateTime dateTime, ZoneId zone)
Notice that there isn’t an option to pass in the Month enum.
The date and time classes have private constructors
along with static methods
that return instances. This is known as the factory pattern
. The exam creators may throw something like this at you:
var d = new LocalDate(); // DOES NOT COMPILE
You are not allowed to construct a date or time object directly.
var d = LocalDate.of(2022, Month.JANUARY, 32)
When you pass invalid numbers to of(), it will throw DateTimeException
java.time.DateTimeException: Invalid value for DayOfMonth (valid values 1-28/31): 32
Manipulating Dates and Times
The date and time classes are immutable. Remember to assign the results of these methods to a reference variable so they are not lost.
12: var date = LocalDate.of(2022, Month.JANUARY, 20); 13: System.out.println(date); // 2022–01–20 14: date = date.plusDays(2); 15: System.out.println(date); // 2022–01–22 16: date = date.plusWeeks(1); 17: System.out.println(date); // 2022–01–29 18: date = date.plusMonths(1); 19: System.out.println(date); // 2022–02–28 20: date = date.plusYears(5); 21: System.out.println(date); // 2027–02–28 22: var date = LocalDate.of(2024, Month.JANUARY, 20); 23: var time = LocalTime.of(5, 15); 24: var dateTime = LocalDateTime.of(date, time); 25: System.out.println(dateTime); // 2024–01–20T05:15 26: dateTime = dateTime.minusDays(1); 27: System.out.println(dateTime); // 2024–01–19T05:15 28: dateTime = dateTime.minusHours(10); 29: System.out.println(dateTime); // 2024–01–18T19:15 30: dateTime = dateTime.minusSeconds(30); 31: System.out.println(dateTime); // 2024–01–18T19:14:30
var date = LocalDate.of(2024, Month.JANUARY, 20); var time = LocalTime.of(5, 15); var dateTime = LocalDateTime.of(date, time) .minusDays(1).minusHours(10).minusSeconds(30);
It is common for date and time methods to be chained.
What do you think this prints?
var date = LocalDate.of(2024, Month.JANUARY, 20); date.plusDays(10); System.out.println(date);
It prints January 20, 2024.
Whenever you see immutable types
, pay attention to make sure that the return value of a method call isn’t ignored.
Do you see what is wrong here?
var date = LocalDate.of(2024, Month.JANUARY, 20); date = date.plusMinutes(1); // DOES NOT COMPILE
LocalDate
does not contain time. This means that you cannot add minutes to it.
Which method LocalDate
can call?
plusYears() minusYears() plusMonths() minusMonths() plusWeeks() minusWeeks() plusDays() minusDays()
Which method LocalTime
can call?
plusHours() minusHours() plusMinutes() minusMinutes() plusSeconds() minusSeconds() plusNanos() minusNanos()
Which method LocalDateTime
or ZonedDateTime
can call?
plusYears() minusYears() plusMonths() minusMonths() plusWeeks() minusWeeks() plusDays() minusDays() plusHours() minusHours() plusMinutes() minusMinutes() plusSeconds() minusSeconds() plusNanos() minusNanos()
> [!Note]
LocalDate and LocalDateTime have a method to convert themselves into long values, equivalent to the number of milliseconds that have passed since January 1, 1970, referred to as the epoch.
What’s special about this date?
That’s what Unix started using for date standards, so Java reused it.
Working with Periods
public static void main(String[] args) { var start = LocalDate.of(2022, Month.JANUARY, 1); var end = LocalDate.of(2022, Month.MARCH, 30); var period = Period.ofMonths(1); // create a period performAnimalEnrichment(start, end, period); } private static void performAnimalEnrichment(LocalDate start, LocalDate end, Period period) { // uses the generic period var upTo = start; while (upTo.isBefore(end)) { System.out.println("give new toy: " + upTo); upTo = upTo.plus(period); // adds the period } }
Creating Period
var annually = Period.ofYears(1); // every 1 year, P1Y var quarterly = Period.ofMonths(3); // every 3 months, P3M var everyThreeWeeks = Period.ofWeeks(3); // every 3 weeks, P21D var everyOtherDay = Period.ofDays(2); // every 2 days, P2D var everyYearAndAWeek = Period.of(1, 0, 7); // every year and 7 days, P1Y7D
System.out.println(Period.of(1,2,3)); // output: P1Y2M3D // P is for period // 1Y is 1 year // 2M is 2 months // 3D is 3 days
How to get Period
of everyYearAndAWeek?
Invalid ex: (Period is immutable)
var wrong = Period.ofYears(1).ofWeeks(1); // every week, output: P7D var wrong = Period.ofYears(1); wrong = Period.ofWeeks(1); // every week, get new Period, output:P7D
Valid ex:
jshell> Period.of(1,0,7) $7 ==> P1Y7D
3: var date = LocalDate.of(2022, 1, 20); 4: var time = LocalTime.of(6, 15); 5: var dateTime = LocalDateTime.of(date, time); 6: var period = Period.ofMonths(1); 7: System.out.println(date.plus(period)); // 2022–02–20 8: System.out.println(dateTime.plus(period)); // 2022–02–20T06:15 9: System.out.println(time.plus(period)); // Exception
Line 9 attempts to add a month to an object that has only a time.
This won’t work.
Java throws an UnsupportedTemporalTypeException
and complains that we attempted to use an Unsupported unit: Months.
Creating Durations
var daily = Duration.ofDays(1); // PT24H var hourly = Duration.ofHours(1); // PT1H var everyMinute = Duration.ofMinutes(1); // PT1M var everyTenSeconds = Duration.ofSeconds(10); // PT10S var everyMilli = Duration.ofMillis(1); // PT0.001S var everyNano = Duration.ofNanos(1); // PT0.000000001S
var daily = Duration.of(1, ChronoUnit.DAYS); var hourly = Duration.of(1, ChronoUnit.HOURS); var everyMinute = Duration.of(1, ChronoUnit.MINUTES); var everyTenSeconds = Duration.of(10, ChronoUnit.SECONDS); var everyMilli = Duration.of(1, ChronoUnit.MILLIS); var everyNano = Duration.of(1, ChronoUnit.NANOS);
> [!Note]
ChronoUnit for DifferencesChronoUnit
is a great way to determine how far apart two Temporal values are. Temporal includes LocalDate, LocalTime, and so on. ChronoUnit
is in the java.time.temporal
package.
ChronoUnit
is in the java.time.temporal
package.
var one = LocalTime.of(5, 15); var two = LocalTime.of(6, 30); var date = LocalDate.of(2016, 1, 20); System.out.println(ChronoUnit.HOURS.between(one, two)); // 1 System.out.println(ChronoUnit.MINUTES.between(one, two)); // 75 System.out.println(ChronoUnit.MINUTES.between(one, date)); // DateTimeException
- The first print statement shows that between truncates rather than rounds.
- The second shows how easy it is to count in different units. Just change the ChronoUnit type.
- The last reminds us that Java will throw an exception if we mix up what can be done on date vs. time objects.
Alternatively, you can truncate
any object with a time element. For example:
LocalTime time = LocalTime.of(3, 12, 45); System.out.println(time); // 03:12:45 LocalTime truncated = time.truncatedTo(ChronoUnit.MINUTES); System.out.println(truncated); // 03:12
This example zeroes out any fields smaller than minutes. In our case, it gets rid of the seconds.
LocalTime truncated = time.truncatedTo(ChronoUnit.MINUTES);
7: var date = LocalDate.of(2022, 1, 20); 8: var time = LocalTime.of(6, 15); 9: var dateTime = LocalDateTime.of(date, time); 10: var duration = Duration.ofHours(6); 11: System.out.println(dateTime.plus(duration)); // 2022–01–20T12:15 12: System.out.println(time.plus(duration)); // 12:15 13: System.out.println( 14: date.plus(duration)); // UnsupportedTemporalTypeException
- Line 11 shows that we can add hours to a LocalDateTime, since it contains a time.
- Line 12 also works, since all we have is a time.
- Line 13 fails because we cannot add hours to an object that does not contain a time.
7: var date = LocalDate.of(2022, 1, 20); 8: var time = LocalTime.of(6, 15); 9: var dateTime = LocalDateTime.of(date, time); 10: var duration = Duration.ofHours(23); 11: System.out.println(dateTime.plus(duration)); // 2022–01–21T05:15 12: System.out.println(time.plus(duration)); // 05:15 13: System.out.println( 14: date.plus(duration)); // UnsupportedTemporalTypeException
- This time we see that Java moves forward past the end of the day.
- Line 11 goes to the next day since we pass midnight.
- Line 12 doesn’t have a day, so the time just wraps around—just like on a real clock.
Period vs. Duration
Remember that Period and Duration are not equivalent. This example shows a Period and Duration of the same length:
var date = LocalDate.of(2022, 5, 25); var period = Period.ofDays(1); var days = Duration.ofDays(1); System.out.println(date.plus(period)); // 2022–05–26 System.out.println(date.plus(days)); // Unsupported unit: Seconds
Which objects can use Period and Duration?
- LocalDate, can use Period
- LocalTime, can use Duration
- LocalDateTime, can use both Period and Duration
- ZonedDateTime, can use both Period and Duration
Working with Instants
The Instant
class represents a specific moment in time in the GMT time zone. Suppose that you want to run a timer:
var now = Instant.now(); // do something time consuming var later = Instant.now(); var duration = Duration.between(now, later); System.out.println(duration.toMillis()); // Returns number milliseconds
ZonedDateTime to Instant
var date = LocalDate.of(2022, 5, 25); var time = LocalTime.of(11, 55, 00); var zone = ZoneId.of("US/Eastern"); var zonedDateTime = ZonedDateTime.of(date, time, zone); var instant = zonedDateTime.toInstant(); // 2022–05–25T15:55:00Z System.out.println(zonedDateTime); // 2022–05–25T11:55–04:00[US/Eastern] System.out.println(instant); // 2022–05–25T15:55:00Z
The last two lines represent the same moment in time. The ZonedDateTime includes a time zone. The Instant gets rid of the time zone and turns it into an Instant of time in GMT.
You cannot convert a LocalDateTime to an Instant. Remember that an Instant is a point in time. A LocalDateTime does not contain a time zone, and it is therefore not universally recognized around the world as the same moment in time
Accounting for Daylight Saving Time
You only have to work with U.S. daylight saving time on the exam
var date = LocalDate.of(2022, Month.MARCH, 13); var time = LocalTime.of(1, 30); var zone = ZoneId.of("US/Eastern"); var dateTime = ZonedDateTime.of(date, time, zone); System.out.println(dateTime); // 2022–03-13T01:30-05:00[US/Eastern] System.out.println(dateTime.getHour()); // 1 System.out.println(dateTime.getOffset()); // -05:00 dateTime = dateTime.plusHours(1); System.out.println(dateTime); // 2022–03-13T03:30-04:00[US/Eastern] System.out.println(dateTime.getHour()); // 3 System.out.println(dateTime.getOffset()); // -04:00
Notice that two things change in this example.
The time jumps from 1:30 to 3:30. The UTC offset also changes. Remember when we calculated GMT time by subtracting the time zone from the time? You can see that we went from 6:30 GMT (1:30 minus –5:00) to 7:30 GMT (3:30 minus –4:00). This shows that the time really did change by one hour from GMT’s point of view. We printed the hour and offset fields separately for emphasis.
var date = LocalDate.of(2022, Month.NOVEMBER, 6); var time = LocalTime.of(1, 30); var zone = ZoneId.of("US/Eastern"); var dateTime = ZonedDateTime.of(date, time, zone); System.out.println(dateTime); // 2022-11-06T01:30-04:00[US/Eastern] dateTime = dateTime.plusHours(1); System.out.println(dateTime); // 2022-11-06T01:30-05:00[US/Eastern] dateTime = dateTime.plusHours(1); System.out.println(dateTime); // 2022-11-06T02:30-05:00[US/Eastern]
We went from 5:30 GMT to 6:30 GMT, to 7:30 GMT.
var date = LocalDate.of(2022, Month.MARCH, 13); var time = LocalTime.of(2, 30); var zone = ZoneId.of("US/Eastern"); var dateTime = ZonedDateTime.of(date, time, zone); System.out.println(dateTime); // 2022–03–13T03:30–04:00[US/Eastern]
Java is smart enough to know that there is no 2:30 a.m. that night and switches over to the appropriate GMT offset.