Как считать время в java
Перейти к содержимому

Как считать время в java

  • автор:

Как посчитать время потраченное на выполнение задания?

Пишу маленькое приложение на Android на Java. У меня пользователи в одном активити проходят тест и, по завершению теста, открывается следующее активити, в которое передается итоговая инфа по прохождению теста. Так вот, одно из полей — это потраченное время на задание. я пробую считать время хронометром, но он в миллисекундах считает и потом форматировать через различные проверки в формат 00:00 (02 : 34), очень костыльно получается. Я уверен, что есть более изящное решение. Как это можно сделать?

Отслеживать

5,185 3 3 золотых знака 23 23 серебряных знака 48 48 бронзовых знаков

задан 14 дек 2015 в 21:13

10.9k 17 17 золотых знаков 62 62 серебряных знака 127 127 бронзовых знаков

Измерьте прошедшее время (или время выполнения) в Java

В этом посте будет обсуждаться, как измерить прошедшее время в Java, используя System.nanoTime() , System.currentTimeMillis() , Instant.now() а также StopWatch предоставлено Guava и Apache Commons Lang.

1. Использование System.nanoTime() метод

Мы можем использовать System.nanoTime() для измерения прошедшего времени с точностью до наносекунды. Он возвращает текущее значение источника времени с высоким разрешением работающей JVM в наносекундах.

Значение, возвращаемое этим методом, само по себе не имеет значения, но оно может стать значимым при вычислении разницы между двумя такими значениями.

import java . util . concurrent . TimeUnit ;
// Программа для измерения прошедшего времени на Java
class Main
public static void main ( String [ ] args ) throws InterruptedException
long startTime = System . nanoTime ( ) ;
/* … Измеряемый код начинается … */
// спать 5 секунд
TimeUnit . SECONDS . sleep ( 5 ) ;
/* … Измеряемый код заканчивается … */
long endTime = System . nanoTime ( ) ;
// получаем разницу между двумя значениями нано-времени
long timeElapsed = endTime — startTime ;
System . out . println ( «Execution time in nanoseconds: » + timeElapsed ) ;
System . out . println ( «Execution time in milliseconds: » + timeElapsed / 1000000 ) ;

Выход (может варьироваться):

Execution time in nanoseconds : 5000372657
Execution time in milliseconds: 5000

2. Использование System.currentTimeMillis() метод

Java System класс также предоставляет статический метод currentTimeMillis() который возвращает разницу между текущим временем и полуночью 1 января 1970 года по всемирному координированному времени в миллисекундах.

Идеально, currentTimeMillis() следует использовать для измерения времени настенных часов, и nanoTime() должен измерять прошедшее время программы. Если прошедшее время измеряется с помощью System.currentTimeMillis() , результаты могут быть неточными.

Основы API Time для Java

Во многих языках программирования работа с датой и временем — непростая задача. Но, начиная с Java 8, JDK предоставляет новый API Time, полностью меняющий подход к концепциям, которые относятся к времени.

Примечания. Хотя JSR 310 был представлен в Java 8, для большей удобочитаемости в приведенных примерах кода задействована такая функция Java 10, как вывод типа локальной переменной. Однако сами примеры кода совместимы с Java 8. В части примеров, содержащих // => , будет показан вывод toString() предыдущей строки/переменной.

До JSR310

До появления нового API в JDK было лишь несколько классов для обработки даты и времени.

Вот наиболее известные из них.

  • java.util.Date — конкретный момент времени с точностью до миллисекунды, например 1 января 1970 года 00:00:00 по Гринвичу.
  • java.util.Calendar — мостик между моментом времени и параметрами календаря, например месяц, год, день и т. д.
  • java.util.TimeZone отвечает за смещение часовых поясов и обработку летнего времени (DST).
  • java.text.DateFormat — форматирование и парсинг.

На первый взгляд эти четыре варианта охватывают наиболее распространенные сценарии. Но действительно ли они способны справиться со всеми деликатными особенностями даты и времени?

Миллисекунды

Поскольку java.util.Date базируется на миллисекундах, мы склонны думать о дате и времени как о сумме миллисекунд.

static long MILLIS_PER_MINUTE = 1_000L * 60L; // 60_000L

static long MILLIS_PER_HOUR = MILLIS_PER_MINUTE * 60L; // 3_600_000L

static long MILLIS_PER_DAY = MILLIS_PER_HOUR * 24L; // 86_400_000L

Использование миллисекунд может показаться интуитивно понятным, но в конечном итоге приводит к ошибкам.

Работать со временем сложно из-за интуитивных предположений о дате и времени, которые не соответствуют действительности. Дейв ДеЛонг ведет большой список таких представлений с краткими объяснениями. Вот несколько таких неверных предположений.

  • Дни длятся 86 400 секунд.
  • Полночь бывает каждый день.
  • Границы часовых поясов всегда проходят по ровным часам.

Проблема с граничными случаями в том, что мы часто не осознаем их существования, пока не столкнемся с ними. Если наш код ломается только в високосные годы, он может нормально работать до четырех лет.

Не все — идеальный момент во времени

Date представляет один момент времени с точностью до миллисекунды. Но как насчет более широких единиц?

В какой день начинается январь 2021 года? Во сколько наступает 6 января?

Нам нужно представлять различные концепции даты и времени, помимо одной точки.

  • Даты без указания времени: 30 декабря 2020 года.
  • Время без дат: 12:24.
  • Месяц и годы: декабрь 2020 года.
  • Годы: 2020 год.
  • Сроки: 7 дней.
  • Различные календарные системы: японский календарь.

Эти концепции приходилось реализовывать самостоятельно с помощью контрактов кода, например представлять даты без указания времени в виде java.util.Date со временем полночь. Из-за таких контрактов снижается гибкость данных, и они легко ломаются. Эти крайние случаи и соображения могут легко привести ко многим ошибкам, которые не сразу становятся очевидными.

Joda Time

К счастью, сторонний фреймворк Joda-Time предоставляет лучшую концепцию для работы с датами и временем, благодаря чему он стал стандартной библиотекой до Java 8. Однако, начиная с Java 8, на его основе был разработан новый API Time.

API Time Java (JSR 310)

Для устранения ранее упомянутых недостатков понадобился совершенно новый API. Он был разработан с нуля при участии автора Joda-Time Стивена Коулборна, который возглавлял работу. Результатом стало полное и всестороннее дополнение к JDK. Но чем этот API настолько лучше предшественника?

Цели проектирования

Новый API разрабатывался с учетом нескольких основных принципов.

Неизменяемость. Каждый тип должен быть по возможности неизменяемым. Преимущества неизменяемости хорошо известны: потокобезопасность, снижение числа ошибок из-за отсутствия состояний и лучшая совместимость со сборщиком мусора.

Гибкость API. Гибкий код — это понятный код, с которым легче работать.

Ясность, очевидность, ожидаемый результат. Каждый метод должен быть четко определен и понятен. Управляемый доменом дизайн с согласованными префиксами имен методов повышает ясность и читаемость.

Расширяемость. ISO 8601 — наиболее распространенная и основная для нового API календарная система. Однако нужна возможность пользоваться и другими календарями, которые могли бы предоставлять разработчики приложений, а не только сам JDK.

Локальные типы

Новый пакет java.time.* содержит много различных типов, каждый из которых предназначен для определенной цели. Сначала изучим типы Local , которые отделены от концепции часовых поясов.

java.time.LocalDate

В соответствии с названием, этот тип представляет дату без часового пояса: только день, месяц и год.

var date = LocalDate.of(2021, 1, 1);// => 2021-01-01

java.time.LocalTime

Это время без даты и часового пояса. Применяется стандартное определение времени: время внутри суток, в 24-часовом формате, начиная с полуночи.

LocalTime хранит часы, минуты, секунды и наносекунды. Хотя данный тип поддерживает точность вплоть до наносекунд, имейте в виду, что фактическая точность зависит от реализации JVM/JDK.

var now = LocalTime.now();
// => 12:45:38.896793

var time = LocalTime.of(12, 45);
// => 12:45

java.util.LocalDateTime

Это комбинация LocalTime и LocalDate .

var dt = LocalDateTime.of(2021, 1, 1, 12, 45);// => 2021-01-01T12:45

Есть возможность легко декомпозировать на составляющие:

var dt = LocalDateTime.of(2021, 1, 1, 12, 45);
// => 2021-01-01T12:45

var date = dt.toLocalDate();
// => 2021-01-01

var time = dt.toLocalTime();
// => 12:45

Часовые пояса и смещения

Часовые пояса и их смещения — проклятие всех, кто работает со временем. При работе с ними можно допустить много ошибок (что обычно и происходит).

Чтобы это исправить, API Time разделяет ответственность на несколько классов.

  • ZoneOffset — смещение от времени в UTC/GMT, от +14:00 до -12:00.
  • ZoneRules — правила изменения смещения для одного часового пояса (например, летнее время, исторические изменения).
  • ZoneId — идентификатор часового пояса, например Европа/Берлин.

Доступны два различных типа часовых поясов.

  • ZonedDateTime — привязка к определенному ZoneId .
  • OffsetDateTime / OffsetTime — дата/время со смещением, но не привязанные к определенному часовому поясу.

java.time.OffsetDateTime / java.time.OffsetTime

OffsetDateTime — это упрощенная версия ZonedDateTime без привязки к конкретному часовому поясу, определенная только смещением. Она больше подходит для форматов обмена, таких как сохранение в базах данных или JSON/XML.

var dt = LocalDateTime.of(2021, 1, 1, 12, 45);
// => 2021-01-01T12:45

var offset = ZoneOffset.of("+02:00");
// => +02:00

var odt = OffsetDateTime.of(dt, offset);
// => 2021-01-01T12:45+02:00

java.time.ZonedDateTime

Смещения часто бывает достаточно, но иногда нужно обрабатывать данные, относящиеся к конкретному часовому поясу. Для таких случаев существует ZonedDateTime .

var dt = LocalDateTime.of(2021, 1, 1, 12, 45);
// => 2021-01-01T12:45

var zoneId = ZoneId.of("Europe/Berlin");
// => Europe/Berlin

var zdt = ZonedDateTime.of(dt, zoneId);
// => 2021-01-01T12:45+01:00[Europe/Berlin]

Другие типы даты и времени

Помимо типов даты, времени и даты/времени, новый API содержит специальные классы и для других концепций.

java.time.Instant

Instant — ближайший доступный эквивалент java.util.Date . Это классическая временная метка по отношению к эпохе. По умолчанию эпоха начинается с метки времени Unix “0” (1970–01–01T00:00:00Z, полночь в начале 1 января 1970 UTC).

var instant = Instant.ofEpochSecond(1609505123);// => 2021-01-01T12:45:23Z

Этот тип можно преобразовать в другие, если предоставить недостающую информацию. Например, чтобы создать LocalDateTime , нужно указать соответствующий ZoneId . В таком случае можно будет применить правила, такие как летнее время и смещение.

var instant = Instant.ofEpochSecond(1609505123);
// => 2021-01-01T12:45:23Z

var zoneId = ZoneId.of("Europe/Berlin");
// => Europe/Berlin

var dt = LocalDateTime.ofInstant(instant, zoneId);
// 2021-01-01T13:45:23

java.time.Duration

Duration представляет собой промежуток, основанный на времени (часы, минуты, секунды, наносекунды). Его можно создать либо напрямую, либо вывести в качестве разности между другими типами:

var sixHours = Duration.ofHours(6);
// => PT6H

var lhs = LocalDateTime.of(2020, 12, 24, 15, 22, 23);
var rhs = LocalDateTime.of(2021, 1, 1, 12, 45, 18);

var diff = Duration.between(lhs, rhs);
// => PT189H22M55S

java.time.Period

Period — двойник Duration , только не на основе промежутка времени, а на основе даты (года, месяца, дня).

var threeQuarters = Period.ofMonths(9);
// => P9M

var lhs = LocalDate.of(2020, 7, 12);
var rhs = LocalDate.of(2021, 1, 1);

var diff = Period.between(lhs, rhs);
// => P5M20D

java.time.Year

Год по календарю ISO.

var jan2021 = YearMonth.of(YearMonth.of(2021, Month.JANUARY));// => 2021-01

Имейте в виду: соответствие между григорианским и юлианским календарями есть только для недавних лет. Например, некоторые области России перешли на современный григорианский календарь только в 1920 году. Кроме того, многочисленные календарные реформы могут дополнительно усложнить расчеты с использованием исторических дат.

java.time.YearMonth

Тип даты без указания дня, к примеру январь 2021 года.

var jan2021 = YearMonth.of(YearMonth.of(2021, Month.JANUARY));// => 2021-01

java.time.MonthDay

Указание даты без года, например 6 января.

var threeKingsDay = MonthDay.of(Month.JANUARY, 6);// --01-06

Строка вывода может показаться странной, но подобный вид точно так же определен в стандарте ISO 8601:2000. Однако обновленный стандарт ISO 8601:2004 запрещает пропускать год, если присутствует месяц.

Перечисления Month / DayOfWeek

Еще один источник множества багов — разовые ошибки, связанные с месяцами и днями недели.

  • Январь представлен цифрой 1 или цифрой 0?
  • А декабрь — 11 или 12?
  • Когда начинается неделя? В воскресенье или в понедельник?
  • Какими значениями представлены эти дни?

Поскольку API Java Time основан на стандарте ISO 8601, неделя всегда начинается в понедельник. Чтобы сохранять последовательность, для понедельника и января используются значения 1.

Для большего удобства представлены два перечисления, которые в большинстве методов взаимозаменяемы с числовыми значениями.

var january2021 = YearMonth.of(2021, Month.JANUARY);
var wednesday = LocalDateTime.now().with(DayOfWeek.WEDNESDAY);
  • java.time.Month ;
  • java.time.DayOfWeek .

Общий дизайн API

Когда в API много новых классов, приходится запоминать большое количество новых методов и концепций. Чтобы облегчить когнитивную нагрузку, API был разработан с согласованными префиксами имен методов и общими концепциями между типами.

Префиксы имен методов

Можно легко изучить различные возможности типа, просто запустив автозаполнение после запуска префикса.

Классический геттер для извлечения частей типа.

var date = LocalDate.of(2021, Month.JANUARY, 1);
var year = date.getYear();
// => 2021

Возвращает копию с некоторым изменением.

var date = LocalDate.of(2021, Month.JANUARY, 1);
date = date.withDayOfMonth(15)
// => 2021-01-15

Возвращает копию с результатом вычисления.

var date = LocalDate.of(2021, Month.JANUARY, 1);
date = date.plusDays(15L);
date = date.minusYears(10L)
// => 2011-01-16
  • multipliedBy/dividedBy/negated

Дополнительные вычисления для Duration / Period .

var quarter = Period.ofMonths(3);
var fourQuarters = quarter.multipliedBy(4);
// => P12M

Преобразование между типами.

var dt = LocalDateTime.of(2021, 1, 1, 12, 45);

var date = dt.toLocalDate();
// => 2021-01-01

var time = dt.toLocalTime();
// => 12:45

Возвращает новый объект с изменениями относительно часового пояса.

var date = LocalDate.of(2021, 1, 1);

LocalDateTime dt = date.atTime(12, 45);
// => 2021-01-01T12:45

var zoneId = ZoneId.of("Europe/Berlin");

ZonedDateTime zdt = dt.atZone(zoneId);
// => 2021-01-01T12:45+01:00[Europe/Berlin]

Статические методы фабрики без преобразований.

var date = LocalDate.of(2021, 1, 1);

var zoneId = ZoneId.of("Europe/Berlin");

Статические методы фабрики c преобразованием.

var dt = LocalDateTime.of(2021, 1, 1, 12, 45);

var date = LocalDate.from(dt);
// => 2021-01-01

Имейте в виду, что преобразование работает только для нисходящих операций. К примеру, нельзя создать LocalDateTime из LocalDate :

var date = LocalDate.of(2021, 1, 1);
var dt = LocalDateTime.from(date);
// Выбросит исключение:
// Exception java.time.DateTimeException: Unable to obtain LocalDateTime from TemporalAccessor: 2021-01-01 of type java.time.LocalDate
// | at LocalDateTime.from (LocalDateTime.java:461)
// | at do_it$Aux (#47:1)
// | at (#47:1)
// | Caused by: java.time.DateTimeException: Unable to obtain LocalTime from TemporalAccessor: 2021-01-01 of type java.time.LocalDate
// | at LocalTime.from (LocalTime.java:431)
// | at LocalDateTime.from (LocalDateTime.java:457)
// | .

Статические методы фабрики для обработки текстового ввода.

var date = LocalDate.parse("2021-01-01");

var dt = LocalDateTime.parse("2021-01-01T12:45:32");

Парсинг и форматирование

У всех типов определены методы toString() , основанные на стандарте ISO 8601.

TYPE | FORMAT
----------------|-------------------------------------
LocalDate | uuuu-MM-dd
LocalTime | HH:mm
| HH:mm:ss
| HH:mm:ss.SSS
| HH:mm:ss.SSSSSS
| HH:mm:ss.SSSSSSSSS
LocalDateTime | uuuu-MM-dd'T'HH:mm
| uuuu-MM-dd'T'HH:mm:ss
| uuuu-MM-dd'T'HH:mm:ss.SSS
| uuuu-MM-dd'T'HH:mm:ss.SSSSSS
| uuuu-MM-dd'T'HH:mm:ss.SSSSSSSSS
Year | value without leading zeroes
YearMonth | uuuu-MM
MonthDay | --MM-dd
OffesetDateTime | uuuu-MM-dd'T'HH:mmXXXXX
| uuuu-MM-dd'T'HH:mm:ssXXXXX
| uuuu-MM-dd'T'HH:mm:ss.SSSXXXXX
| uuuu-MM-dd'T'HH:mm:ss.SSSSSSXXXXX
| uuuu-MM-dd'T'HH:mm:ss.SSSSSSSSSXXXXX
OffestTime | HH:mm:ssXXXXX
| HH:mm:ss.SSSXXXXX
| HH:mm:ss.SSSSSSXXXXX
| HH:mm:ss.SSSSSSSSSXXXXX
ZonedDateTime | LocalDateTime + ZoneOffset
ZoneOffset | Z (for UTC)
| +h
| +hh
| +hh:mm
| -hh:mm
| +hhmm
| -hhmm
| +hh:mm:ss
| -hh:mm:ss
| +hhmmss
| -hhmmss
Duration | PT[n]H[n]M[n]S
Period | P[n]Y[n]M[n]D

Формат, созданный через toString() , также доступен в соответствующих методах parse(CharSequence text) , что отлично подходит для методов обмена или нелокализованного отображения.

Для более понятных и локализованных представлений можно воспользоваться классом java.time.format.DateTimeFormatter . Он потокобезопасен, неизменяем и предоставляет гибкий API:

var formatted = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL) 
.withLocale(Locale.GERMAN)
.format(LocalDate.of(2021, 1, 1))
// => Freitag, 1. Januar 2021

Его также можно применить для парсинга, предоставив форматер для метода parse :

var formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL) 
.withLocale(Locale.GERMAN);

var parse = LocalDate.parse("Freitag, 1. Januar 2021", formatter);
// => 2021-01-01

java.time.TemporalAdjuster

С помощью функционального интерфейса TemporalAdjuster можно определить стратегии настройки типов, реализующих Temporal . Таким образом можно получить четко определенные, повторно используемые настройки для новых типов API Time.

API Time предоставляет несколько предопределенных регуляторов через служебный класс TemporalAdjusters . Названия методов (в основном) говорят сами за себя:

dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek)firstDayOfMonth()
firstDayOfNextMonth()
firstDayOfNextYear()
firstDayOfYear()
firstInMonth(DayOfWeek dayOfWeek)
lastDayOfMonth()
lastDayOfYear()
lastInMonth(DayOfWeek dayOfWeek)
next(DayOfWeek dayOfWeek)
nextOrSame(DayOfWeek dayOfWeek)
ofDateAdjuster(UnaryOperator dateBasedAdjuster)previous(DayOfWeek dayOfWeek)
previousOrSame(DayOfWeek dayOfWeek)

Например, в приложении, где есть платная подписка, можно создать настройки для конкретных клиентов, такие как следующая дата выставления счета nextBillingDate(Customer customer) . Код легко читаем, а вся логика расчета даты выставления счета в зависимости от клиента находится в одном месте.

java.time.temporal.TemporalUnit и java.time.temporal.ChronoUnit

Интерфейс TemporalUnit предоставляет способ выражения единиц даты и времени, которые затем можно задействовать в расчетах.

Наиболее востребованные единицы измерения уже доступны в перечислении ChronoUnit , где предоставлены константы для всевозможных видов единиц измерения, таких как MILLENNIA , DAYS , HOURS , MILLIS и т. д.

Помимо конкретных методов расчета, таких как LocalDate plusDays(long daysToAdd) , существуют также неспецифические методы, для которых требуется TemporalUnit , например LocalDate plus(long amountToAdd, TemporalUnit unit) .

Все вычисления API Time по возможности сохраняют рациональность, а также остаются в пределах своей единицы и связанных с ней более крупных единиц. Новые типы — скорее комбинации различных единиц измерения, а не единичные значения.

Это означает, что если мы добавим месяц к LocalDate , это повлияет на месяц (и связанные с ним единицы, такие как год).

var date = LocalDate.of(2021, 1, 31);
// 2021-01-31

date = date.plus(1L, ChronoUnit.MONTHS);
// => 2021-02-28

Разницу также легко подсчитать с помощью ChronoUnit . В случае LocalDate :

var startDate = LocalDate.of(2021, 1, 1);
// 2021-01-01

var endDate = LocalDate.of(2023, 11, 8);
// 2023-11-08

var amount = startDate.until(endDate, ChronoUnit.WEEKS);
// => 148

Само значение перечисления содержит два метода для большей понятности кода вычислений.

  • R addTo(R temporal, long amount) ;
  • long between(Temporal temporal1Inclusive, Temporal temporal2Exclusive) .

Предыдущие примеры также можно выразить через эти методы:

var date = LocalDate.of(2021, 1, 31);
// 2021-01-31

date = ChronoUnit.MONTHS.addTo(date, 1L);
// => 2021-02-28


var startDate = LocalDate.of(2021, 1, 1);
// => 2021-01-01

var endDate = LocalDate.of(2023, 11, 8);
// => 2023-11-08

var amount = ChronoUnit.WEEKS.between(startDate, endDate);
// => 148

В сочетании со static import читаемость повышается еще больше:

import static java.time.temporal.ChronoUnit;

var date = LocalDate.of(2021, 1, 31);
// => 2021-01-31

date = MONTHS.addTo(date, 1L);
// 2021-02-28


var startDate = LocalDate.of(2021, 1, 1);
// => 2021-01-01

var endDate = LocalDate.of(2023, 11, 8);
// => 2023-11-08

var amount = WEEKS.between(startDate, endDate);
// => 148

Константы перечисления также представимы в виде Duration в рамках календаря ISO:

ChronoUnit.HALF_DAYS.getDuration();
// => PT12H

ChronoUnit.WEEKS.getDuration();
// => PT168H

ChronoUnit.CENTURIES.getDuration();
// => PT876582H

Преобразование между типами

Нельзя просто взять и заменить все экземпляры java.util.Date одним из новых типов. Поэтому необходима возможность осуществлять преобразование между ними. Метод java.util.Date#toInstant() обеспечивает связь между старыми и новыми датами.

Instant может быть преобразован в другой тип, если предоставлены соответствующие данные относительно часового пояса:

Соответствующий код вполне понятен:

// Шаг 1: Есть объект даты до-JSR310
var date = new Date();

// Шаг 2: Определить подходящий часовой пояс
var zone = ZoneId.systemDefault();

// Шаг 3: Преобразовать дату в Instant
var instant = date.toInstant();

// SШаг 4: Преобразовать в ZonedDateTime
var zdt = instant.atZone(zone);

Теперь можно воспользоваться еще одним методом to для дальнейших преобразований.

Поддержка Android

В прошлом многие функции Java 8+ не сразу были доступны для Android. Для них требовался либо сторонний фреймворк, либо бэкпорты.

Благодаря плагину Android Gradle 4.0 многие функции Java 8 можно использовать с помощью десахаризацию без необходимости повышать уровень API. Однако потребуются некоторые изменения в build.gradle и новая зависимость:

android defaultConfig // Требуется при установке minSdkVersion на 20 или ниже 
multiDexEnabled true
>

compileOptions // Отметка для получения поддержки нового API языка
coreLibraryDesugaringEnabled true
// Установка совместимости с Java 8
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
>
>

dependencies coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.9'
>

Список всех API, доступных через десахаризацию, можно найти здесь.

API Time для Java 6 и 7

Хотя Java 8 вышла шесть лет назад, не все могут позволить себе перейти на эту версию. Но не отчаивайтесь. Благодаря бэкпорту у вас остается возможность воспользоваться новым API.

Проект ThreeTen Backport предоставляет совместимый с Java 6 и 7 способ применения новых типов без дополнительных зависимостей. Проект поддерживается главным автором API Time Стивеном Коулборном.

Ссылки

  • JSR-310 Date and Time API Guide (JCP.org).
  • Package java.time (Oracle).
  • ISO 8601 (Wikipedia).
  • ThreeTen Backport.
  • 3 применения исключений, которые улучшат навыки программирования на Java
  • Осваиваем реактивное программирование на Java
  • Асинхронность в Java

Как рассчитать разницу времени и даты в Java

В этом уроке мы покажем вам 2 примера для вычисления разницы даты / времени в Java:

  1. Ручной расчет времени.
  2. Библиотека времени Йода.

1. Ручной расчет времени

Обращенные Date в миллисекундах (мс) и рассчитайте разницу между двумя датами по следующим правилам:

 1000 milliseconds = 1 second 60 seconds = 1 minute 60 minutes = 1 hour 24 hours = 1 day 
 package com.csharpcoderr.date; import java.text.SimpleDateFormat; import java.util.Date; public class DateDifferentExample < public static void main(String[] args) < String dateStart = "01/14/2012 09:29:58"; String dateStop = "01/15/2012 10:31:48"; // ЧЧ преобразует часы в 24-часовой формат (0-23), расчет дня SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss"); Date d1 = null; Date d2 = null; try < d1 = format.parse(dateStart); d2 = format.parse(dateStop); // в миллисекундах long diff = d2.getTime() - d1.getTime(); long diffSeconds = diff / 1000 % 60; long diffMinutes = diff / (60 * 1000) % 60; long diffHours = diff / (60 * 60 * 1000) % 24; long diffDays = diff / (24 * 60 * 60 * 1000); System.out.print(diffDays + " days, "); System.out.print(diffHours + " hours, "); System.out.print(diffMinutes + " minutes, "); System.out.print(diffSeconds + " seconds."); >catch (Exception e) < e.printStackTrace(); >> > 
 1 days, 1 hours, 1 minutes, 50 seconds. 

Почему секундам и минутам нужно% 60, а часам% 24?

Если вы измените его на

 long diffSeconds = diff / 1000; 
 1 days, 1 hours, 1 minutes, 90110 seconds. 

« 90110 ”- общее количество секунд разницы между date1 а также date2 , это правильно, если вы хотите узнать разницу только в секундах.

ЧИТАТЬ ТАКЖЕ: Java MongoDB: обновить документ

Чтобы отобразить разницу в формате « день, час, минута и секунда », вы должны использовать модуль (% 60), чтобы обрезать оставшиеся секунды ( 90060 ). Понял? Идея применяется также в минутах (% 60) и часах (% 24).

 90110 % 60 = 50 seconds (you want this) 90110 - 50 = 90060 seconds (you dont want this) 

2. Пример Joda Time

Вот эквивалентный пример, но с использованием времени Joda для расчета различий между двумя датами.

PS Этот пример использует joda-time-2.1.jar

 package com.csharpcoderr.date; import java.text.SimpleDateFormat; import java.util.Date; import org.joda.time.DateTime; import org.joda.time.Days; import org.joda.time.Hours; import org.joda.time.Minutes; import org.joda.time.Seconds; public class JodaDateDifferentExample < public static void main(String[] args) < String dateStart = "01/14/2012 09:29:58"; String dateStop = "01/15/2012 10:31:48"; SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss"); Date d1 = null; Date d2 = null; try < d1 = format.parse(dateStart); d2 = format.parse(dateStop); DateTime dt1 = new DateTime(d1); DateTime dt2 = new DateTime(d2); System.out.print(Days.daysBetween(dt1, dt2).getDays() + " days, "); System.out.print(Hours.hoursBetween(dt1, dt2).getHours() % 24 + " hours, "); System.out.print(Minutes.minutesBetween(dt1, dt2).getMinutes() % 60 + " minutes, "); System.out.print(Seconds.secondsBetween(dt1, dt2).getSeconds() % 60 + " seconds."); >catch (Exception e) < e.printStackTrace(); >> > 
 1 days, 1 hours, 1 minutes, 50 seconds. 

Оставьте комментарий ниже, если у вас есть альтернативные способы ��

Рекомендации

  1. Второй в Википедии
  2. Официальный сайт Joda Time

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *