В этом посте мы более подробно рассмотрим новый API Date / Time, который мы получаем в Java 8 (
JSR 310 ). Обратите внимание, что этот пост в основном основан на примерах кода, которые показывают новые функциональные возможности API. Я думаю, что примеры говорят сами за себя, поэтому я не тратил много времени на написание текста вокруг них 🙂
Давайте начнем!
Работа с объектами даты и времени
Все классы Java 8 Date / Time API находятся в пакете java.time. Первый класс, на который мы хотим посмотреть, это java.time.LocalDate. LocalDate представляет дату года-месяца-дня без времени. Мы начнем с создания новых экземпляров LocalDate:
|
01
02
03
04
05
06
07
08
09
10
11
|
// the current dateLocalDate currentDate = LocalDate.now();// 2014-02-10LocalDate tenthFeb2014 = LocalDate.of(2014, Month.FEBRUARY, 10);// months values start at 1 (2014-08-01)LocalDate firstAug2014 = LocalDate.of(2014, 8, 1);// the 65th day of 2010 (2010-03-06)LocalDate sixtyFifthDayOf2010 = LocalDate.ofYearDay(2010, 65); |
LocalTime и LocalDateTime — следующие классы, на которые мы смотрим. Оба работают аналогично LocalDate. LocalTime работает со временем (без дат), в то время как LocalDateTime объединяет дату и время в одном классе:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
LocalTime currentTime = LocalTime.now(); // current timeLocalTime midday = LocalTime.of(12, 0); // 12:00LocalTime afterMidday = LocalTime.of(13, 30, 15); // 13:30:15// 12345th second of day (03:25:45)LocalTime fromSecondsOfDay = LocalTime.ofSecondOfDay(12345);// dates with times, e.g. 2014-02-18 19:08:37.950LocalDateTime currentDateTime = LocalDateTime.now();// 2014-10-02 12:30LocalDateTime secondAug2014 = LocalDateTime.of(2014, 10, 2, 12, 30);// 2014-12-24 12:00LocalDateTime christmas2014 = LocalDateTime.of(2014, Month.DECEMBER, 24, 12, 0); |
По умолчанию классы LocalDate / Time будут использовать системные часы в часовом поясе по умолчанию. Мы можем изменить это, предоставив часовой пояс или альтернативную реализацию Clock :
|
1
2
3
4
5
|
// current (local) time in Los AngelesLocalTime currentTimeInLosAngeles = LocalTime.now(ZoneId.of("America/Los_Angeles"));// current time in UTC time zoneLocalTime nowInUtc = LocalTime.now(Clock.systemUTC()); |
Из объектов LocalDate / Time мы можем получить всевозможную полезную информацию, которая может нам понадобиться. Несколько примеров:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
LocalDate date = LocalDate.of(2014, 2, 15); // 2014-02-15boolean isBefore = LocalDate.now().isBefore(date); // false// information about the monthMonth february = date.getMonth(); // FEBRUARYint februaryIntValue = february.getValue(); // 2int minLength = february.minLength(); // 28int maxLength = february.maxLength(); // 29Month firstMonthOfQuarter = february.firstMonthOfQuarter(); // JANUARY// information about the yearint year = date.getYear(); // 2014int dayOfYear = date.getDayOfYear(); // 46int lengthOfYear = date.lengthOfYear(); // 365boolean isLeapYear = date.isLeapYear(); // falseDayOfWeek dayOfWeek = date.getDayOfWeek();int dayOfWeekIntValue = dayOfWeek.getValue(); // 6String dayOfWeekName = dayOfWeek.name(); // SATURDAYint dayOfMonth = date.getDayOfMonth(); // 15LocalDateTime startOfDay = date.atStartOfDay(); // 2014-02-15 00:00// time informationLocalTime time = LocalTime.of(15, 30); // 15:30:00int hour = time.getHour(); // 15int second = time.getSecond(); // 0int minute = time.getMinute(); // 30int secondOfDay = time.toSecondOfDay(); // 55800 |
Некоторая информация может быть получена без указания конкретной даты. Например, мы можем использовать класс Year, если нам нужна информация о конкретном году:
|
1
2
3
4
5
6
7
|
Year currentYear = Year.now();Year twoThousand = Year.of(2000);boolean isLeap = currentYear.isLeap(); // falseint length = currentYear.length(); // 365// sixtyFourth day of 2014 (2014-03-05)LocalDate date = Year.of(2014).atDay(64); |
Мы можем использовать методы плюс и минус, чтобы сложить или вычесть определенное количество времени. Обратите внимание, что эти методы всегда возвращают новый экземпляр (классы даты / времени Java 8 являются неизменяемыми).
|
1
2
3
4
|
LocalDate tomorrow = LocalDate.now().plusDays(1);// before 5 houres and 30 minutesLocalDateTime dateTime = LocalDateTime.now().minusHours(5).minusMinutes(30); |
TemporalAdjusters — еще один хороший способ манипулирования датами. TemporalAdjuster — это интерфейс с одним методом, который используется для отделения процесса корректировки от фактических объектов даты / времени. Доступ к набору общих TemporalAdjusters можно получить с помощью статических методов класса TemporalAdjusters .
|
1
2
3
4
5
6
7
|
LocalDate date = LocalDate.of(2014, Month.FEBRUARY, 25); // 2014-02-25// first day of february 2014 (2014-02-01)LocalDate firstDayOfMonth = date.with(TemporalAdjusters.firstDayOfMonth());// last day of february 2014 (2014-02-28)LocalDate lastDayOfMonth = date.with(TemporalAdjusters.lastDayOfMonth()); |
Статический импорт облегчает чтение:
|
01
02
03
04
05
06
07
08
09
10
11
12
|
import static java.time.temporal.TemporalAdjusters.*;...// last day of 2014 (2014-12-31)LocalDate lastDayOfYear = date.with(lastDayOfYear());// first day of next month (2014-03-01)LocalDate firstDayOfNextMonth = date.with(firstDayOfNextMonth());// next sunday (2014-03-02)LocalDate nextSunday = date.with(next(DayOfWeek.SUNDAY)); |
Часовые пояса
Работа с часовыми поясами — еще одна важная тема, которая упрощается благодаря новому API. Классы LocalDate / Time, которые мы видели до сих пор, не содержат информацию о часовом поясе. Если мы хотим работать с датой / временем в определенном часовом поясе, мы можем использовать ZonedDateTime или OffsetDateTime :
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
ZoneId losAngeles = ZoneId.of("America/Los_Angeles");ZoneId berlin = ZoneId.of("Europe/Berlin");// 2014-02-20 12:00LocalDateTime dateTime = LocalDateTime.of(2014, 02, 20, 12, 0);// 2014-02-20 12:00, Europe/Berlin (+01:00)ZonedDateTime berlinDateTime = ZonedDateTime.of(dateTime, berlin);// 2014-02-20 03:00, America/Los_Angeles (-08:00)ZonedDateTime losAngelesDateTime = berlinDateTime.withZoneSameInstant(losAngeles);int offsetInSeconds = losAngelesDateTime.getOffset().getTotalSeconds(); // -28800// a collection of all available zonesSet<String> allZoneIds = ZoneId.getAvailableZoneIds();// using offsetsLocalDateTime date = LocalDateTime.of(2013, Month.JULY, 20, 3, 30);ZoneOffset offset = ZoneOffset.of("+05:00");// 2013-07-20 03:30 +05:00OffsetDateTime plusFive = OffsetDateTime.of(date, offset);// 2013-07-19 20:30 -02:00OffsetDateTime minusTwo = plusFive.withOffsetSameInstant(ZoneOffset.ofHours(-2)); |
Timestamps
Такие классы, как LocalDate и ZonedDateTime обеспечивают своевременное представление людей. Однако часто нам нужно работать со временем, если смотреть с точки зрения машины. Для этого мы можем использовать класс Instant, который представляет временные метки. Мгновенное время отсчитывает время, начиная с первой секунды 1 января 1970 года (1970-01-01 00:00:00), также называемое EPOCH . Мгновенные значения могут быть отрицательными, если они произошли до эпохи. Они соответствуют стандарту ISO 8601 для представления даты и времени.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
// current timeInstant now = Instant.now();// from unix timestamp, 2010-01-01 12:00:00Instant fromUnixTimestamp = Instant.ofEpochSecond(1262347200);// same time in millisInstant fromEpochMilli = Instant.ofEpochMilli(1262347200000l);// parsing from ISO 8601Instant fromIso8601 = Instant.parse("2010-01-01T12:00:00Z");// toString() returns ISO 8601 format, e.g. 2014-02-15T01:02:03ZString toIso8601 = now.toString();// as unix timestamplong toUnixTimestamp = now.getEpochSecond();// in millislong toEpochMillis = now.toEpochMilli();// plus/minus methods are available tooInstant nowPlusTenSeconds = now.plusSeconds(10); |
Периоды и продолжительность
Period и Duration — два других важных класса. Как имена предполагают, что они представляют количество или количество времени. Период использует значения на основе даты (годы, месяцы, дни), а длительность использует секунды или наносекунды для определения количества времени. Продолжительность наиболее подходит при работе с инстансами и машинным временем. Периоды и длительности могут содержать отрицательные значения, если конечная точка находится перед начальной точкой.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
// periodsLocalDate firstDate = LocalDate.of(2010, 5, 17); // 2010-05-17LocalDate secondDate = LocalDate.of(2015, 3, 7); // 2015-03-07Period period = Period.between(firstDate, secondDate);int days = period.getDays(); // 18int months = period.getMonths(); // 9int years = period.getYears(); // 4boolean isNegative = period.isNegative(); // falsePeriod twoMonthsAndFiveDays = Period.ofMonths(2).plusDays(5);LocalDate sixthOfJanuary = LocalDate.of(2014, 1, 6);// add two months and five days to 2014-01-06, result is 2014-03-11LocalDate eleventhOfMarch = sixthOfJanuary.plus(twoMonthsAndFiveDays);// durationsInstant firstInstant= Instant.ofEpochSecond( 1294881180 ); // 2011-01-13 01:13Instant secondInstant = Instant.ofEpochSecond(1294708260); // 2011-01-11 01:11Duration between = Duration.between(firstInstant, secondInstant);// negative because firstInstant is after secondInstant (-172920)long seconds = between.getSeconds();// get absolute result in minutes (2882)long absoluteResult = between.abs().toMinutes();// two hours in seconds (7200)long twoHoursInSeconds = Duration.ofHours(2).getSeconds(); |
Форматирование и анализ
Форматирование и анализ — еще одна важная тема при работе с датами и временем. В Java 8 это можно сделать с помощью методов format () и parse ():
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
// 2014-04-01 10:45LocalDateTime dateTime = LocalDateTime.of(2014, Month.APRIL, 1, 10, 45);// format as basic ISO date format (20140220)String asBasicIsoDate = dateTime.format(DateTimeFormatter.BASIC_ISO_DATE);// format as ISO week date (2014-W08-4)String asIsoWeekDate = dateTime.format(DateTimeFormatter.ISO_WEEK_DATE);// format ISO date time (2014-02-20T20:04:05.867)String asIsoDateTime = dateTime.format(DateTimeFormatter.ISO_DATE_TIME);// using a custom pattern (01/04/2014)String asCustomPattern = dateTime.format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));// french date formatting (1. avril 2014)String frenchDate = dateTime.format(DateTimeFormatter.ofPattern("d. MMMM yyyy", new Locale("fr")));// using short german date/time formatting (01.04.14 10:45)DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT) .withLocale(new Locale("de"));String germanDateTime = dateTime.format(formatter);// parsing date stringsLocalDate fromIsoDate = LocalDate.parse("2014-01-20");LocalDate fromIsoWeekDate = LocalDate.parse("2014-W14-2", DateTimeFormatter.ISO_WEEK_DATE);LocalDate fromCustomPattern = LocalDate.parse("20.01.2014", DateTimeFormatter.ofPattern("dd.MM.yyyy")); |
преобразование
Конечно, у нас не всегда есть объекты нужного нам типа. Поэтому нам нужна опция для преобразования различных объектов, относящихся к дате / времени, между собой. В следующих примерах показаны некоторые из возможных вариантов преобразования:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
// LocalDate/LocalTime <-> LocalDateTimeLocalDate date = LocalDate.now();LocalTime time = LocalTime.now();LocalDateTime dateTimeFromDateAndTime = LocalDateTime.of(date, time);LocalDate dateFromDateTime = LocalDateTime.now().toLocalDate();LocalTime timeFromDateTime = LocalDateTime.now().toLocalTime();// Instant <-> LocalDateTimeInstant instant = Instant.now();LocalDateTime dateTimeFromInstant = LocalDateTime.ofInstant(instant, ZoneId.of("America/Los_Angeles"));Instant instantFromDateTime = LocalDateTime.now().toInstant(ZoneOffset.ofHours(-2));// convert old date/calendar/timezone classesInstant instantFromDate = new Date().toInstant();Instant instantFromCalendar = Calendar.getInstance().toInstant();ZoneId zoneId = TimeZone.getDefault().toZoneId();ZonedDateTime zonedDateTimeFromGregorianCalendar = new GregorianCalendar().toZonedDateTime();// convert to old classesDate dateFromInstant = Date.from(Instant.now());TimeZone timeZone = TimeZone.getTimeZone(ZoneId.of("America/Los_Angeles"));GregorianCalendar gregorianCalendar = GregorianCalendar.from(ZonedDateTime.now()); |
Вывод
С Java 8 мы получаем очень богатый API для работы с датой и временем, расположенный в пакете java.time. API может полностью заменить старые классы, такие как java.util.Date или java.util.Calendar, новыми, более гибкими классами. Благодаря главным образом неизменяемым классам новый API помогает в построении многопоточных систем.
- Источник примеров можно найти на GitHub .