Chapter 8. Use Java SE 8 Date/Time API

8.1.  Create and manage date- and time-based events, including a combination of date and time in a single object, by using LocalDate, LocalTime, LocalDateTime, Instant, Period, and Duration

[Note]

The classes defined in the java.time package represent the principal date-time concepts, including instants, durations, dates, times, time-zones and periods. They are based on the ISO calendar system, which is the de facto world calendar following the proleptic Gregorian rules.

[Important]

One of the serious weaknesses of the existing date/time classes and formatters (such as java.util.Date and SimpleDateFormatter) in Java is that they aren't thread-safe. This puts the burden on developers to use them in a thread-safe manner and to think about concurrency problems in their day-to-day development of date-handling code. The new Date/Time API avoids this issue by ensuring that all its core classes are immutable and represent well-defined values.

All new Date/Time API classes are immutable and thread-safe. After the object is created, it cannot be modified. To alter the value of an immutable object, a new object must be constructed as a modified copy of the original.

Timestamps

  • Instant

    Instant is essentially a numeric timestamp. The current Instant can be retrieved from a Clock. This is useful for logging and persistence of a point in time and has in the past been associated with storing the result from System.currentTimeMillis().

    An Instant is a point of time counting from the first second of January 1, 1970 (1970-01-01T00:00:00Z), also known as EPOCH. This timestamps are very useful and used in several applications and operating systems. The Instant class is the API answer for this machine view of the time.

    Instant values can be negative if they occured before the epoch. They follow ISO 8601 the standard for representing date and time.

    An Instant can be created in several ways:

    // Current time
    Instant now = Instant.now();
    
    // From Unix timestamp, 2015-07-13T20:45:44.404Z
    Instant fromUnixTimestamp = Instant.ofEpochSecond(1436820344);
    
    // Same time in millis
    Instant fromEpochMilli = Instant.ofEpochMilli(1436820344404L);
    
    // Parsing from ISO 8601
    Instant fromIso8601 = Instant.parse("2015-07-10T12:00:00Z");
    System.out.println(fromIso8601);
    
    // toString() returns ISO 8601 format, e.g. 2015-07-13T20:47:33.563Z
    String toIso8601 = now.toString();
    System.out.println(toIso8601);
    
    // As unix timestamp
    long toUnixTimestamp = now.getEpochSecond();
    System.out.println(toUnixTimestamp);
    
    // In milliseconds
    long toEpochMillis = now.toEpochMilli();
    System.out.println(toEpochMillis);
    
    								

    output:

    2015-07-10T12:00:00Z
    2015-07-13T20:47:33.563Z
    1436820453
    1436820453563
    								

Dates and Times

  • LocalDate

    A LocalDate represents a year-month-day (like '2015-07-14') in the ISO calendar and is useful for representing a date without a time. You might use a LocalDate to track a significant event, such as a birth date or wedding date.

    You can creating new LocalDate instances in different ways:

    // The current date
    LocalDate currentDate = LocalDate.now();
    System.out.println(currentDate);
    
    // 1979-02-15
    LocalDate feb15th = LocalDate.of(1979, Month.FEBRUARY, 15);
    
    
    // Days values start at 1 (2000-09-01)
    LocalDate sept1st = LocalDate.of(2000, 9, 1);
    System.out.println(sept1st);
    
    // The 256th day of 2015
    LocalDate programmerDay = LocalDate.ofYearDay(2015, 256);
    System.out.println(programmerDay);
    								

    output:

    2015-07-14
    1979-02-15
    2000-09-01
    2015-09-13
    								

  • LocalTime

    LocalTime stores a time without a date.

    The LocalTime class is similar to the other classes whose names are prefixed with Local, but deals in time only. This class is useful for representing human-based time of day, such as movie times, or the opening and closing times of the local library.

    LocalTime currentTime = LocalTime.now(); // current time
    System.out.println(currentTime);
    
    LocalTime midday = LocalTime.of(12, 0); // 12:00
    System.out.println(midday);
    
    LocalTime afterMidday = LocalTime.of(13, 30, 45); // 13:30:45
    System.out.println(afterMidday);
    
    // 12345th second of day (03:25:45)
    LocalTime fromSecs = LocalTime.ofSecondOfDay(12345); // (valid values 0 - 86399)
    System.out.println(fromSecs);
    								

    output:

    23:45:41.009
    12:00
    13:30:45
    03:25:45
    								

    The LocalTime class does not store time zone or daylight saving time information.

  • LocalDateTime

    The class that handles both date and time, without a time zone, is LocalDateTime, one of the core classes of the Date/Time API. This class is used to represent date (month-day-year) together with time (hour-minute-second-nanosecond) and is, in effect, a combination of LocalDate with LocalTime. This class can be used to represent a specific event. To include a time zone, you must use a ZonedDateTime or an OffsetDateTime.

    In addition to the now() method that every temporal-based class provides, the LocalDateTime class has various of(...) methods (or methods prefixed with ofXXX) that create an instance of LocalDateTime.

    // Date with time
    LocalDateTime currentDateTime = LocalDateTime.now();
    System.out.println("Current date and time : " + currentDateTime);
    
    // 2015-09-15 10:15
    LocalDateTime sept15th = LocalDateTime.of(2015, 9, 15, 10, 15);
    System.out.println("September 15th : " + sept15th);
    
    // 2015-12-25 12:00
    LocalDateTime christmas2015 = LocalDateTime.of(2015, Month.DECEMBER, 25, 12, 0);
    System.out.println("Christmas 2015 : " + christmas2015);
    								

    output:

    Current date and time : 2015-07-16T20:41:08.634
    September 15th : 2015-09-15T10:15
    Christmas 2015 : 2015-12-25T12:00
    								

  • ZonedDateTime

    The ZonedDateTime class, in effect, combines the LocalDateTime class with the ZoneId class. It is used to represent a full date (year, month, day) and time (hour, minute, second, nanosecond) with a time zone (region/city, such as Europe/Paris).

    ZoneId minsk = ZoneId.ofOffset("GMT", ZoneOffset.ofHours(+3));
    ZoneId berlin = ZoneId.of("Europe/Berlin");
    
    // Current date and time
    LocalDateTime dateTime = LocalDateTime.now();
    System.out.println("Here : " + dateTime);
    
    ZonedDateTime minskDateTime = ZonedDateTime.of(dateTime, minsk);
    System.out.println("Minsk : " + minskDateTime);
    
    // Current date and time in Berlin, Germany
    ZonedDateTime berlinDateTime = minskDateTime.withZoneSameInstant(berlin);
    System.out.println("Berlin : " + berlinDateTime);
    
    								

    output:

    Here : 2015-07-16T23:50:15.516
    Minsk : 2015-07-16T23:50:15.516+03:00[GMT+03:00]
    Berlin : 2015-07-16T22:50:15.516+02:00[Europe/Berlin]
    								

Periods and Durations

Period and Duration are two other important classes. Like the names suggest they represent a quantity or amount of time.

  • Period

    To define an amount of time with date-based values (years, months, days), use the Period class. The Period class provides various get methods, such as getMonths, getDays, and getYears, so that you can extract the amount of time from the period.

    The total period of time is represented by all three units together: months, days, and years. To present the amount of time measured in a single unit of time, such as days, you can use the ChronoUnit.between method.

    The following code reports how old you are, assuming that you were born on September 15, 1974. The Period class is used to determine the time in years, months, and days. The same period, in total days, is determined by using the ChronoUnit.between method and is displayed in parentheses:

    LocalDate today = LocalDate.now();
    LocalDate birthday = LocalDate.of(1974, Month.SEPTEMBER, 15);
    Period p = Period.between(birthday, today);
    long p2 = ChronoUnit.DAYS.between(birthday, today);
    System.out.printf("You are %d years, %d months, and %d days old (%d days total)", p.getYears(), p.getMonths(), p.getDays(), p2);
    								

    The code produces output similar to the following:

    You are 40 years, 10 months, and 3 days old (14916 days total)
    								

    These calculations do not account for time zone differences. If you were, for example, born in Australia, but currently live in Bangalore, this slightly affects the calculation of your exact age. In this situation, use a Period in conjunction with the ZonedDateTime class. When you add a Period to a ZonedDateTime, the time differences are observed.

  • Duration

    A Duration is most suitable in situations that measure machine-based time, such as code that uses an Instant object. A Duration object is measured in seconds or nanoseconds and does not use date-based constructs such as years, months, and days, though the class provides methods that convert to days, hours, and minutes. A Duration can have a negative value, if it is created with an end point that occurs before the start point.

    The following code calculates, in nanoseconds, the duration between two instants:

    // Current time
    Instant now1 = Instant.now();
    
    // Wait __appropximately__ 1 second
    Thread.sleep(1000);
    
    // Current time
    Instant now2 = Instant.now();
    
    // Calculate real duration
    long ns = Duration.between(now1, now2).toNanos();
    System.out.println("Duration (ns) : " + ns);
    								

    output:

    Duration (ns) : 1000000000
    								

    A Duration is not connected to the timeline, in that it does not track time zones or daylight saving time. Adding a Duration equivalent to 1 day to a ZonedDateTime results in exactly 24 hours being added, regardless of daylight saving time or other time differences that might result.

Professional hosting         Free 'Oracle Certified Expert Web Services Developer 6' Guide     Exam 1Z0-810: Upgrade to Java SE 8 Programmer Quiz