Я сделал простой метод, который используется для преобразования метки времени, полученной из базы данных, в 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».
Если бы кто-нибудь мог пролить свет на это, я был бы очень признателен, поскольку я не понимаю, почему это происходит.
@WJS Возвращает объект Date.
Какой Row
класс? Доморощенный? Меня очень сбивает с толку то, что getTimestamp()
возвращает Date
. Который, кстати, является плохо разработанным и давно устаревшим классом, поэтому, если вы можете обновить класс, чтобы иметь возможность возвращать современный тип, сделайте это. Я понимаю, что на данный момент это, вероятно, просто переместит причину вашей ошибки в другое место.
Instant
не зависит от часового пояса и не является проблемой. Что вас смутило, так это то, что он печатает в формате UTC. Ваша ошибка связана с выполнением .atZone(ZoneOffset.UTC)
, что дает вам дату UTC, 22 декабря, чего вы не хотите. Вместо этого вам нужно return row.getTimestamp(key).toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
. При работе в часовом поясе Америки/Чикаго выдается желаемое 2022-12-21
(не зная, является ли это вашим часовым поясом, просто приведено в качестве примера).
Отвечает ли это на ваш вопрос? Преобразование java.util.Date в java.time.LocalDate
Попробуйте так. Ознакомьтесь с 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? Также у вас есть какие-либо идеи, почему код, который у меня был, будет вести себя так, как он? Я не понимаю, почему это так изменило день.
Я не уверен, почему он добавил день, если он не был скорректирован на основе часового пояса на другое местное время по умолчанию.
Думаю, одна из загадок жизни. Не могли бы вы объяснить, что означает раздел «EEE LLL» в формате? Я не знаком с этим. Или не могли бы вы указать мне ресурс, где я мог бы немного узнать об этом?
Можно ли сделать так, чтобы дата не была привязана к конкретному часовому поясу как в этом формате? Это значит, что он может локализовать время в любом часовом поясе, в котором он находится?
Или не могли бы вы указать мне ресурс, где я мог бы немного узнать об этом? Пакет java.time заменяет устаревшие и глючные Date
и связанные с ними устаревшие классы. Документация DateTimeFormatter
связана в моем ответе.
У OP есть старомодный Date. We don’t need to go through
toString()` и снова выполняется синтаксический анализ для преобразования в LocalDate
. Также LLL
в строке шаблона формата указана неверная информация. Так и должно быть MMM
. Вам также необходимо указать локаль для вашего форматтера (на практике это, вероятно, сработает, если вы исправите только одну из двух ошибок, но это приведет к путанице).
Ваш обновленный способ очень хорош. Я предлагаю вам либо подтолкнуть плохой путь к концу вашего вопроса, либо пропустить его.
M/L для номера/текста не означает M для номера и L для текста. M и L работают как для чисел, так и для текста. Разница в том, что (цитата) Буквы шаблона «L», «c» и «q» определяют автономную форму стилей текста. В то время как в английском языке отдельная форма аббревиатуры месяца не должна отличаться, есть языки, в которых она отличается. Читатель, знакомый с таким языком, может спутать LLL
с днем месяца.
@ОлеВ.В. ХОРОШО. Спасибо за объяснение. Буду менять на М.
Избегайте ненужных манипуляций со строками. Используйте типы даты и времени для значений даты и времени.
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() ;
Какой тип возвращает
getTimeStamp(key)
?