Time
Goals
- Understand general concepts of time representation for machines versus for computers.
- Learn about time zones, daylight saving time, and leap years.
- Be able to work with computer time and human time using the Java time library.
- Know how to represent the passing of time.
- Be familiar with legacy date and time handling in Java.
Concepts
- absolute time
- daylight saving time (DST)
- duration
- Greenwich Mean Time (GMT)
- Internet Assigned Numbers Authority (IANA)
- instant
- International Organization for Standardization (ISO)
- local time
- period
- time zone
- timestamp
- Coordinated Universal Time (UTC)
- Zulu Time
Library
java.lang.System.currentTimeMillis()
java.lang.System.nanoTime()
java.time
java.time.Duration
java.time.Duration.ofDays(long days)
java.time.Duration.toMinutes()
java.time.Duration.toDays()
java.time.Instant
java.time.Instant.atZone(ZoneId zone)
java.time.Instant.ofEpochMilli(long epochMilli)
java.time.Instant.parse(CharSequence text)
java.time.Instant.toString()
java.time.LocalDate
java.time.LocalDate.of(int year, int month, int dayOfMonth)
java.time.LocalDate.parse(CharSequence text, DateTimeFormatter formatter)
java.time.LocalDateTime
java.time.LocalTime
java.time.LocalTime.of(int hour, int minute, int second)
java.time.Month
java.time.Month.getValue()
java.time.MonthDay
java.time.Period
java.time.Period.between(LocalDate startDateInclusive, LocalDate endDateExclusive)
java.time.Period.getDays()
java.time.Period.of(int years, int months, int days)
java.time.Period.ofDays(int days)
java.time.Year
java.time.ZonedDateTime
java.time.ZonedDateTime.of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond, ZoneId zone)
java.time.ZonedDateTime.of(LocalDate date, LocalTime time, ZoneId zone)
java.time.ZonedDateTime.plus(TemporalAmount amountToAdd)
java.time.ZonedDateTime.toInstant()
java.time.ZoneId
java.time.ZoneId.of(String zoneId)
java.time.ZoneId.systemDefault()
java.time.ZoneOffset
java.time.ZoneOffset.UTC
java.time.format.DateTimeFormatter
java.time.format.DateDimeFormatter.ISO_INSTANT
java.time.format.DateTimeFormatter.ISO_LOCAL_DATE
java.time.format.DateTimeFormatter.format(TemporalAccessor temporal)
java.time.format.DateTimeFormatter.ofPattern(String pattern)
java.time.format.DateTimeFormatter.withZone(ZoneId zone)
java.time.format.FormatStyle
java.time.temporal
java.time.temporal.Temporal
java.time.temporal.TemporalAccessor
java.text.DateFormat
java.util.Calendar
java.util.Calendar.DAY_OF_WEEK_IN_MONTH
java.util.Calendar.HOUR
java.util.Calendar.YEAR
java.util.Calendar.get(int field)
java.util.Calendar.getInstance()
java.util.Calendar.getInstance(TimeZone zone)
java.util.Calendar.set(int field, int value)
java.util.Calendar.set(int year, int month, int date, int hourOfDay, int minute)
java.util.Calendar.setTimeZone(TimeZone value)
java.util.Date
java.util.Date()
java.util.Date.from(Instant instant)
java.util.Date.getTime()
java.util.Date.setTime(long time)
java.util.Date.toInstant()
java.util.GregorianCalendar
java.util.GregorianCalendar()
java.util.GregorianCalendar(int year, int month, int dayOfMonth)
java.util.TimeZone
Lesson
Time is a concept that is easy to experience but hard to define. Even more difficult is describing time in a computer program. On the face of it describing the passage of time should be simple for a computer, which can keep track of the endless procession of seconds and microseconds without being encumbered with philosophical explanations or human descriptions of time. But this is exactly what causes problems with time when programming: the computer must eventually interact with humans, and the disparate human ways of conceptualizing and describing time can easily cause confusion and mistakes.
Modeling Time
There are several aspects of referring to time, and each has two opposing approaches:
- human time / computer time
- Humans refer to time differently than computers.
- local time / absolute time
- Humans can refer to a local time relative to their time zone, or an absolute time that is same for everyone in the world. Computers by default represent absolute times, but in their own way.
- point in time / passage of time
- Sometimes a program needs to indicate the time when an event occurred or when it will occur; in other circumstances a program may need to describe how long an event lasted.
Human Time
You will likely be most familiar with how humans describe local time by referring to the clock on the wall or the days marked on a calendar. We refer to this as local time because it is only valid in your time zone, one of the 24 divisions of time around the world. Take the date for the New Year as an example, which is January 1. The year begins on January 1 in New York as well as in San Francisco. But because these cities are separated by several time zones, some people in San Francisco will still be having dinner when they see people on New York celebrating the new year on television.
A typical clock only tells local time as well. The New Year parade in New York may begin at noon, or 12:00 p.m. But people in San Francisco will see the parade on their televisions when clocks in California indicate only 9:00 a.m. To remove ambiguity, we can indicate a time zone to indicate an absolute time.
Time zones are politically-defined geographic regions that determine the time around the world. The time within any particular time zone is the same throughout the zone, and can be measured by an offset from Coordinated Universal Time (UTC), an international standard based on the time at 0° longitude. Because 0° longitude goes through Greenwich, a predecessor to UTC was named Greenwich Mean Time (GMT). UTC is sometimes represented by a Z
for zero
. You may even here UTC referred to as Zulu Time, as Zulu
is the international phonetic spelling of Z
.
Even with a time zone designation, however, the absolute time in human terms is complicated by daylight saving time (DST), in which a country or an area of a country changes the time forward or backwards during different seasons. (UTC is independent of DST.) To identify the time zones independent of their offsets from UTC, the Internet Assigned Numbers Authority (IANA) has assigned a unique name for each region in its Time Zone Database
. For example the IANA TZ identifizer for the region commonly known as Pacific Time
is America/Los_Angeles
; during the winter it has the offset -08:00
, while during the summer it has the offset -07:00
.
Calculating how much time has passed between two absolute times can become quite difficult, as some designated times may never have existed within a time zone. If a state advances an hour for DST at midnight, for example, the clock completely skips 12:30 a.m.! The IANA Time Zone Database maintains historical DST and other changes, allowing the the time in each time zone to be calculated in the past.
Computer Time
The computer avoids many of the problems imposed by the strange customs of humans by conceptualizing time as a series of seconds endlessly marching on from some starting point. The starting point or epoch used by most computer systems is midnight on January 1, 1970 in UTC. Thus every event can be identified as a number that is independent of any time zone. Many computers track the number of milliseconds that have passed since the epoch.
TODO provide some Instant examples in human time and computer time
ISO 8601
The standard that governs time representation around the world is ISO 8601: Data elements and interchange formats — Information interchange — Representation of dates and times. This document is put out by the International Organization for Standardization (ISO), and prescribes various format for representing dates and times. One of the most most common is the representation for a date and time of day, with an included offset from UTC, such as 1985-04-12T10:15:30+04:00
.
Beyond the specific syntax, however, ISO 8601 is based on a certain conception of dates and times. Dates are based on the Gregorian calendar, and rules are introduced for representing dates before the institution of the Gregorian calendar in 1875. Week numbers and day ordinals are fixed, and definitions are put into place regarding time scales and leap years. Thus many time library implementations rely not only on ISO 8601 for how time should be represented as text, but also for its basic model of time representation.
Representing Time
The latest versions of Java provide built-in libraries for tracking time, located in the java.time
package. Lower-level time processing classes may be found in the java.time.temporal
subpackage including the java.time.temporal.Temporal
interface that underlies most of the Java time-related types, and an even lower-level interface java.time.temporal.TemporalAccessor
which allows access to individual fields of time classes. The time classes represent value objects, which you have studied. You can therefore expect the time classes to be immutable to be comparable with equals(…)
, and to include static factory methods typically named of(…)
.
Local and Zoned Time
Representing a general date date or time, not tied to any time zone, is accomplished using the java.time.LocalDate
and java.time.LocalTime
classes. These types correspond to the date marked on a calendar or the time displayed on a clock, respectively. These classes represent immutable value types, so it is no surprise that they provide many static factory methods including LocalDate.of(int year, int month, int dayOfMonth)
and LocalTime.of(int hour, int minute, int second)
. The local date and time classes provide a variety of static factory methods, including some that use the java.time.Month
enum.
java.time.LocalDate
- A general year, month, and day not fixed to any time zone.
java.time.MonthDay
- A month and a day not fixed to any time zone or even associated with a particular year.
java.time.Month
- A single month of the year.
java.time.Year
- A year without regard to any time zone.
java.time.LocalTime
- A general time not associated with any particular date nor fixed to any time zone.
java.time.LocalDateTime
- A combined date and time not fixed to any time zone.
Local dates and times are relative or floating
; they do not provide sufficient information to determine precisely when an event occurred or will occur. Recording the date and time of a birth, for instance, must include the time zone. A journal entry as well would normally indicate the time zone in order to fix the exact moment in an absolute way worldwide: December 11, 2016 10:53 a.m. America/Los Angeles
.
The zoned time classes keep track of a time zone in addition to their other time components, and thus are able to represent absolute times in history. To represent the time zone itself Java provides the class java.time.ZoneId
. You can create a ZoneId
using its static factory method ZoneId.of(String zoneId)
with the identifier from the IANA Time Zone Database, such as ZoneId.of("Europe/Paris")
. The current time zone of the system can be found using ZoneId.systemDefault()
.
The main zoned time class is java.time.ZonedDateTime
, which is essentially a LocalDateTime
combined with a ZoneId
. It can be created using all its components using the static factory method ZonedDateTime.of(int year, int month, int dayOfMonth, int hour, int minute, int second, int nanoOfSecond, ZoneId zone)
. There exist various other static factory methods, including one from an existing LocalDate
, and LocalTime
, with the addition of a time zone using ZonedDateTime.of(LocalDate date, LocalTime time, ZoneId zone)
.
java.time.ZoneId
- Identifies a time zone from the IANA Time Zone Database.
java.time.ZonedDateTime
- Represents an absolute date and time in a particular time zone.
Instances
The number of ticks on a computer that marks some single, absolute, instantaneous point in time is referred to as an instant. In applications an instance is The java.time.Instant
class keeps track of time down to the nanosecond, although it is more typical to create an Instant
from the number of milliseconds past the epoch using Instant.ofEpochMilli(long epochMilli)
, as milliseconds past the epoch is the traditional record of Java time. You can also create an instant from one of the human time classes with time zone information such as ZonedDateTime.toInstant()
. You can produce a human time representation by providing the Instant
with a time zone using Instant.atZone(ZoneId zone)
.
Periods and Durations
Calculating the number of days from January 1 to July 1 for an arbitrary year might seem simple until you recall that leap years must be taken into account. Measuring the number of hours between Friday and Tuesday for some arbitrary dates might seem an easy thing to do until you remember that, depending on time zone, daylight savings might have come into effect depending on the date, robbing an hour from the result. Just as there is a human approach and a computer approach to representing points in time, Java provides two separate approaches for measuring the passage of time: a period for the passage of human calendar days, and a duration for calculating the time difference between two instants.
java.time.Period
- Measures a difference based on human dates: calendar days, months, and years.
java.time.Duration
- Measures the amount of of computer time that passes.
A Period
can be created using the static factory method Period.between(LocalDate startDateInclusive, LocalDate endDateExclusive)
. You can also create periods from a certain number of days, months, weeks, or years, using for example Period.of(int years, int months, int days)
or Period.ofDays(int days)
. After getting a Period
, you can get the number of days or months that have passed, such as with Period.getDays()
.
A Duration
on the other hand is a more general, computer-oriented designation of time passing, and can be created from various types of points in time using Duration.between(Temporal startInclusive, Temporal endExclusive)
. A Duration
can also be created from a number of seconds/milliseconds/nanoseconds, minutes, hours, or days, using for example Duration.ofDays(long days)
. Once you have a Duration
, you can calculate the passage of time using for example Duration.toMinutes()
or Duration.toDays()
. The days and other times given by a Duration are standardized times and will not take into account leap seconds or calendar-time concepts such as DST.
Time Formats
Java provides the java.time.format.DateTimeFormatter
class both for creating and for parsing text-based representations of time. A DateTimeFormatter
is created from a pattern; once created, it is immutable and can be as often as needed, even from multiple threads of execution.
Predefined Formats
There are several predefined formatters that you use, most of them for creating ISO 8601 based representations (hence the word ISO
in the names). One of the most useful of these is DateDimeFormatter.ISO_INSTANT
, which provides an ISO 8601 compliant way to represent a timestamp for storage and later retrieval. Some of these formatters are ISO-like
, and include elements that are not part of ISO 8601; check the API documentation before using them.
DateTimeFormatter
s (DateTimeFormatter
API)Formatter | Description | Example |
---|---|---|
DateTimeFormatter.BASIC_ISO_DATE | Basic ISO date | "20111203" |
DateTimeFormatter.ISO_LOCAL_DATE | ISO Local Date | "2011-12-03" |
DateTimeFormatter.ISO_OFFSET_DATE | ISO Date with offset | "2011-12-03+01:00" |
DateTimeFormatter.ISO_DATE | ISO Date with or without offset | "2011-12-03+01:00" , "2011-12-03" |
DateTimeFormatter.ISO_LOCAL_TIME | Time without offset | "10:15:30" |
DateTimeFormatter.ISO_OFFSET_TIME | Time with offset | "10:15:30+01:00" |
DateTimeFormatter.ISO_TIME | Time with or without offset | "10:15:30+01:00" , "10:15:30" |
DateTimeFormatter.ISO_LOCAL_DATE_TIME | ISO Local Date and Time | "2011-12-03T10:15:30" |
DateTimeFormatter.ISO_OFFSET_DATE_TIME | Date Time with Offset | "2011-12-03T10:15:30+01:00" |
DateTimeFormatter.ISO_ZONED_DATE_TIME | Zoned Date Time | "2011-12-03T10:15:30+01:00[Europe/Paris]" |
DateTimeFormatter.ISO_DATE_TIME | Date and time with ZoneId | "2011-12-03T10:15:30+01:00[Europe/Paris]" |
DateTimeFormatter.ISO_ORDINAL_DATE | Year and day of year | "2012-337" |
DateTimeFormatter.ISO_WEEK_DATE | Year and Week | "2012-W48-6" |
DateTimeFormatter.ISO_INSTANT | Date and Time of an Instant | "2011-12-03T10:15:30Z" |
DateTimeFormatter.RFC_1123_DATE_TIME | RFC 1123 / RFC 822 | "Tue, 3 Jun 2008 11:05:30 GMT" |
Formatting
Formatting is performed using DateTimeFormatter.format(TemporalAccessor temporal)
, as shown in this example using DateTimeFormatter.ISO_LOCAL_DATE
:
If you wish to show the time in a different time zone (for those formats that support time zones), you can create a new DateTimeFormatter
using the fluent method DateTimeFormatter.withZone(ZoneId zone)
. The new DateTimeFormatter
will show the time in the requested zone, but the time value being formatted not be changed. The following example shows how to determine the date in Paris at the exact time a person was born in New York, using the DateTimeFormatter.ISO_LOCAL_DATE
formatter and DateTimeFormatter.withZone(…)
. Note that although the birth occurred on May 30 in the America/New_York
time zone, because of the time difference it was already May 31 in the Europe/Paris
time zone.
Parsing
Parsing is most easily done through a static factory parse(CharSequence text, DateTimeFormatter formatter)
method of the type you want to create for producing an instance of the time class based upon a text-based representation. For example to parse an ISO 8601 representation of a date back into a LocalDate
instance, you could use LocalDate.parse(CharSequence text, DateTimeFormatter formatter)
.
Localized Formats
When displaying dates to the user, or parsing dates entered by the user, instead of using one of the ISO 8601 representations you will likely prefer to show the date in the format expected for the user's region. For example a user in the United States might be accustomed to writing the date as 5/30/80
or May 30, 1980
, while a user in Brazil might expect to use 30/05/80
or 30 de Maio de 1980
. Java provides several static factory methods to create a localized
DateTimeFormatter
appropriate for the user expectations of your system's region.
DateTimeFormatter
s (DateTimeFormatter
API)Formatter | Description | Example |
---|---|---|
DateTimeFormatter.ofLocalizedDate(dateStyle) | Formatter with date style from the locale | "2011-12-03" |
DateTimeFormatter.ofLocalizedTime(timeStyle) | Formatter with time style from the locale | "10:15:30" |
DateTimeFormatter.ofLocalizedDateTime(dateTimeStyle) | Formatter with a style for date and time from the locale | "3 Jun 2008 11:05:30" |
DateTimeFormatter.ofLocalizedDateTime(dateStyle,timeStyle) | Formatter with date and time styles from the locale | "3 Jun 2008 11:05" |
To create one of these localized formats, provide a java.time.format.FormatStyle
enum value specifying the style of the date and/or time portion of the string. You can use the FormatStyle
values as you would any other value object constants.
DateTimeFormatter
s (FormatStyle
API)Format Style | Description | Example |
---|---|---|
FormatStyle.FULL | Representation including the most detail. | "Wednesday, December 14, 2016 8:10:19 AM PST" |
FormatStyle.LONG | Representation including much detail. | "December 14, 2016 8:10:19 AM PST" |
FormatStyle.MEDIUM | Representation including fewer details. | "Dec 14, 2016 8:10:19 AM" |
FormatStyle.SHORT | Mostly numeric representation. | "12/14/16 8:10 AM" |
Legacy
The date and time classes presented in this lesson are reasonably elegant and reasonably complete. But they weren't always part of Java; they were only added relatively recently after development under JSR 310: Date and Time API. In fact most Java code you come in contact with will likely be using one of the legacy approaches to timekeeping, so it is valuable to have an idea of the alternatives and how they interact with the new Java approach to time.
System.currentTimeMillis()
Java's most primitive representation of time is that shared by many computer systems: a record of the number of milliseconds that has passed since the epoch on midnight, January 1, 1970 UTC. This long
value marks passage of computer time, and can be retrieved using java.lang.System.currentTimeMillis()
.
Date
The java.util.Date
class is conceptually little more than a wrapper around some value produced by System.currentTimeMillis()
; a frozen system time, analogous to an Instant
. Calling the no-parameter constructor Date()
in fact will create a date with the current value of System.currentTimeMillis()
, and Date.getTime()
allows you to retrieve this value. But Date
has several very large drawbacks:
Date
is not a value object—it is mutable! Because it allows the represented number of milliseconds to be updated usingDate.setTime(long time)
, you can never be sure that yourDate
instance has not been modified elsewhere in the program.Date
doesn't separate well the concepts of computer time versus human time. It providing methods for accessing component of the time in human terms such as year and month. The human time accessor methods inDate
have since been deprecated.- Some of the date units (e.g. month) are represented as zero-based, and others as one-based.
For these reasons you should not use Date
except as necessary for interacting with legacy code.
Calendar
To address some of the shortcomings in Date
, Java introduced the java.util.Calendar
abstract class. Calendar
, like Date
, is also a wrapper around a system time in milliseconds. The difference is that Calendar
allows more robust manipulation of human time concepts such as dates and time zones. A Calendar is not that much different from your computer's operating system: internally it represents some absolute system time in milliseconds, yet its interface allows access of human time components based upon its current time zone.
The specific rules for working with calendar dates and times depend on which Calendar
subclass is used. The most common subclass java.util.GregorianCalendar
, which represents the calendar in use in ares around the world, and more or less agrees with ISO 8601. You can create an instance of the appropriate subclass of Calendar
for your region, representing your current time zone, using Calendar.getInstance()
.
You can get individual components of human time using Calendar.get(int field)
, providing a field constant such as Calendar.HOUR
, Calendar.YEAR
, or even Calendar.DAY_OF_WEEK_IN_MONTH
. You can also update the calendar time using Calendar.set(int field, int value)
with one of the same fields. You can set several fields at the same time using one of the convenience setters that take certain predefined fields such as Calendar.set(int year, int month, int date, int hourOfDay, int minute)
.
Time zones are represented by the legacy class java.util.TimeZone
. You can get a Calendar
for a particular time zone using Calendar.getInstance(TimeZone zone)
. The complementary method Calendar.setTimeZone(TimeZone value)
will change the Calendar
's time zone.
Joda-Time
The Jode-Time library was created to address the deficiencies of Java's Date
and Calendar
classes. For many years before JSR 310 was available Java developers needing more sophisticated and/or easier date and time handling increasingly opted to abandon the legacy classes and instead use Jode-Time. With the introduction of JSR 310 there is no longer any need for Joda Time, and any programs using that library should migrate to the new Java time handling API.
Review
Summary
TODO
Gotchas
- Don't use
Month.ordinal()
, which is zero-based, to get a month value to pass to a static factory method, which expect one-based month values; useMonth.getValue()
instead. - Some of the
DateTimeFormatter
predefined formats include elements that are not part of theISO 8601
standard and are not interoperable with other systems. System.nanoTime()
is not simply a more precise version of system time thanSystem.currentTimeMillis()
. Rather it uses an arbitrary starting point, and is only useful for measure the passage of time.- Avoid the
java.text.DateFormat
class; its name is similar to that ofDateTimeFormatter
, but it is an outdated class that should only be used with legacy code.
In the Real World
- Most existing Java code still uses the legacy
Date
class. New code should use the non-legacy Java date and time classes presented in this lesson.
Think About It
- TODO provide some tips and example about determining which time type to use
Self Evaluation
- What is the
epoch
in a computer's conception of time, and what is the most common epoch used?
Task
In your value object for a publication's range of years for first published
date, you likely represented the year as an int
or an Integer
. Upgrade your range value class to use the java.time.Year
class to represent each of the years in the range. Do not allow either of the years to be null
; if the range consists a single year, simply use the same year for ends of the range (assuming your range end is inclusive).
When Booker starts, display the current time and date in an easily readable format using the user's current time zone.
Once Booker has completed performing its functionality, before exiting print a user-friendly message indicating how long the operations took in total, measured from the time Booker started executing.
- If more than
1000ms
passed, display the time in no finer granularity than seconds. - You may show minutes or higher granularity if you wish, if appropriate.
The CURRENT_YEAR
constant makes Booker brittle. It requires the program to be recompiled every year or it will become inaccurate. Rather than use a CURRENT_YEAR
constant, use the Java time library to determine the current year dynamically each time you do the comparison.
- Make a note in the comments that this is still not an ideal situation, because it does not account for books that are being entered into the system that have not yet been published.
See Also
- Trail: Date Time (Oracle - The Java™ Tutorials)
- Date and Time Classes (Oracle - The Java™ Tutorials)
- About
timezone
(Stack Overflow) - Instant Class (Oracle - The Java™ Tutorials)
- Period and Duration (Oracle - The Java™ Tutorials)
- Parsing and Formatting (Oracle - The Java™ Tutorials)
- Date and Time Formats (W3C)
References
Resources
Acknowledgments
- Calendar and clock icons used from KDE Oxygen Icons licensed under the GNU LGPL 3.
- Time zones photo by TimeZonesBoy (Own work) [CC BY-SA 4.0], via Wikimedia Commons.
- Some symbols are from Font Awesome by Dave Gandy.