Преобразование между java.время.LocalDateTime и java.утиль.Дата
Java 8 имеет совершенно новый API для даты и времени. Одним из самых полезных классов в этом API является LocalDateTime
, для проведения независимого от часового пояса значения даты со временем.
вероятно, есть миллионы строк кода, использующих устаревший класс java.util.Date
для этой цели. Таким образом, при взаимодействии старого и нового кода возникнет необходимость в преобразовании между ними. Поскольку, по-видимому, нет прямых методов для достижения этого, как это можно сделать?
7 ответов
короткий ответ:
Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
Date out = Date.from(ldt.atZone(ZoneId.systemDefault()).toInstant());
объяснение:
(на основе этот вопрос о LocalDate
)
несмотря на свое название, java.util.Date
представляет собой момент на временной линии, а не "дата". Фактические данные, хранящиеся в объекте, являются long
отсчет миллисекунд с 1970-01-01T00:00Z (полночь в начале 1970 GMT/UTC).
эквивалентный класс java.util.Date
в JSR-310 это Instant
, таким образом удобные методы для того чтобы обеспечить преобразование туда и обратно:
Date input = new Date();
Instant instant = input.toInstant();
Date output = Date.from(instant);
A java.util.Date
экземпляр не имеет понятия часового пояса. Это может показаться странным, если вы называете toString()
на java.util.Date
, потому что toString
относительно часового пояса. Однако этот метод фактически использует часовой пояс Java по умолчанию на лету, чтобы предоставить строку. Часовой пояс не является частью фактического состояния java.util.Date
.
An Instant
также не содержит информации о часовом поясе. Таким образом, преобразовать из Instant
в местный дата-время необходимо указать часовой пояс. Это может быть зона по умолчанию - ZoneId.systemDefault()
- или это может быть часовой пояс, который контролирует ваше приложение, например часовой пояс из пользовательских настроек. LocalDateTime
имеет удобный заводской метод, который занимает как мгновенный, так и часовой пояс:
Date in = new Date();
LocalDateTime ldt = LocalDateTime.ofInstant(in.toInstant(), ZoneId.systemDefault());
в обратном направлении,LocalDateTime
часовой пояс определяется путем вызова atZone(ZoneId)
метод. The ZonedDateTime
затем можно преобразовать непосредственно в Instant
:
LocalDateTime ldt = ...
ZonedDateTime zdt = ldt.atZone(ZoneId.systemDefault());
Date output = Date.from(zdt.toInstant());
обратите внимание, что преобразование из LocalDateTime
to ZonedDateTime
имеет потенциал для введения неожиданного поведения. Это связано с тем, что не каждая локальная дата-время существует из-за летнего времени. Осенью / Осенью происходит перекрытие в локальной временной линии, где одна и та же локальная дата-время происходит дважды. Весной есть промежуток, где исчезает час. См. Javadoc atZone(ZoneId)
для большего определения того, что будет делать преобразование.
резюме, если вы туда-обратно в java.util.Date
в LocalDateTime
и java.util.Date
вы можете в конечном итоге с другим моментом из-за летнего времени.
дополнительная информация: есть еще одна разница, которая повлияет на очень старые даты. java.util.Date
использует календарь, который имеет шансы на 15 октября 1582 года, с датами до этого, используя Юлианский календарь вместо григорианского. Напротив,java.time.*
использует систему календаря ISO (эквивалентную Григорианской) на все время. В большинстве случаев вы хотите использовать систему календаря ISO, но вы можете увидеть странные эффекты при сравнении дат до 1582 года.
вот что я придумал ( и, как и все головоломки времени даты, это, вероятно, будет опровергнуто на основе какой-то странной настройки часового пояса-прыжка-дневного света :D )
цикл: Date
> LocalDateTime
дано: Date date = [some date]
(1) LocalDateTime
InstantDate
Instant instant = Instant.ofEpochMilli(date.getTime());
LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
(2) Date
Instant LocalDateTime
Instant instant = ldt.toInstant(ZoneOffset.UTC);
Date date = Date.from(instant);
пример:
дано:
Date date = new Date();
System.out.println(date + " long: " + date.getTime());
(1) LocalDateTime
InstantDate:
создать Instant
С Date
:
Instant instant = Instant.ofEpochMilli(date.getTime());
System.out.println("Instant from Date:\n" + instant);
создать Date
С Instant
(не обязательно,но для наглядности):
date = Date.from(instant);
System.out.println("Date from Instant:\n" + date + " long: " + date.getTime());
создать LocalDateTime
С Instant
LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
System.out.println("LocalDateTime from Instant:\n" + ldt);
(2) Date
Instant LocalDateTime
создать Instant
С LocalDateTime
:
instant = ldt.toInstant(ZoneOffset.UTC);
System.out.println("Instant from LocalDateTime:\n" + instant);
создать Date
С Instant
:
date = Date.from(instant);
System.out.println("Date from Instant:\n" + date + " long: " + date.getTime());
выход:
Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574
Instant from Date:
2013-11-01T14:13:04.574Z
Date from Instant:
Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574
LocalDateTime from Instant:
2013-11-01T14:13:04.574
Instant from LocalDateTime:
2013-11-01T14:13:04.574Z
Date from Instant:
Fri Nov 01 07:13:04 PDT 2013 long: 1383315184574
гораздо более удобный способ, если вы уверены, что вам нужен часовой пояс по умолчанию :
Date d = java.sql.Timestamp.valueOf( myLocalDateTime );
следующее, кажется, работает при преобразовании из нового API LocalDateTime в java.утиль.дата:
Date.from(ZonedDateTime.of({time as LocalDateTime}, ZoneId.systemDefault()).toInstant());
обратное преобразование может быть (надеюсь) достигнуты подобным образом...
надеюсь, что это помогает...
Я не уверен, что это самый простой или лучший способ, или если есть какие-либо подводные камни, но он работает:
static public LocalDateTime toLdt(Date date) {
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(date);
ZonedDateTime zdt = cal.toZonedDateTime();
return zdt.toLocalDateTime();
}
static public Date fromLdt(LocalDateTime ldt) {
ZonedDateTime zdt = ZonedDateTime.of(ldt, ZoneId.systemDefault());
GregorianCalendar cal = GregorianCalendar.from(zdt);
return cal.getTime();
}
все здесь:http://blog.progs.be/542/date-to-java-time
ответ с "круглым отключением" не является точным : когда вы делаете
LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
если ваш системный часовой пояс не UTC / GMT, вы меняете время !
Если вы находитесь на android и используете threetenbp можно использовать DateTimeUtils
вместо.
ex:
Date date = DateTimeUtils.toDate(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
вы не можете использовать Date.from
так как он поддерживается только на api 26+