Scala / Joda - Joda DateTimeFormat не применяется - PullRequest
0 голосов
/ 06 апреля 2020

Я хочу получить дату из БД и сохранить ее формат. Например, "20200406T145511.067Z" Когда я пытаюсь проанализировать ее как Joda DateTime, формат меняется на "2020-04-06T14:55:11.067+01:00". Из-за этой проблемы я попытался явно указать DateTimeFormat, который Joda DateTime должен возвращать как "yyyyMMdd'T'HHmmss.SSS'Z'", но, похоже, он не применяется. Я хочу вернуть DateTime объект в ожидаемом формате (например, "20200406T145511.067Z").

    val dateTimeFormat = DateTimeFormat.forPattern("yyyyMMdd'T'HHmmss.SSS'Z'")
    val itemDateTime = dateTimeFormat.parseDateTime(record.get("itemDateTime").asString)

    println("Neo4J: " + record.get("assetDateTime").asString) // Neo4J: 20200406T145511.067Z
    println("Joda: " + assetDateTime) // Joda: 2020-04-06T14:55:11.067+01:00

    val lastUpdatedDateTime = dateTimeFormat.parseDateTime(record.get("lastUpdatedDateTime").asString)

    println("Neo4J: " + record.get("lastUpdatedDateTime").asString) // Neo4J: 20200406T145511.383Z
    println("Joda: " + lastUpdatedDateTime) // Joda: 2020-04-06T14:55:11.383+01:00

РЕДАКТИРОВАТЬ: Я обновил свой код, чтобы вернуть правильный тип DateTime, но теперь я получаю ошибку неверного формата -

java.lang.IllegalArgumentException: Invalid format: "20200406T161516.856Z" is malformed at "1516.856Z"

Я не понимаю, почему это происходит. Любая помощь будет оценена.

Обновленный код:

    val dateTimeFormat = DateTimeFormat.forPattern("yyyyMMdd'T'HHmmss.SSS'Z'")
    val itemDateTime = dateTimeFormat.parseDateTime(record.get("itemDateTime").asString)
    val itemDateTimeFormat = dateTimeFormat.print(itemDateTime)
    val lastUpdatedDateTime = dateTimeFormat.parseDateTime(record.get("lastUpdatedDateTime").asString)
    val lastUpdatedDateTimeFormat = dateTimeFormat.print(lastUpdatedDateTime)
    if (lastUpdatedDateTime.isAfter(itemDateTime) new DateTime(lastUpdatedDateTimeFormat) else new DateTime(itemDateTimeFormat)

Ответы [ 3 ]

1 голос
/ 06 апреля 2020

Вы можете просто разобрать ISODateTimeFormatter

import org.joda.time.DateTime
import org.joda.time.format.DateTimeFormat
import org.joda.time.format.ISODateTimeFormat

// val inputDt = record.get("itemDateTime").asString 
// let's imagine we have a data as following:
val inputDt = "20200406T161516.856Z"
val dateTimeFormat = DateTimeFormat.forPattern("yyyyMMdd'T'HHmmss.SSS'Z'")
val itemDateTime = dateTimeFormat.parseDateTime(inputDt)
val parsedDate = DateTime.parse(itemDateTime.toString, ISODateTimeFormat.dateTimeParser());
println(parsedDate) // 2020-04-06T16:15:16.856Z
val result: String = dateTimeFormat.print(parsedDate) //NOTE: return type is String
println(result) // 20200406T161516.856Z

ОБНОВЛЕНИЕ:

Документация говорит :

Внутри класс содержит два кусочки данных. Во-первых, он содержит дату и время в миллисекундах от Java эпохи 1970-01-01T00: 00: 00Z.

Что я понимаю из этого предложения, независимо от вашего форматирования оно сохраняется как Long (внутреннее состояние) и его представление для клиента может быть различным в зависимости от Formatter и Chronology.

Что мы можем сделать, это не то, какой формат это на уровне приложения. Возможно, нам потребуется вернуть указанную c отформатированную дату, чтобы мы могли преобразовать ее, когда нам нужно, например: вернуть json для остального клиента:

val dateFormat = "yyyyMMdd'T'HHmmss.SSS'Z'"
val dateTimeWrites: Writes[DateTime] = new Writes[DateTime] {
  def writes(d: DateTime): JsValue = JsString(d.toString())
}
1 голос
/ 07 апреля 2020

DateTime не может и не должен иметь формат

Вы не можете. Вы спрашиваете о невозможном. Вам также не следует этого хотеть.

A DateTime представляет дату и время в часовом поясе. Он не имеет, как не может иметь формат. Вы можете иметь любой формат в String. Только в String, а не в DateTime. Также как у вас не может быть int с форматом. Вы можете отформатировать int в различные строки, такие как 18, 0018, +18 и 0x0012, но int остается неизменным.

Это хорошо! Хорошая практика во всех программах, кроме простейших одноразовых, говорит о том, что мы должны держать модель и представление отдельно. Ваша дата и время принадлежат вашей модели, здесь нам нужен ваш DateTime. Как это выглядит, его формат - вопрос презентации. не относится к вашей модели.

Поэтому, когда вы читаете дату и время из базы данных, удовлетворяйте себя объектом DateTime, как вы уже делаете, и не делайте этого. беспокоиться о формате, потому что у него нет. Всякий раз, когда вам нужна строка в указанном вами компактном формате, отформатируйте DateTime в такую ​​строку, используя тот же форматер.

В вашем анализе есть ошибка

Вы не спрашивали об этом , но вы должны знать.

    println("Neo4J: " + record.get("assetDateTime").asString) // Neo4J: 20200406T145511.067Z
    println("Joda: " + assetDateTime) // Joda: 2020-04-06T14:55:11.067+01:00

Пожалуйста, обратите внимание на дату и время в комментариях. Они не одинаковы. Первый находится в UT C, обозначаемом конечным Z. Да, Z - это смещение нуля от UT C. Последняя дата-время имеет тот же час дня и другое смещение UT C, +01:00. Таким образом, он обозначает другой момент времени, равный 2020-04-06T13: 55: 11.067 UT C.

Ваша проблема заключается в жестком кодировании Z в строке шаблона формата, заключив его в одинарные кавычки , Никогда не делай этого. Смещение должно быть проанализировано как смещение. Для этого используйте ZZ в строке шаблона формата. В Java (потому что это то, что я могу написать):

    DateTimeFormatter dateTimeFormat = DateTimeFormat.forPattern("yyyyMMdd'T'HHmmss.SSSZZ");
    String assetDateTimeString = "20200406T145511.067Z";
    DateTime itemDateTime = dateTimeFormat.parseDateTime(assetDateTimeString);
    System.out.println(itemDateTime);

Вывод при запуске в часовом поясе Европы / Лондона:

2020-04-06T15: 55: 11.067 + 01: 00

Если вы хотите сохранить смещение от строки, сообщите вашему форматеру так:

    DateTimeFormatter dateTimeFormat = DateTimeFormat.forPattern("yyyyMMdd'T'HHmmss.SSSZZ")
            .withOffsetParsed();

2020-04-06T14: 55: 11.067Z

0 голосов
/ 06 апреля 2020
val dateTimeFormat = DateTimeFormat.forPattern("yyyyMMdd'T'HHmmss.SSS'Z'")
val itemDateTime = dateTimeFormat.parseDateTime(record.get("itemDateTime").asString)

Здесь вы анализируете строку с форматом yyyyMMdd'T'HHmmss.SSS'Z' в действительный объект DateTime. Чтобы распечатать содержимое объекта в нужном формате, вам нужно вызвать dateTimeFormat.print(itemDateTime)

...