UNIX Epoch time
A UNIX Epoch time is a system for describing a point in time, defined as an approximation of the number of seconds that have elapsed since 00:00:00 Coordinated Universal Time (UTC), Thursday, 1 January 1970. Every day is treated as if it contains exactly 86400 seconds, so leap seconds are not applied to seconds since the Epoch.
A time zone is a region of the globe that observes a uniform standard time for legal, commercial, and social purposes. Time zones tend to follow the boundaries of countries and their subdivisions because it is convenient for areas in close commercial or other communication to keep the same time.
Most of the time zones on land are offset from Coordinated Universal Time (UTC) by a whole number of hours (UTC−12 to UTC+14), but a few zones are offset by 30 or 45 minutes (e.g. Newfoundland Standard Time is UTC−03:30, Nepal Standard Time is UTC+05:45, and Indian Standard Time is UTC+05:30).
Some higher latitude and temperate zone countries use daylight saving time for part of the year, typically by adjusting local clock time by an hour. Many land time zones are skewed toward the west of the corresponding nautical time zones. This also creates a permanent daylight saving time effect.
Notation of time
ISO 8601 is an international standard that defines methods of representing dates and times in textual form, including specifications for representing time zones. In general, ISO 8601 applies to representations and formats of dates in the Gregorian calendar, times based on the 24-hour timekeeping system (with optional time zone information, e. g. the UTC offset), time intervals and combinations thereof. For example for combined date and time in UTC is "2018-09-01T07:37:50+00:00" or "2018-09-01T07:37:50Z".
If a time is in Coordinated Universal Time (UTC), a "Z" is added directly after the time without a separating space. "Z" is the zone designator for the zero UTC offset. "09:30 UTC" is therefore represented as "09:30Z" or "0930Z". Likewise, "14:45:15 UTC" is written as "14:45:15Z" or "144515Z". UTC time is also known as "Zulu" time, since "Zulu" is a phonetic alphabet code word for the letter "Z".
Offsets from UTC Time
Offsets from UTC are written in the format ±[hh]:[mm], ±[hh] [mm], or ±[hh] (either hours ahead or behind UTC). For example, if the time being described is one hour ahead of UTC (such as the time in Berlin during the winter), the zone designator would be "+01:00", "+0100", or simply "+01". This numeric representation of time zones is appended to local times in the same way that alphabetic time zone abbreviations (or "Z", as above) are appended. The offset from UTC changes with daylight saving time, e.g. a time offset in Chicago, which is in the North American Central Time Zone, is "−06:00" for the winter (Central Standard Time) and "−05:00" for the summer (Central Daylight Time).
Time Zone Abbreviations
Time zones are often represented by alphabetic abbreviations such as "EST", "WST", and "CST", but these are not part of the international time and date standard ISO 8601 and their use as sole designator for a time zone is discouraged. Such designations can be ambiguous; for example, "ECT" could be interpreted as "Eastern Caribbean Time" (UTC−4h), "Ecuador Time" (UTC−5h), or "European Central Time" (UTC+1h).
In order to address these complexities and provide better support in the JDK core, a new date and time API in
java.time package has been designed for Java SE 8.
LocalDate and LocalTime
The first classes you will probably encounter when using the new API are
LocalTime. They are local in the sense that they represent date and time from the context of the observer, such as a calendar on a desk or a clock on your wall. There is also a composite class called
LocalDateTime, which is a pairing of LocalDate and
Time zones, which disambiguate the contexts of different observers, are put to one side here; you should use these local classes when you don’t need that context. A desktop JavaFX application might be one of those times. These classes can even be used for representing time on a distributed system that has consistent time zones.
All the core classes in the new API are constructed by fluent factory methods. When constructing a value by its constituent fields, the factory is called
of; when converting from another type, the factory is called
from. There are also parse methods that take strings as parameters. See :
LocalDateTime timePoint = LocalDateTime.now(); // The current date and time LocalDate.of(2018, Month.DECEMBER, 12); // from values LocalDate.ofEpochDay(150); // middle of 1970 LocalTime.of(17, 18); // the train I took home today LocalTime.parse("10:15:30"); // From a String
Standard Java getter conventions are used in order to obtain values from new Java Date Time API classes, as shown down:
LocalDate theDate = timePoint.toLocalDate(); Month month = timePoint.getMonth(); int day = timePoint.getDayOfMonth(); timePoint.getSecond();
You can also alter the object values in order to perform calculations. Because all core classes are immutable in the new API, these methods are called with and return new objects, rather than using setters. There are also methods for calculations based on the different fields:
// Set the value, returning a new object LocalDateTime thePast = timePoint.withDayOfMonth(10).withYear(2010); /* You can use direct manipulation methods, or pass a value and field pair */ LocalDateTime yetAnother = thePast.plusWeeks(3).plus(3, ChronoUnit.WEEKS);
The new API also has the concept of an adjuster—a block of code that can be used to wrap up common processing logic. You can either write a WithAdjuster, which is used to set one or more fields, or a PlusAdjuster, which is used to add or subtract some fields. Value classes can also act as adjusters, in which case they update the values of the fields they represent. Built-in adjusters are defined by the new API, but you can write your own adjusters if you have specific business logic that you wish to reuse. See:
import static java.time.temporal.TemporalAdjusters.*; LocalDateTime timePoint = ... foo = timePoint.with(lastDayOfMonth()); bar = timePoint.with(previousOrSame(ChronoUnit.WEDNESDAY)); // Using value classes as adjusters timePoint.with(LocalTime.now());
The new API supports different precision time points by offering types to represent a date, a time, and date with time, but obviously there are notions of precision that are more fine-grained than this. The
truncatedTo method exists to support such use cases, and it allows you to truncate a value to a field, as shown down:
LocalTime truncatedTime = time.truncatedTo(ChronoUnit.SECONDS);
The local classes that we looked at previously abstract away the complexity introduced by time zones. A time zone is a set of rules, corresponding to a region in which the standard time is the same. There are about 40 of them. Time zones are defined by their offset from Coordinated Universal Time (UTC). They move roughly in sync, but by a specified difference.
Time zones can be referred to by two identifiers: abbreviated, for example, “PLT,” and longer, for example, “Asia/Karachi.” When designing your application, you should consider what scenarios are appropriate for using time zones and when offsets are appropriate.
- ZoneId is an identifier for a region, see below. Each ZoneId corresponds to some rules that define the time zone for that location. When designing your software, if you consider throwing around a string such as “PLT” or “Asia/Karachi,” you should use this domain class instead. An example use case would be storing users’ preferences for their time zone.
// You can specify the zone id when creating a zoned date time ZoneId id = ZoneId.of("Europe/Paris"); ZonedDateTime zoned = ZonedDateTime.of(dateTime, id);
- ZoneOffset is the period of time representing a difference between Greenwich/UTC and a time zone. This can be resolved for a specific ZoneId at a specific moment in time, as shown below:
ZoneOffset offset = ZoneOffset.of("+2:00");
Time Zone Classes
- ZonedDateTime is a date and time with a fully qualified time zone (see below). This can resolve an offset at any point in time. The rule of thumb is that if you want to represent a date and time without relying on the context of a specific server, you should use ZonedDateTime.
- OffsetDateTime is a date and time with a resolved offset. This is useful for serializing data into a database and also should be used as the serialization format for logging time stamps if you have servers in different time zones.
- OffsetTime is a time with a resolved offset, as shown below.
OffsetTime time = OffsetTime.now(); // changes offset, while keeping the same point on the timeline OffsetTime sameTimeDifferentOffset = time.withOffsetSameInstant( offset); // changes the offset, and updates the point on the timeline OffsetTime changeTimeWithNewOffset = time.withOffsetSameLocal( offset); // Can also create new object with altered fields as before changeTimeWithNewOffset .withHour(3) .plusSeconds(2);
A Period represents a value such as “3 months and 1 day,” which is a distance on the timeline. This is in contrast to the other classes we’ve looked at so far, which have been points on the timeline. See:
// 3 years, 2 months, 1 day Period period = Period.of(3, 2, 1); // You can modify the values of dates using periods LocalDate newDate = oldDate.plus(period); ZonedDateTime newDateTime = oldDateTime.minus(period); // Components of a Period are represented by ChronoUnit values assertEquals(1, period.get(ChronoUnit.DAYS));
A Duration is a distance on the timeline measured in terms of time, and it fulfills a similar purpose to Period, but with different precision, as shown below:
// A duration of 3 seconds and 5 nanoseconds Duration duration = Duration.ofSeconds(3, 5); Duration oneDay = Duration.between(today, yesterday);
It’s possible to perform normal plus, minus, and “with” operations on a Duration instance and also to modify the value of a date or time using the Duration.
In order to support the needs of developers using non-ISO calendaring systems, Java SE 8 introduces the concept of a Chronology, which represents a calendaring system and acts as a factory for time points within the calendaring system. There are also interfaces that correspond to core time point classes, but are parameterized by
These classes are there purely for developers who are working on highly internationalized applications that need to take into account local calendaring systems, and they shouldn’t be used by developers without these requirements. Some calendaring systems don’t even have a concept of a month or a week and calculations would need to be performed via the very generic field API.
The Rest of the API
Java SE 8 also has classes for some other common use cases. There is the MonthDay class, which contains a pair of Month and Day and is useful for representing birthdays. The YearMonth class covers the credit card start date and expiration date use cases and scenarios in which people have a date with no specified day.
JDBC in Java SE 8 will support these new types, but there will be no public JDBC API changes. The existing generic setObject and getObject methods will be sufficient.
These types can be mapped to vendor-specific database types or ANSI SQL types; for example, the ANSI mapping looks like:
- DATE mapped to Java LocalDate class.
- TIME mapped to Java LocalTime class.
- TIMESTAMP mapped to Java LocalDateTime class.
- TIME WITH TIMEZONE mapped to OffsetTime class.
- TIMESTAMP WITH TIMEZONE mapped to OffsetDateTime class.
Java Date/Time API Best Practices:
- Servers should generally have their OS set to UTC as the time zone, or if not provided use GMT time zone. Your Java implementation probably picks up this setting as its own current default time zone.
- Do not depend on the time zone being set to UTC at OS or JVM lunching time. A sysadmin could change it. And any Java code in any thread of any app within your JVM can change the JVM’s current default time zone at runtime by calling TimeZone.setDefault.
- Your business logic, data storage, and data exchange should almost always be done in UTC. Nearly every database has a feature for adjusting any input into UTC and storing in UTC.
- When presenting and formatting a date-time to a user, adjust into the expected his local time zone. When serializing a date-time value, use the ISO 8601 string formats.
- When using Java and JDBC, you will be using the java.sql.Timestamp and related data types. They are always in UTC, automatically.
- If your business requirements consider the original input data’s time zone to be important, to be remembered, then store that explicitly as a separate column in your database table. and a proper time zone name is most appropriate to store such as America/Montreal.
- Do not confuse a "time zone", such as America/New_York with a "time zone offset", such as -05:00. They are two different things.
- Always store local time with timezone and not just its UTC offset OR store the converted UTC time of your local time only if it is enough. In other word don't trust time-zone offsets embedded in textual representation of the date-time and don't accept to parse and follow them. Instead always request that time zone and/or reference zone have to be explicitly defined.