Как преобразовать java.sql.timestamp в LocalDate (java8) java.time?

Ответы:

196

Ты можешь сделать:

timeStamp.toLocalDateTime().toLocalDate();

Обратите внимание, что для преобразования timestamp.toLocalDateTime() будет использоваться Clock.systemDefaultZone()часовой пояс. Это может быть то, что вы хотите, а может и не быть.

assylias
источник
1
Это было добавлено в Java 8.
assylias
54
Просто примечание, timestamp.toLocalDateTime()метод будет использовать часовой пояс systemDefault для преобразования. Это может быть то, что вы хотите, а может и не быть.
jacobhyphenated
1
@jacobhyphenated, пожалуйста, отправьте ответ, используя явный часовой пояс. Спасибо!
user482745
Комментарий @ jacobhyphenated здесь чрезвычайно важен, отсюда и количество голосов за него. Подробности см. В моем ответе stackoverflow.com/a/57101544/2032701
Руслан
@jacobhyphenated LocalDateTimeвсегда использует часовой пояс по умолчанию. Вот что означает «местный» в его названии.
М. Прохоров
21

Принятый ответ не идеален, поэтому я решил добавить свои 2 цента

timeStamp.toLocalDateTime().toLocalDate();

- плохое решение в целом , я даже не уверен, почему они добавили этот метод в JDK, поскольку он действительно сбивает с толку, выполняя неявное преобразование с использованием системного часового пояса. Обычно при использовании только классов даты java8 программист вынужден указывать часовой пояс, что хорошо.

Хорошее решение

timestamp.toInstant().atZone(zoneId).toLocalDate()

Где zoneId - это часовой пояс, который вы хотите использовать, обычно это либо ZoneId.systemDefault (), если вы хотите использовать системный часовой пояс, либо какой-либо жестко заданный часовой пояс, например ZoneOffset.UTC

Общий подход должен быть

  1. Освободитесь от новых классов даты java8, используя класс, который напрямую связан, например, в нашем случае java.time.Instant напрямую связан с java.sql.Timestamp , то есть между ними не требуется преобразования часовых поясов .
  2. Используйте хорошо продуманные методы этого класса java8, чтобы поступать правильно. В нашем случае atZone (zoneId) явно дал понять, что мы выполняем преобразование и используем для него определенный часовой пояс.
Руслан
источник
1
Я не согласен. Отметка времени (а также дата) не имеют информации о зоне. LocalDate не имеет информации о зоне, поэтому они эквивалентны. Преобразование между ними может выполняться независимо от какой-либо конкретной зоны. Преобразование в ZonedDateTime перед преобразованием в LocalDate добавляет часовой пояс, а затем снова снимает его - у вас гораздо больше шансов получить неприятную ошибку - трудно найти -, делая это таким образом.
AutomatedMike
5
@AutomatedMike Timestamp (а также Date) представляет собой момент времени в формате UTC. LocalDate не представляет собой момент времени, а скорее время, которое можно увидеть на настенных часах. Пожалуйста, прочтите их javadocs. «Преобразование между ними может выполняться независимо от какой-либо конкретной зоны» - неверно , новая метка времени (0L) .toLocalDateTime () возвращает «1970-01-01T03: 00» для моего часового пояса в Москве. Результат может быть другим для вашего часового пояса.
Руслан
1
@AutomatedMike Даже если вы уберете время, выполнив toLocalDate (), легко доказать, что день может быть неправильным, если в метке времени было время около полуночи, например new Timestamp (1000 * 60 * 60 * 23) .toLocalDateTime (). ToLocalDate () возвращает "1970-01-02" для моего московского часового пояса, когда это "1970-01-01" по UTC.
Руслан
1
@AutomatedMike «добавляет часовой пояс, а затем снова его снимает» - суть не в добавлении и удалении часового пояса, а в преобразовании между разными понятиями с использованием явного часового пояса. Это контрастирует с примерами из двух моих предыдущих комментариев, где часовой пояс применяется неявно .
Руслан
7

Я немного расширю ответ @assylias, чтобы учесть часовой пояс. Есть как минимум два способа получить LocalDateTime для определенного часового пояса.

Вы можете использовать часовой пояс setDefault для всего приложения. Его следует вызывать перед любым преобразованием timestamp -> java.time:

public static void main(String... args) {
    TimeZone utcTimeZone = TimeZone.getTimeZone("UTC");
    TimeZone.setDefault(utcTimeZone);
    ...
    timestamp.toLocalDateTime().toLocalDate();
}

Или вы можете использовать цепочку toInstant.atZone:

timestamp.toInstant()
        .atZone(ZoneId.of("UTC"))
        .toLocalDate();
Павел
источник