【问题标题】:Scala / Joda - Joda DateTimeFormat not applyingScala / Joda - Joda DateTimeFormat 不适用
【发布时间】:2020-07-18 15:43:33
【问题描述】:

我想从数据库中检索日期并保留其格式。例如"20200406T145511.067Z" 当我尝试将其解析为 Joda DateTime 时,格式更改为 "2020-04-06T14:55:11.067+01:00"。由于这个问题,我试图明确说明 Joda DateTime 应该返回的 DateTimeFormat,"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)

【问题讨论】:

  • 这是目前工作中使用的。我们希望在未来进行更新,但现在我需要坚持下去。

标签: scala datetime jodatime


【解决方案1】:

你可以只用 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

更新:

文档says:

在内部,该类包含两条数据。首先,它将日期时间保存为从 Java 纪元 1970-01-01T00:00:00Z 开始的毫秒数。

我从这句话中了解到,无论您的格式如何,它都保持为Long(内部状态),并且它对客户端的表示可能会有所不同,具体取决于格式化程序和年表。

我们能做什么,它不是应用程序级别的格式。我们可能需要返回一个特定的格式化日期,所以我们可以在需要的时候进行转换,例如:return a json for rest client :

val dateFormat = "yyyyMMdd'T'HHmmss.SSS'Z'"
val dateTimeWrites: Writes[DateTime] = new Writes[DateTime] {
  def writes(d: DateTime): JsValue = JsString(d.toString())
}

【讨论】:

  • 您在此处显示的结果是我试图避免的结果。我想要的结果不能包含连字符,也不能包含冒号。
  • 啊,我明白了。然后你需要从日期时间格式调用 print ,用val result = dateTimeFormat.print(parsedDate)更新我的回答
  • 我正在尝试将其作为 DateTime 类型返回,我认为这就是我当前遇到的问题。如果您再看一下我的问题,则会有一个更新的部分。感谢您给我的任何帮助!
  • @Chris,我用一点观点再次更新了答案
【解决方案2】:

日期时间不能也不应该有格式

你不能。你在问不可能的事。你也不应该这样做。

DateTime 表示时区中的日期和时间。它没有,因为不能有格式。您可以在String 中使用任何您喜欢的格式。仅在 String 中,不在 DateTime 中。就像您不能拥有带有格式的 int 一样。您可以将int 格式化为不同的字符串,例如180018+180x0012,但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

请仔细查看 cmets 中的日期时间。她们不一样。前者采用 UTC 格式,由结尾的 Z 表示。是的,Z 与 UTC 的偏移量为零。后一个日期时间具有相同的时间和不同的 UTC 偏移量,+01:00。因此它指定了一个不同的时间点,等于 2020-04-06T13:55:11.067 UTC。

您的问题是在格式模式字符串中硬编码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

【讨论】:

  • 感谢您的解释,非常有帮助。日期时间在我的数据库中存储为20200406T145511.067Z,但在尝试返回时我似乎无法删除连字符和冒号。您的解决方案解决了我的时区问题,但我正在努力为不需要的字符找到解决方案。你有什么建议吗?
  • 我不知道您的数据库,也无法确定,但在我看来,要存储到您的数据库中,您应该使用相同的格式化程序将 DateTime 格式化为字符串,这将给出你是一个没有连字符的字符串,然后存储该字符串(如果你的数据库有日期时间类型,可能还有其他更有吸引力的选项)。
【解决方案3】:
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)

【讨论】:

  • 我希望它的返回类型是 DateTime 而不是 String。打印语句只是为了显示格式不正确。我应该提供有关返回类型的更多详细信息。
  • 我在返回结果时添加了new DateTime() 调用,所以我得到了预期的格式。但是,我仍然收到格式错误。我会更新问题。
猜你喜欢
  • 2021-05-22
  • 1970-01-01
  • 2019-02-27
  • 2020-06-05
  • 2013-07-15
  • 1970-01-01
  • 2012-12-01
  • 1970-01-01
  • 2011-06-07
相关资源
最近更新 更多