Java, конвертирующий полученную временную метку в мгновенную, дает неправильный день

Я сделал простой метод, который используется для преобразования метки времени, полученной из базы данных, в LocalDate. Однако по какой-то причине я продолжаю получать неправильный день в преобразовании. Я поделился кодом ниже.

    private LocalDate getLocalDateFromTimeStamp(Row row, String key){
        return LocalDate.parse(row.getTimestamp(key).toInstant().atZone(ZoneOffset.UTC).toLocalDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
}

Итак, я ожидаю дату 2022-12-21, но получаю 2022-12-22.

Когда я отлаживаю и проверяю, что

row.getTimestamp (ключ)

дает мне Date объект Wed Dec 21 20:47:46 CST 2022, чего я и ожидаю.

Когда я проверяю, что

row.getTimestamp(key).toInstant()

делает, я получаю "2022-12-22T02:47:46.299Z". И я думаю, что именно здесь возникает проблема, и я не уверен, почему это происходит. LocalDate, возвращаемый методом, — «2022-12-22».

Если бы кто-нибудь мог пролить свет на это, я был бы очень признателен, поскольку я не понимаю, почему это происходит.

Какой тип возвращает getTimeStamp(key)?

WJS 14.02.2023 21:27

@WJS Возвращает объект Date.

skippy130 14.02.2023 21:35

Какой Row класс? Доморощенный? Меня очень сбивает с толку то, что getTimestamp() возвращает Date. Который, кстати, является плохо разработанным и давно устаревшим классом, поэтому, если вы можете обновить класс, чтобы иметь возможность возвращать современный тип, сделайте это. Я понимаю, что на данный момент это, вероятно, просто переместит причину вашей ошибки в другое место.

Ole V.V. 15.02.2023 07:21

Instant не зависит от часового пояса и не является проблемой. Что вас смутило, так это то, что он печатает в формате UTC. Ваша ошибка связана с выполнением .atZone(ZoneOffset.UTC), что дает вам дату UTC, 22 декабря, чего вы не хотите. Вместо этого вам нужно return row.getTimestamp(key).toInstant().atZone(ZoneId.systemDefaul‌​t()).toLocalDate();. При работе в часовом поясе Америки/Чикаго выдается желаемое 2022-12-21 (не зная, является ли это вашим часовым поясом, просто приведено в качестве примера).

Ole V.V. 15.02.2023 07:35

Отвечает ли это на ваш вопрос? Преобразование java.util.Date в java.time.LocalDate

Ole V.V. 15.02.2023 07:40
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
5
72
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Попробуйте так. Ознакомьтесь с DateTimeFormatter для получения подробной информации о следующих аргументах.

String date = "Wed Dec 21 20:47:46 CST 2022";
  • EEE трехбуквенный день недели
  • MMM трехбуквенный месяц
  • dd целый день
  • HH:mm:ss время в 24-часовом формате
  • z название часового пояса (CST)
  • yyyy год
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss z yyyy");
LocalDate dt = LocalDateTime.parse(date, dtf).toLocalDate();
System.out.println(dt);

отпечатки

2022-12-21

Обновлено

Если у вас действительно есть экземпляр Date, вы можете попробовать следующее:

LocalDate ldt = LocalDate.ofInstant(date.toInstant(), 
    ZoneId.systemDefault());

Спасибо, что сработало! Если у вас есть секунда, не могли бы вы объяснить, что это за формат, шаблон, который вы использовали для создания DateTimeFormatter? Также у вас есть какие-либо идеи, почему код, который у меня был, будет вести себя так, как он? Я не понимаю, почему это так изменило день.

skippy130 14.02.2023 21:40

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

WJS 14.02.2023 21:47

Думаю, одна из загадок жизни. Не могли бы вы объяснить, что означает раздел «EEE LLL» в формате? Я не знаком с этим. Или не могли бы вы указать мне ресурс, где я мог бы немного узнать об этом?

skippy130 14.02.2023 22:03

Можно ли сделать так, чтобы дата не была привязана к конкретному часовому поясу как в этом формате? Это значит, что он может локализовать время в любом часовом поясе, в котором он находится?

skippy130 14.02.2023 23:05

Или не могли бы вы указать мне ресурс, где я мог бы немного узнать об этом? Пакет java.time заменяет устаревшие и глючные Date и связанные с ними устаревшие классы. Документация DateTimeFormatter связана в моем ответе.

WJS 14.02.2023 23:32

У OP есть старомодный Date. We don’t need to go through toString()` и снова выполняется синтаксический анализ для преобразования в LocalDate. Также LLL в строке шаблона формата указана неверная информация. Так и должно быть MMM. Вам также необходимо указать локаль для вашего форматтера (на практике это, вероятно, сработает, если вы исправите только одну из двух ошибок, но это приведет к путанице).

Ole V.V. 15.02.2023 07:25

Ваш обновленный способ очень хорош. Я предлагаю вам либо подтолкнуть плохой путь к концу вашего вопроса, либо пропустить его.

Ole V.V. 15.02.2023 07:52

M/L для номера/текста не означает M для номера и L для текста. M и L работают как для чисел, так и для текста. Разница в том, что (цитата) Буквы шаблона «L», «c» и «q» определяют автономную форму стилей текста. В то время как в английском языке отдельная форма аббревиатуры месяца не должна отличаться, есть языки, в которых она отличается. Читатель, знакомый с таким языком, может спутать LLL с днем ​​месяца.

Ole V.V. 15.02.2023 13:30

@ОлеВ.В. ХОРОШО. Спасибо за объяснение. Буду менять на М.

WJS 15.02.2023 13:38

тл;др

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

myResultSet
.getObject( … , OffsetDateTime.class )  // For any database column of a data type akin to the SQL standard type of `TIMESTAMP WITH TIME ZONE`.
.toLocalDate()  // Extract the date portion from the returned `OffsetDateTime` object. 
.toString()     // Generate text in standard ISO 8601 format. 

Подробности

Класс Timestamp является частью ужасных классов даты и времени, которые теперь унаследованы. Используйте только их замены, современные классы java.time, определенные в JSR 310.

Вместо Timestamp используйте OffsetDateTime с JDBC 4.2 и более поздних версий. Сделайте это для любого столбца базы данных с типом данных, аналогичным стандартному типу SQL TIMESTAMP WITH TIME ZONE.

OffsetDateTime odt = myResultSet.getObject( … , OffsetDateTime.class ) ;

Ваш вопрос не ясен, но вы, кажется, хотите, чтобы часть даты этого момента была видна со смещением от UTC, равным нулю часов-минут-секунд.

Полученный OffsetDateTime, вероятно, уже находится в формате UTC. Но будем уверены:

OffsetDateTime odtUtc = odt.withOffsetSameInstant( ZoneOffset.UTC ) ;

Извлеките часть даты.

LocalDate localDate = odtUtc.toLocalDate() ;

Чтобы сгенерировать текст в стандартном формате ISO 8601, позвоните toString.

String output = localDate.toString() ;

Другие вопросы по теме