Time is a scalar quantity, so it would only need a number to express a time value.
Since you want to relate time to calendars, which are made for humans, things get more complicated.
Java date and time classes' history:
- the java.util.Date class was introduced in Java 1.0
- the java.util.Calendar class was introduced in Java 1.1
- third-party date and time libraries, such as Joda-Time, were used by developer to overcome Java standard API's issues
- the java.time API was introduced in Java 1.8 to fix the flaws in the previous versions of the platforms
1 The Time Line
The unit of time is the second, which is derived from the Earth's rotation around its axis.
Universal Time
- Earth rotation is not uniform: in 1967, a more precise definition of second was derived from the property of atoms of caesium-133 and atomic clocks were introduced to keep the official time.
- Since rotation rate of Earth varies with climate events, official time keepers synchronize absolute time with solar mean time
- official time keepers add or remove a second to keep the Universal Time close to the mean solar time
- In UTC, a day has 24 * 60 * 60 = 86400 seconds.
- the number of seconds in a minute is usually 60, but with an occasional leap second it may be 61.
Universal Time and Computer Systems
- Computer system keeps 86400 seconds per day and do not respect leap seconds.
- when a leap second is officially introduced, computer systems slow down or speed up before the leap second.
Java Date and Time API specification for the time scale:
- A day has 86,400 seconds
- Time scale matches the official time at noon each day
The Time Line in Java and the Instant class
- the
Instantclass represents a point in the time line - The static method Instant.now() returns the current instant
- time is measured on time scale with origin set at midnigth of January 1, 1970 at Greenwich meridian
- from that origin, time is measured in 86,400 seconds per day
- Instant.MIN and Instant.MAX are one billion behind and ahead the origin
The Duration class represents the amount of time between two instants
- the static method Duration.between gives the difference between two instants
Example:
Instant start = Instant.now(); callMethod(); Instant stop = Instant.now(); Duration timeElapsed = Duration.between(start, stop); long millis = timeElapsed.toMillis();
2 Human Time
When you refer to absolute time you mean the Time Line, when you refer to human time you mean the UTC Local Time.
Java consider two types of human times: local time/date and zoned time
- the LocalDate/LocalTime class has a date/time of the day, but no time zone information.
- use a LocalDate to store a local date,
- for example: Ayrton Senna was born on 21 March 1960
- the ZonedDateTime class has a time, day and a time zone: it represents a precise instant of time
- use a ZonedDateTime to store an instant in the time line
- for example: launch of SpaceX Falcon 9 is scheduled for May 20, 2018, 4:42:00 p.m. EDT, 20:42 UTC
LocalTime Application Examples
- Use local dates and times to represent bithdays, holidays and timetables/schedule times
ZonedTime Wrong Application Examples
- use a time zone only to represent absolute time instances
- using a time zone to represent a meeting scheduled for every week is a bad choice
- if you happen to cross the time zone boundaries the meeting will be an hour late or early
3 Local Date
The LocalDate class
- A LocalDate class instance is a date with a year, month and a day of the month
- To construct a LocalDate instance use the static methods
LocalDate.now()orLocalDate.of().
Example: LocalDate.of() and LocalDate.now()
LocalDate today = LocalDate.now(); // Today's date LocalDate sennaBirthday1 = LocalDate.of(1960, 3, 21); LocalDate sennaBirthday2 = LocalDate.of(1960, Month.MARCH, 21); // Note that LocalDate's conventions for month parameter differ from those in java.util.Date
The Period class
- a Period object represents the difference between two local date objects
- a Period object expresses a number of elapsed years, months or days
- note that the difference between two time instants is a Duration, not a Period
Example: compute the next birthday
birthday.plus(Period.ofYears(1)) // OK birthday.plusYears(1) // OK birthday.plus(Duration.ofDays(365)) // KO, may produce a wrong result in a leap year
The until method returns the difference between two local dates
Example: until method
LocalDate today = LocalDate.now(); LocalDate christmas = LocalDate.of(2018, Month.DECEMBER, 25); Period period1 = today.until(christmas); // a period in months and days Period period2 = today.until(christmas, ChronoUnit.DAYS); // a period in days
The DayOfWeek enumeration
- The localDate.getDayOfWeek() method returns a value of the DayOfWeek enumeration
- DayOfWeek.MONDAY has the value 1 and DayOfWeek.SUNDAY has the value 7, while in the java.util.Calendar, Sunday has value 1 and Saturday value 7
The MonthDay, YearMonth and Year classes describe partial dates
- for example: December 25, without the year, can be represented as a MonthDay
4 Date Adjusters
The TemporalAdjusters class provides static methods for making common change in date calculations
- can be applied to compute dates such as the first Monday of every month in a scheduling application
Example: use the TemporalAdjusters class to get the first Monday of the current month
int currentYearValue = Year.now().getValue(); Month currentMonth = LocalDate.now().getMonth(); LocalDate firstMonday = LocalDate.of(currentYearValue, currentMonth, 1).with(TemporalAdjusters.nextOrSame(DayOfWeek.MONDAY));
5 Local Time
The LocalTime class
- A LocalTime object represents a time of day in the ISO format without a time zone.
- for example: 22:15:30
- To create a LocalTime instance use the static methods
LocalTime.now()orLocalTime.of().
Example: LocalTime.of() and LocalTime.now()
LocalTime timeOfClock = LocalTime.now(); LocalTime timeForBed = LocalTime.of(23, 30); // or LocalTime.of(23, 30, 0)
Example: plus() method
LocalTime nightShift = LocalTime.of(20, 30);
LocalTime endWork = nightShift.plusHours(9); // endWork is 05:30:00
System.out.println("work starts at "+nightShift+" and ends at "+endWork);
// the plus and minus operations wrap around a 24-hour day
Note LocalTime doesn’t concern itself with AM/PM.
The LocalDateTime class
- The LocalDateTime class represents a date and a time
- it is suitable for storing a point in time in a fixed time zone.
- use a LocalDateTime for schedules of events or classes
- Note: if you need to deal with users that are in different time zones or time that span over daylight saving time, use a ZonedDateTime not a LocalDateTime
6 Zoned Time
Time zones are messy and daylight saving time make things even more complicated.
Time zone makes it harder to develop calendar applications
- if you travel from a continent to another, you move from a local time to another local time, but you expect the calendar application to alert you with the new local time
The Internet Assigned Numbers Authority (IANA) maintains a database which contains all known time zones around the world
- The IANA updates this database when rules for daylight saving time change
- Java uses the IANA's time zones database
A Time Zone has an ID, which is a String such as "Europe/Berlin" or "Europe/London"
- the static method ZoneId.getAvailableZoneIds returns a collection of all the available time zone
To construct a ZoneId object use the static method ZoneId.of(id) passing a selected time zone ID as a String value
Create a ZonedDateTime object in two ways:
- invoke the static method ZonedDateTime.of(year, month, day, hour, minute, second, nano, zoneId)
- turn a LocalDateTime object into a ZonedDateTime by calling local.atZone(zoneId)
Example: create a ZonedDateTime object
ZonedDateTime liftOff = ZonedDateTime.of(2018, 5, 20, 16, 42, 0, 0, ZoneId.of("America/New_York"));
System.out.println("launch of SpaceX Falcon 9 is scheduled for: " + liftOff);
// 2018-05-20T16:42-04:00[America/New_York]
A zonedDateTime represents a specific instant on the time line in certain time zone
- you can get a ZonedDateTime from an Instant and viceversa:
-
zonedDateTime.toInstant()returns an Instant object -
instant.atZone(ZoneId.of("<ZoneIdString>"))returns the ZonedDateTime object at the UTC time zone argument
ZonedDateTime and LocalDateTime have many methods in common, but daylight savings time introduces some complications
- When a dayligth saving time is introduced, clocks advance by an hour:
if you construct a ZonedDateTime that is contained in a skipped hour, you get a ZonedDateTime with an hour ahead - When a dayligth saving time ends, clocks are set back by an hour and there are two instants with the same local time:
if you construct a ZonedDateTime that is contained in this range you get the earlier of the two.
Note: pay attention when changing date across saving time boundaries
- suppose you are building a application that schedule meetings
- if you want to set another meeting for the next week, add a period of seven days not a duration
ZonedDateTime nextMeeting = meeting.plus(Period.ofDays(7)); // OK
The OffsetDateTime class represents a time with an offset from UTC
- this class does not use time zone rules
- this class should be used by specialized applications, which do not require time zone rules
7 Formatting and Parsing
The DateTimeFormatter class contains three types of formatters for date/time values:
- predefined standard formatters
- intended for machine-readable timestamps
- locale-specific formatters
- intended for presenting date and times to human readers
- formatters with custom patters
Example: how to use a standard formatter
String formattedString = DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(liftOff); System.out.println(formattedString); // 2018-05-20T16:42:00-04:00
To create a Locale-specific formatter call one of the three static construct methods and pass a formatting style:
- there are three construct methods: ofLocalizedDate, ofLocalizedTime or ofLocalizedDateTime
- there are four formatting styles: SHORT, MEDIUM, LONG and FULL
Example: how to use a Locale-specific formatter
String formattedString = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG).format(liftOff); System.out.println(formattedString); // May 20, 2018 4:42:00 PM EDT
the withLocale() method
- the format() method uses the default locale
- to change to a different locale use the withLocale() method and then call the format() method
Example: use the Locale-specific formatter setting a specific locale
String formattedString = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG).withLocale(Locale.ITALIAN).format(liftOff); System.out.println(formattedString); // 20 maggio 2018 16.42.00 EDT
Note that the java.time.format.DateTimeFormatter class replaces the java.util.DateFormat class
You can create your own date format by specifying a pattern
Example: a DateTimeFormatter with a pattern defined by the developer
String formattedString = DateTimeFormatter.ofPattern("EEEE dd/MM/yyyy HH:mm").format(liftOff);
System.out.println(formattedString); // Sunday 20/05/2018 16:42
// the pattern is formed by letters, each of which indicates a different time field
Parsing a string into a date/time
To parse a date/time value from a string, use a static parse method of the class you want parse into
Example: parsing with standard formatter
LocalDate sennaBirthday = LocalDate.parse("1960-06-21");
liftOff = ZonedDateTime.parse("2018-05-20T16:42:00-04:00");
Example: parsing with a custom formatter
liftOff = ZonedDateTime.parse("2018/05/20 16:42:00-04:00", DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ssxxx"));
8 Interoperating with Legacy Code
The new Date and Time API have to interoperate with Java 1.0 and Java 1.1 classes
The java.util.Date and the Instant classes are similar. In Java SE 8, the java.util.Date class has two added conversion methods:
- the toInstant() method converts from Date to Instant
- the from() static method converts from Instant to Date
The java.util.GregorianCalendar and the ZonedDateTime classes are similar. In Java SE 8, the java.util.GregorianCalendar classes has two added conversion methods:
- the toZonedDateTime() method converts from GregorianCalendar to a ZonedDateTime
- the from() static method converts from ZonedDateTime to GregorianCalendar
No comments:
Post a Comment