Преобразование между 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+