This document contains guidelines and best practices for working with time and time zones in applications and document formats. Use cases are provided to help choose an approach that ensures that geographically distributed applications work well with date and time values. This document also aims to provide a basic understanding and vocabulary for talking about time and time handling in software, a source of confusion for many developers and content authors on the Web.
We welcome comments on this document, but to make it easier to track them, please raise separate issues for each comment, and point to the section you are commenting on using a URL.
This document is based on several previous documents. The original Working Group Note (Working With Timezones) was by Martin Dürst, Mark Davis, Felix Sasaki, and Addison Phillips. A later revision was written by Martin Dürst, Mark Davis, Felix Sasaki, Richard Ishida, and Addison Phillips. Sections [[[#history]]] and [[[#what-is-time-zone]]] were adapted from an article and later a Unicode conference presentation (Time Out of Joint) by Addison Phillips. Information on time zone scenarios is based on work by Norbert Lindenberg. Information about temporal serializations and use cases is based on work by CJ Butenhoff.
One common requirement for applications is the need to deal with dates, times, or durations. Working with time-related data can be complex because values are related to calendars and timekeeping rules, which themselves can be somewhat arcane. One of these complexities in working with time-related data is the effect of time zone on the handling and presentation of the data.
This document contains guidelines and best practices for working with date and time values, including time zones, in applications and document formats. Use cases are provided to help choose an approach that ensures that geographically distributed applications work well with date and time values. This document also aims to provide a basic understanding and vocabulary for talking about time, a source of confusion for many developers and content authors on the Web.
Working with date and time values, including the effect of time zones on the display and processing of these values, can be confusing. By understanding how date and time values work and how to manage these values in applications or specify them in standards, you can prevent many problems.
When working with date and time values, the time zone, the locale, and your choices for encoding, handling, and processing date and time values can produce different and perhaps unexpected or unwanted results. Some examples of errors due to improper date/time handling might include the items listed below. Reading the best practices and guidelines in this document can help you create specifications, designs, or implementations that avoid errors when working with time values.
This section provides the basic concepts, terminology, and background for those unfamiliar with the origins, processing, and representation of date and time values in modern computer systems.
These definitions are useful in understanding date/time values.
Chronology or calendar A timekeeping system used to organize dates and times.
Many different chronologies and calendars have been used or are in use today around the world. These different systems have varying rules for organizing and dividing time values.
ISO Chronology is based on the [[ISO8601]] standard, which is the de facto world calendar. This system uses a proleptic Gregorian calendar.
A proleptic calendar is a calendar that applies modern rules to all times in the past, as if the calendar were observed at that time.
For example, the Gregorian calendar was created in 1582 CE, but not adopted universally, even by countries observing the Julian calendar. A proleptic Gregorian calendar (and thus, by extension, the ISO Chronology) applies year numbers, leap years, and dating for dates in the past, even when that would be inappropriate historically.
Observed Time A moment in time based on an observed event or events. For example, "local noon", the shortest day or the year, or the first new moon.
Wall Time A date or time value as experienced by human beings, so called because the value might be what is shown on a paper calendar or analog clock mounted on the wall in a given location at a given moment.
Epoch A specific moment in time that serves as a reference point for a given chronology. The most common epoch is the Unix Epoch, which is used by the most common computer timekeeping systems and measures incremental time values from midnight, January 1, 1970 in the UTC time zone, i.e. from 1970-01-01T00:00:00.000Z
Era A grouping within a calendar used to number years. Most eras start with year "1" and count up to the start of the next era. There are some exceptions to this: the Gregorian calendar's era "BCE" counts backwards, with 1 BCE being the year just before 1 CE (1 AD).
Ghost time A wall time that can never exist because of time zone or calendar rules. For example, the date `2023-02-29` is a "ghost time" because 2023 is not a leap year in the Gregorian calendar. Similarly, in the `America/Los_Angeles` time zone, the wall time `2:34 a.m.` on the date `2024-03-10` is a "ghost time" because, due to daylight-savings time, the clock skips from `1:59 a.m.` directly to `3:00 a.m.`.
Timeline In a given chronology, the fixed sequence of moments, measured against the epoch. A datetime value is said to be on the timeline if it is attached to a discrete moment in time. This is a hallmark of incremental time values.
Incremental Time A datetime value consisting of monotonically increasing integer units measured from a specific moment in time (which is called the epoch). For example, the moment 1970-01-02T00:00:00.000Z
in the ISO Chronology might have an incremental time value (measured in milliseconds) of 86400000
, since there are 86,400 seconds in a day and 1000 ms in a second.
Field-based Time A datetime value that stores the time value in separate fields (era, year, month, day, hour, minute, second, millisecond, etc.)
Floating Time Any date or time value that is not fixed to a specific incremental time value or time zone. Also called a local or plain date or time value.
Instant An incremental time in the Unix epoch. An instant can be converted for display in any calendar and/or time zone and any two instants can be ordered in time.
Universal Coordinated Time or UTC is the basis for modern timekeeping. Among other things, it provides a common baseline for converting between incremental and wall time. UTC is also known as GMT (Greenwich Mean Time). There are some subtle differences between the two, but none that the average person would notice. The time zone offset for UTC is 0
. UTC is often indicated in field-based formats using Z
.
Local Time Offset The different (positive or negative) of a given location from UTC. This is usually expressed as an offset in hours and minutes, such as +10:00
or -09:30
.
Daylight Savings Time Also called summer time or daylight time and abbreviated DST. The practice of advancing clocks to make better use of longer periods of daylight during the summer, so that darkness falls at a later [=wall time=]. Rules around observation (or non-observation) of DST is one feature of a time zone.
Computer systems tell time differently than people do. So it is helpful to understand how time works within computers as well as in the real world in order to get a handle on how to get the results that you want. This description is necessarily simplified.
Timekeeping has its roots in observable celestial events, such as sunrise, sunset, the longest/shortest day of the year, the phases of the moon, or the position of the constellations. This is called observed time and underpins the various customary systems for measuring time.
Conventions have been established by various cultures to organize time into more convenient units. For example, days are broken up into arbitrary units such as hours, minutes, and seconds or grouped together to form weeks. Years are broken up into months. They are also numbered starting from significant events or organized into eras. Each unique cultural system for organizing time forms a calendar or chronology.
Gradually, over time, most chronologies have weakened or sometimes removed some of the ties to the original observational basis for events. For example, the Gregorian calendar's months do not correspond to the lunar cycle. Other calendars retain stronger linkages to specific celestial events. For example, most Islamic calendars use actual solar or lunar observations to determine the start of specific periods or months.
Mechanical timekeeping allows for more precision and standardization in counting or measuring events. We refer to the dates and times experienced in a given location as wall time because the date or time can be read from a printed calendar or a clock mounted on the wall.
The advent of speed-of-light communication (such as the telegraph) and efficient means of travel (such as railroads) meant that timekeeping based on local observations (such as "local noon") became inconvenient: it is difficult to manage schedules when each locality keeps its own clock! Even relatively small travel distances produce measurable differences in observed time. As a result, synchronization of different regions that observe the same calendar and wall time became necessary, resulting in the advent of time zones.
Observed time has many disadvantages computationally. Observed events are not always predictable or convenient to use. The advent of mechanical timekeeping has allowed a different kind of time to flourish: incremental time based on a monotonic progression of fixed units. In some cases, incremental time is merely a prediction of when an event might be observed.
The modern standardized system of timekeeping in computer systems is generally based on a few core standards. Universal Coordinated Time (or "UTC"), adopted in 1972 CE, is used for global synchronization of clocks and to define local time zone variations. Many systems set computer clocks using the UNIX epoch (counting time from January 1, 1970 in UTC). Standards such as [[ISO8601]] or [[RFC3339]] provide serialization schemes for the interchange of date and time values and most programming languagues or data formats provide data structures for storing or exchanging date and time values. These types of systems are usually based on the ISO Chronology (also known as the Gregorian calendar), although they can be converted to other systems, such as the one of the Islamic calendars, the Ethiopic or Chinese solar-lunar calendars, and so forth.
A time zone is a set of rules for determining the local observed time (wall time) as it relates to incremental time (as used in most computing systems) for a particular geographical region.
Before the adoption of time zones, local time was derived directly from observation. Clocks might be set, for example, based on an observed event such as local noon. Traveling fairly short distances across the Earth's surface results in changes in local observed time: you only have to travel about 28 kilometers (17 miles) at the equator (and less distance the further north or south of the equator you are) to alter the observed local noon by one minute.
Time zones were originated in several countries by railroad operators. Before time zones were instituted, it was difficult know when trains would arrive or depart because local wall time might vary significantly from one station to another. This also made it difficult to schedule traffic across the rail network.
Railroads solved this problem by adopting fixed regions in which the same local time was used throughout. These "time zones" were intended to be about one observed hour wide: the local time in the middle of the time zone was used throughout the region so that the most observational deviation most people would see was about half an hour (and, assuming the population is evenly distributed, most people experienced a smaller deviation). This is a value small enough that most people won't notice the difference between actual and observed time.
In the modern era, most countries have a single time zone, but a number of larger or more geographically distributed countries have more than one.
The concept of "Daylight Saving Time" (DST) or "Summer Time" is used as a way of allowing people more sunlight hours in the evening. Not all regions observe summer time: usually those nearer the equator do not need it. Whether summer time is observed and how it is observed varies by jurisdiction.
As the name implies, areas that use some form of "summer time" do so in the summer season. That is, they change their UTC offset forward (usually by one hour) sometime in the spring and the reverse when the observation of summer time ends in the autumn. Since "spring" and "autumn" happen in opposite parts of the year in the northern and southern hemispheres, the starting and ending days are different for time zones in opposite hemispheres.
Observation (or non-observation) of summer time is controlled by national, regional, and sometimes local governments. Regions that otherwise share a UTC offset, even those with similar latitude (or shared borders) can have differing summer time start or stop rules. Sometimes local authorities will make one-time changes to accommodate a special event (such as when hosting the Olympics). Governments sometimes change whether summer time is observed as well as changing when summer time begins or ends.
While other schemes exist, many applications use the IANA Time Zone Database [[BCP175]] and its associated set of identifiers to define time zones.
Time zones are defined by these considerations:
Local Time Offset Time zones are used to compute the offset of wall time from UTC. The local time offset is the difference (positive or negative) between when a given time event is observed in UTC and local time. If all time zones used one-hour offsets, there would be 24 world-wide time zones, ranging between 12 hours before UTC to 11 hours following UTC. However, there are some that use half-hour or even quarter-hour offsets (or even some odd offsets). In addition, some time zones fall outside a single 24-hour span.
Observation of summer time Some times zones include rules for observing daylight-savings or summer time, while others do not. The observation of summer time is defined by a set of rules that include:
Adoption Dates Regions that currently have a specific local time offset and summer time behavior may have had different rules in the past (or plan to adopt new rules in the near future). Correct handling of past time values requires treating such regions as separate time zones.
The most definitive reference for identifying sets of time zone rules is the IANA Timezone Database [[BCP175]], which is used by systems such as various Linux distributions, Java, CLDR, ICU, and many other systems and libraries. Other systems exist: for example, Microsoft Windows uses its own data set and identifiers.
In the TZ database, time zones are given IDs that usually consist of a region and exemplar city. Regions can be continents (such as Europe or America) or oceans (such as Atlantic or Pacific). An exemplar city is a city in the time zone in question that should be well-known to people using the time zone. The TZ database also supplies aliases for many IDs; for example, Asia/Ulan Bator is equivalent to Asia/Ulaanbaatar. The Common Locale Data Repository [[CLDR]] can be used to provide a localized form for the IDs: see Appendix J in [[UAX35]]. Note: some systems, such as Apple Inc.'s MacOS, provide additional exemplar cities.
Specify the use of IANA time zone IDs in standards, protocols, or document formats as the identifier for time zones.
Avoid special purpose time zone IDs, such as those beginning with Etc/.
Use continent/city
IDs in preference to legacy zone IDs such as those starting with US/.
Most countries are either small enough in area or, for practical reasons, choose to observe only a single time zone for the entire country. This means that knowing the region or country of the user is frequently sufficient to identify the time zone of the user as well. At the time this document was published, only twenty countries had more than one observed time zone. These countries are: Argentina, Australia, Brazil, Canada, Chile, Democratic Republic of the Congo, Ecuador, France, Greenland, Indonesia, Kazakhstan, Kiribati, Mexico, Micronesia, Mongolia, New Zealand, Portugal, Russia, Spain, and the United States.
Some special cases exist within this list:
Within each of the countries that observe multiple time zones, knowing the current offset and current time will usually allow you to determine the time zone accurately. An exception to this is the United States: there exist some regions, such as Arizona, whose time zone cannot be determined strictly from the current time, country/region code, and offset, although an inferred time zone will always work for current time applications (not future and past times).
Time zones, their rules, offsets, and observation (or non-observation) of summer time are controlled by a variety of international agreements, as well as national, regional, sub-national, and local governments. This can mean that neighboring areas that might otherwise share a UTC offset, even those with similar latitude (or shared borders) can have differing rules, such as those governing daylight-savings. Sometimes local authorities will change the boundaries of a zone or the offset used by a given region. Or they can make one-time changes to accommodate a special event (such as when hosting the Olympics). The time zone database tracks past changes so that applications can accurately compute wall time for past and future events.
Because there are many governing bodies acting independently, the time zone database is not stabilized. New rule changes or updates to historical records are introduced into the database as they are made known (such as due to legislative action). There is no specific release cycle: updates can happen at any time. When changes affect future events, computing systems have to be updated lest their clocks show the wrong local time for a given region or compute the wrong results for events affected by the change.
There are several ways to represent time data, which vary in suitability according to an application needs.
Incremental time measures time using fixed integer units that increase monotonically from a specific point in time called the [=epoch=]. Most programming languages and operating environments provide data types and APIs that use incremental time to represent or operate on datetime values. Incremental time is not usually seen directly by users. Instead, the incremental time value is formatted into a familiar wall time representation for human consumption.
The most common form of [=incremental time=] is counted in milliseconds (or, occasionally, nanoseconds) in the Unix Epoch. In this system, the value 0
represents midnight, January 1, 1970 in the UTC time zone. Negative numbers represent datetime values earlier than this moment, while positive numbers denote later moments in time. The [[ISO8601]] representation of this would be 1970-01-01T00:00:00.000Z
. Examples of this form of incremental time include:
java.util.Date
time_t
Date
Since incremental time values are just integers, any two incremental time values can be put into order as a sequence of events just by comparing the values. That is, every incremental time value can be put on a timeline.
This also means that incremental datetime values are indepedent of (and generally do not encode) their originating time zone. This is because the monotonic time in the Unix [=Epoch=] is the same everywhere at any given instant. Each incremental time value can be transformed for display using various [=chronologies=], time zone rules or, [=local time offsets=].
Not all incremental time values are tied to specific epoch. A system's clock might be counting from the last time the hardware clock was restarted or some other event. Date values close to January 1, 1970 are often due to an incremental time value of 0 or due to malfunctions in or failure to set the system clock.
A field-based time divides [=wall time=] into separate field values such as year, month, day, hour, minute, second, etc. Field-based times may or may not be tied to either UTC or the local time zone—or may be indeterminate. Field-based times are also typically tied to a specific calendar (such as the Gregorian calendar). The formats described by the [[ISO8601]] standard are field-based.
Some [=field-based time=] values are on the [=timeline=] (that is, "zone-dependent" values) while others are [=floating time=] values. It's important to distinguish between these two when working with [=field-based time=] to avoid inappropriate conversion of the value.
A field-based time may or may not include information about the time zone being used. In a purely numeric representation, such as time_t
, sometimes only the current UTC offset is provided.
A floating time is a date or time value in a calendar that is not a specific instant in time. Applications and data formats use a floating time value when the wall time is more important to the value than putting the event onto a timeline. Generally, a floating time value will include only the date (2024-01-27
) or only the time (13:00:00
), but datetime values (2024-01-27T13:00:00.000
) are sometimes also needed.
[=Floating time=] values are used when a given value's local [=wall time=] expression needs to stay constant, regardless of the viewing user's time zone. For example, if your birthdate were June 1, 1980 this might be represented as the [=floating time=] 1980-06-01
. It does not matter if you view this date in Tokyo, London, or San Francisco: you always want the displayed value to remain constant. Time values that float can include things such as hours of operation as a policy, rather than for a specific location.
Floating time values are often serialized in various ISO8601 formats by omitting the [=local time offset=] (or time zone identifier, such as Z
for [=UTC=]). Data types for floating time values are less common in programming languages and operating environments. Errors are often the result when a floating time value is deserialized into into an [=incremental time=] type, which ties the value to UTC.
Sometimes a producer will emit a floating time value when the consumer expects or requires an incremental time value. In other cases, a consumer might need to convert a local or otherwise incremental time value into a floating date or time.
To float a date or time value means to remove an incremental time value from the timeline by deleting any associated time zone and zone offset information from the value.
One common reason to float a value is if the data type used to collect or process the value is an incremental type (such as an `Instant` or Javascript `Date`) but the value isn't. For example, if you received a user's birth date as a `Date` object. Removing the time zone or offset makes it easier to format the value later without the field values changing incorrectly.
To unfloat a date or time value means to attach a floating time value to the timeline by adding a time zone or zone offset to the value.
One common reason to unfloat a value is that the serialized value might not contain an offset but the value needs to be compared to other incremental values or displayed to the user in local time.
Values received without a time zone or zone offset SHOULD generally be treated as if they are in UTC. Specifications SHOULD provide guidance on how to handle these values. Implementations MAY use some other value for the offset, such as the user agent's local time zone, but only if there is a good reason to do so.
Conversion between or operation on data sets that mix values with and without time zones or [=zone offsets=] presents certain problems. If one wishes to write a comparison between the value of a [=floating time=] value and a non-floating value, then the two values have to be reconciled to us the same reference point on the [=timeline=].
It is good practice to use a time zone identifier or at least an explicit zone offset wherever possible. If one is not available, use UTC as the implicit zone offset for conversions of this nature. This is because the values are exactly centered in the range of possibilities and because representation internally (as computer time) is usually based on UTC. Since a single reference point has been used it might be possible to unwind the change later even if an erroneous conversion has taken place. When working with multiple documents from various sources, the "implicit" offset of the document may vary widely from that of the implementation doing the processing. If UTC is widely used, the chances of error are reduced.
Content and query authors are warned that comparing or processing data sets that contain both date and time values with and without time zones or zone offsets may produce odd results. Such processing should be avoided whenever possible. Generating content that omits zone offset information (where it exists) is a recipe for errors later. Of course, data such as the SQL types cited earlier and which are meant to represent wall time, should continue to omit the zone offset. Query writers can check for the presence (or absence) of zone offset and should do so to modify dates and times explicitly (instead of allowing implicit conversion) whenever possible.
When comparing [=floating times=] to [=incremental times=], use UTC as the time zone.
[=Incremental time=] and [=field-based time=] differ in the way certain operations work. For example, incremental times can often be directly compared: their integer values determine which is earlier or later. [=Field-based times=] have to be normalized and their individual fields compared.
[=Field-based times=] are often optimized to allow for various kinds of adjustments to be made to a value while minimizing the chances for error. For example, to set the date 2005-08-30
forward by one day, an implementation can add 'one unit' to the "day" field and adjust the day, month, and year fields as appropriate to the calendar system. In incremental time, a similar operation might be performed by incrementing the value by 24 hours * 60 minutes * 60 seconds * 1000 milliseconds
, which is one "logical day". However, there can be errors when a particular day has more or fewer seconds in it (such as occur during daylight saving transitions) or when the unit has a variable size, such as when adding a month or a year, since those fields have variable numbers of days in them.
Bear in mind that rolling fields forwards or backwards in [=field-based times=] can be tricky. For example, Feburary does not always have the same number of days in it. Or consider the problem of incrementing the month forward by one in the date 2011-01-30
.
Serializations of date/time values tend to behave as-if they were field-based, in that they provide human-readable values tied to a specific [=chronology=] (typically the [=ISO Chronology=]). The most familiar example of such a serialization scheme is [[ISO8601]], along with its many flavors and interpretations, such as [[RFC3339]] or [[XMLSchema-2]]. The SQL data types date
, time
, and timestamp
are [=field-based time=] values which are intended to be zone offset independent: they are actually [=floating time=] values! The SQL data type timestamp with time zone
is actually the type that should be used for [=incremental time=] values ("timestamps").
By contrast with SQL types, programming languages tend to use [=incremental time=] for their primitive time types. They convert to and from field-based serializations demand. As a result, users might not be clear about the differences between these types or can accidentally create a mixture of different representations. For example, a Java programmer using JDBC might access a field in a SQL query using the class java.sql.Date
. This class represents the value as an [=incremental time=] in UTC. This adds information inappropriately to [=floating time=] values or can remove zone-offset information from the original [=field-based time=] value.
Databases can use [=incremental time=] or either zone offset-dependent or independent field-based structures internally. For example, Oracle databases treat a timestamp
field as though it is in the local time zone of the database instance. The combination of application and database time zones coupled with implicit conversions between [=incremental time=] and [=field-based time=] values can result in date/time values changing meaning without the user intending it.
In [[XMLSchema-2]], as with SQL, dates and times are expressed using [=field-based time=]. The date or time can express the zone offset from UTC (for example using a format such as 08:00:00+01:00
). [=UTC=] is indicated by the letter Z
(for example 08:00:00Z
). The zone offset can also be omitted (producing a [=floating time=] value).
Properly speaking, an XML Schema date or time value with a zone offset is field-based/zone offset dependent and one without is field-based/floating.
If the two types are mixed, then the interpretation of the zone offset is not adequately specified in XML Schema. In [[XPATH-FUNCTIONS]], the interpretation is implementation-defined and is based on an implicit zone offset. This is usually either UTC or whatever the local time offset of the host environment is. The presence or absence of the zone offset in the XML Schema serialized representation might not be indicative of the original data's intention because of the confusion described above. Proper comparisons or processing rely on normalizing all date and time values into [=floating time=] or zone offset-dependent (field-based zone-dependent) forms and never mixing the two in a particular operation.
Date/time values often need to be serialized (converted to some string representation) for exchange in various document formats and protocols. Sometimes these serializations can be produced from or used to instantiate [=incremental time=], [=field-based time=], or [=floating time=] datatype values directly. Precisely which serialization to use depends on the application's use case and available standards. Serializations that use time zone IDs instead of relying on offsets are RECOMMENDED.
Type Being Serialized | Serialization to Use | Description |
---|---|---|
Instant, Timestamp, Date | 2007-01-01T01:00:00.000Z |
An incremental time (instant on the timeline) with UTC offset. |
OffsetDateTime | 2007-01-01T01:00:00.000+01:00 |
An incremental time with an explicit offset from UTC. Zoned Instant is preferred. |
Zoned Offset DateTime | 2007-01-01T01:00:00.000+01:00[America/Chicago] |
An incremental time with an offset and a specific time zone. The time zone should be used when formatting the value for display. Note that the offset and the time zone do not have to match. Generally the offset date time is converted to an instant on the timeline using the offset provided and then the time zone specified is attached to that moment. |
Zoned Instant | 2007-01-01T01:00:00.000Z[America/Chicago] |
An incremental time with a specific time zone that should be used when formatting the value for display. |
Zoned Local Date Time | 2007-01-01T01:00:00.000[America/Chicago] |
A floating time value with both a date and a time plus a specific time zone that should be used when displaying the time value. This serialization is equivalent to a zoned offset date time when the offsets match. |
Local Date Time | 2007-01-01T01:00:00.000 |
A floating time value containing both a date and a time. |
Local Date | 2007-01-01 |
A floating time with a date but no time component. |
Local Time | 00:00:00.000 |
A floating time with a time but no date component. |
Year-Month | 2007-01 |
A floating time value containing only a year and a month. Similar to [[XMLSchema-2]] gYearMonth . |
Year | 2007 |
A floating time value containing only a year. Similar to [[XMLSchema-2]] gYear . |
Month-Day | 01-01 |
A floating time value containing only a month and day. Similar to [[XMLSchema-2]] gMonthDay . |
There are a number of ways applications can use date and time values. In this section we examine the different common use cases and the serializations or data structures to use for each.
Use an incremental time value such as the Instant
or Date
type for timestamp values.
This is the most common use case: use a timestamp unless you have a reason not to. If your application can accurately generate incremental and/or field-based times based on UTC and the events are not tied to specific local time, all that is needed is the timestamp value itself. That is, if your application never needs to recover what the local wall time was when event occurred and only cares about relative ordering of events. For example, if you merge log files from many machines together or if you are recording events in a log, a timestamp is perfectly adequate. For these types of time events, an Instant is sufficient.
It is usually desirable to normalize timestamp values to UTC (or, less commonly, a specific UTC offset) so that separate series of data can be easily compared and merged. Information about local offset may be valuable in recovering the actual wall time, but time zone rules are probably only rarely interesting.
When in doubt, use [=UTC=] for serializing, storing, and exchanging date and time values.
Bear in mind that the [=local time offset=] doesn't change the relationship of a datetime value to the [=timeline=]. Serializing timestamp values with an offset makes the values more difficult to work with, particularly in systems where multiple offsets might be in use.
In other use cases, we'll see that storing the [=time zone=] is valuable or even required for consistent results. However, this never applies to timestamp values. The only thing that storing the [=time zone=] might provide is the originating [=wall time=].
Many applications need to work with events that have already occurred, events in the future, or both. When working with these types of values, additional care needs to be used to avoid problems with the way that time zones interact with events.
You SHOULD use ZonedInstant
type for past-only events.
You MAY use ZonedInstant
, ZonedLocalDateTime
or ZonedOffsetDateTime
types for past events.
For an application that deals only with events that occurred in the past (with no future events) and for which you need to know what the wall time was, the local time offset of the event may be necessary additional data. Note that the time zone also provides the local time offset and is, thus, an acceptable substitute.
Once an event is in the past, its local time offset to UTC becomes fixed. Therefore an incremental time with an offset can always produce wall time in a given chronology.
Although local time offset is sufficient, knowing the specific time zone allows the application to reconstruct the time and its relationship to other time values and is usually more convenient when formating the value for display. For example, without the time zone identifier, it's not possible to accurately include the time zone's name or abbreviation into the display.
You SHOULD use ZonedInstant
type if your application can have events in the future.
For an application that deals with both past and future events (for example, if you have a calendar or a meeting schedule), you will need the time zone (and not merely the local time offset) to ensure proper time computation. This is because a future event's wall time depends on time zone-related information, such as summer time transitions.
One issue with future events is that rules for the event's associated time zone can change from time to time and these changes can require an application to update affected data records in order to meet the user’s expectations. This is because many systems actually store or depend on using an incremental time value for date/time related operations (such as scheduling or notifications). When the time zone rules change, the corresponding the incremental time value needs to be checked or updated if the wall time of the event is expected to stay the same. See above for an example.
A recurring event, such as a regular meeting, is usually defined by a set of rules that express a user's intent. In many cases, the user intends for the event to recur at a specific local wall time in a specific time zone. Each iteration is thus a past or future event.
Each iteration of the event will need to compute a specific (incremental time value) start time and this value will depend on the governing time zone's rules regarding local time offset, summer time transitions, and the like. It is important to use the time zone to perform these computations, as this avoids problems with assuming that the number of units between events (such as hours in a week or minutes in a day) is fixed. It can also help avoid ghost times.
You SHOULD use the appropriate floating time type, such as LocalDateTime
(for values with both date and time), LocalDate
(for date values), or LocalTime
(for time-only values) for values that are not tied to a specific offset or time zone rules.
If your application deals with a date or time value that is not tied to a specific local interpretation or which needs to be interpreted as a different range of incremental time values in different locations, serializing the value without an offset or time zone identifer communicates that the value is a floating time.
Such applications are more common than they first appear. We've already seen examples in this document, such as a list of holidays or a user's birth date. Any "anniversary" type of date (hire date, termination date, wedding date, etc.) is generally best representated a [=floating time=] value. Another application is when you collect statistics using [=instants=] but need to group them into durable time buckets by [=floating=] the values.
Whenever possible, use [=UTC=] or choose a consistent time zone when creating time-based content or data value so that values from discrete sources can be compared more readily.
Bear in mind best practices to assist users in selecting their time zone, including keeping track of their preferences.
Some best practices when implementing time zone selection and management:
If you are a users of specifications such as XQuery [[XQUERY-10]] and XSLT [[XSLT-30]] and other, similar, standards, in addition to the guidelines found elsewhere in this document, take the following into account even if time-zone-sensitive data is rarely used. Sooner or later some data will be affected by the issues described.
Use an explicit zone offset with date, time, and dateTime types, if possible. Include an additional field indicating the time zone if one is not provided.
Do not apply operations based on date or time types (such as indexing) to collections of data in which some data items have zone offset information while other data items do not have zone offset information.
If you have data that includes implicit and fixed explicit [=local time offsets=], before applying any date- or time-sensitive operations, adjust the zone offset of the implicit data to UTC with functions for zone offset adjustment, cf. this section in [[[xpath-functions]]].
If you have data that contains both implicit and fixed explicit [=local time offsets=] and you do not want to adjust the data subset which already has a zone offset, make sure that you recognize this data subset, for example via the component extraction functions [[XPATH-FUNCTIONS]].
One quirk of timekeeping is the need for leap seconds. The Earth's rotation is not even and, in general, is slowing down. To keep observed time and incremental time in sync, the [International Earth Rotation Service] occasionally mandates a "leap second". A leap second usually occurs once or sometimes twice per year and always takes the form of an additional second added to the last minute of the day. Usually the leap second is added to December 31st or June 30th.
Most incremental time values (do not keep track of leap seconds in their incremental time values. What happens is:
java.util.Calendar
class allows for a "61st" second of a minute to accommodate leap seconds, if you set a Java Calendar to the equivalent of December 31, 2008 23:59:60 UTC (a particular leap second value) and then convert that to a java.util.Date
in order to print it out, you might see: "January 1, 2009 00:00:00 UTC". This is because the Date
object is an [=incremental time=] and the code formatting the value doesn't know about the leap second.If your application cares about or is sensitive to leap seconds, special care must be taken to deal with the loss of leap second precision.