Статьи

API Java 8: java.util.time — Instant, LocalDate, LocalTime и LocalDateTime

Я начал испытывать новые API-интерфейсы Java 8 (все еще ранний доступ на момент написания этой статьи), и первое, на что я обратил внимание, это новый API даты и времени ( JSR 310 ). Так как в этом новом долгожданном API есть что рассказать, я думаю, что стоит несколько постов с некоторыми примерами. Этот пост будет первым в серии, начиная с некоторых базовых классов пакета: Instant, LocalDate, LocalTime и LocalDateTime. 

Мгновенное (java.time.Instant)

Вероятно, лучшее место для начала с пакетом java.time — это класс Instant. Мгновенный представляет момент времени (похожий на java.util.Date) с точностью до наносекунд (в отличие от старой даты с точностью до миллисекунд). Для представления момента времени с использованием наносекундной точности требуется больше места, чем может предоставить Long, поэтому внутреннее представление состоит из двух полей Long, первое содержит количество секунд с (или до) стандартной эпохи Java, а другое — число наносекунды последних секунд (поэтому никогда не превышают 999 999 999). Давайте начнем с получения экземпляра Instant и напечатаем его значение:

// Get the current time
Instant instant = Instant.now();

// Output format is ISO-8601
System.out.println(instant);

Instant.toString () возвращает строку в формате ISO8601 (например, «2013-06-25T16: 22: 52.966Z»), что является гораздо более логичным выбором, чем тот, который использовался старым классом Date. Вот несколько других способов создания Instants:

// Convert a java.util.Date into an Instant
Instant instant = Instant.ofEpochMilli(new Date().getTime());

// Create from a String
instant = Instant.parse("1995-10-23T10:12:35Z");

Во втором примере выше создается Instant путем синтаксического анализа строки, эта строка должна быть действительным представлением мгновенного значения UTC (NB: Instant — это момент времени, он не хранит информацию о TimeZone и поэтому поддерживает только строки в формате UTC ). Instant API предоставляет несколько полезных методов, позволяющих выполнять вычисления с использованием Instants и других классов в пакете. Ниже приведен первый пример:

// Adding 5 hours and 4 minutes to an Instant
instant.plus(Duration.ofHours(5).plusMinutes(4));

Сколько экземпляров java.time.Instant используется в приведенном выше примере? Два. Планируется, что пакет java.time будет потокобезопасным, и поэтому большинство его классов являются неизменяемыми, Instant не является исключением из этого правила, и поэтому метод plus () создает новый экземпляр.

Instant instant1 = instant.plus(Duration.ofHours(5).plusMinutes(4));
System.out.println("Instant is immutable, so instant==instant returns: " + (instant == instant1));

The output would be: 
Instant is immutable, so instant==instant returns: false

Вот еще несколько примеров мгновенных расчетов:

// Substract 5 days of an instant
instant.minus(5, ChronoUnit.DAYS); // Option 1
instant.minus(Duration.ofDays(5)); // Option 2

// How many minutes are between to Instants?
long diffAsMinutes = instant.periodUntil(instant1, ChronoUnit.MINUTES); // Option 1
long diffAsMinutes = ChronoUnit.MINUTES.between(instant, instant1); // Option 2

Instants Comparable, что означает, что они могут использоваться в любом месте, где ожидается Comparable (например, коллекции). Instant также предоставляет методы isAfter () и isBefore (), которые могут сделать код более читабельным:

// Compare the two
System.out.format("instant1.compareTo(instant)=%d.%n", instant1.compareTo(instant));

// We can check to see which Instant is before/after the other
System.out.format("instant1.isAfter(instant)=%b, instant1.isBefore(instant)=%b.%n", 
 instant1.isAfter(instant), instant1.isBefore(instant));

The output would be:
instant1.compareTo(instant)=1.
instant1.isAfter(instant)=true, instant1.isBefore(instant)=false.

LocalDate и LocalTime

LocalDate represents a date without a time zone, such as 1-1-2000. LocalTime represents time without a time zone, such as 04:44:59.12 — unlike Instant which is an offset from the Java epoch and as such can be calculated into a precise point of time these two are just date or time without any relation to the epoch — a human readable date and time. There are several ways to obtain LocalTime and LocalDate instances, here are few:

LocalDate localDate = LocalDate.now();
localDate = LocalDate.ofYearDay(2005, 86); // The 86th day of 2005 (27-Mar-2005)
localDate = LocalDate.of(2013, Month.AUGUST, 10); //10th of Aug 2013

LocalTime localTime = LocalTime.of(22, 33); //10:33 PM
localTime = LocalTime.now();
localTime = LocalTime.ofSecondOfDay(4503); // The 4,503 second in a day (1:15:30 AM)

LocalDate and Local time follow the same general concept of multithreading as Instant does — and as such their instances are immutable. LocalDate and LocalTime have calculation and comparison methods similar to the ones Instant has (some of the methods are defined by the java.time.temporal.Temporal interface which implemented by all of these classes):

LocalDate localDate1 = localDate.plus(5, ChronoUnit.HOURS);
localDate.isBefore(localDate1);

LocalDateTime

The last important player in the simple date and time classes is LocalDateTime — this is a combination of LocalDate and LocalTime representing a date and the time within that date, again no time zone. LocalDateTime seems to be very similar to Instant, a reminder: «an Instant is point in time without time zone” and one could say that a point in time is nothing more than a date and time within that date. But there is a difference: LocalDateTime is not a point on the time line as Instant is, LocalDateTime is just a date and time as a person would write on a note. Consider the following example: two persons which were born at 11am, July the 2nd 2013. The first was born in the UK while the second in California. If we ask any of them for their birth date it will look that they were born on the same time (this is the LocalDateTime) but if we align the dates on the timeline (using Instant) we will find out that the one born in California is few hours younger than the one born in the UK (NB: to create the appropriate Instant we have to convert the time to UTC, this is where the difference lays). Beside of that LocalDateTime behaves very similar to the other classes illustrated above:

LocalDateTime localDateTime = LocalDateTime.now();

// Jump to 25 hours and 3 minutes into the future
LocalDateTime inTheFuture = localDateTime.plusHours(25).plusMinutes(3);

// We could do the same on localTime or localDate
System.out.println(localDateTime.toLocalTime().plusHours(25).plusMinutes(3));
System.out.println(localDateTime.toLocalDate().plusMonths(2));

// We could also use TemportalAmount (in this case a Duration and Period)
System.out.println(localDateTime.toLocalTime().plus(Duration.ofHours(25).plusMinutes(3)));
System.out.println(localDateTime.toLocalDate().plus(Period.ofMonths(2)));