【问题标题】:how to deserialize DateTime in Lift如何在 Lift 中反序列化 DateTime
【发布时间】:2013-04-12 21:00:49
【问题描述】:

我在将 org.joda.time.DateTime 字段从 JSON 反序列化为案例类时遇到问题。

JSON:
val ajson=parse(""" { "creationDate": "2013-01-02T10:48:41.000-05:00" }""")

我还设置了这些序列化选项:
implicit val formats = Serialization.formats(NoTypeHints) ++ net.liftweb.json.ext.JodaTimeSerializers.all

以及反序列化:
val val1=ajson.extract[Post]

帖子在哪里:
case class Post(creationDate: DateTime){ ... }

我得到的例外是:

 net.liftweb.json.MappingException: No usable value for creationDate
    Invalid date format 2013-01-02T10:48:41.000-05:00

如何将该日期字符串反序列化为 DateTime 对象?

编辑:
这有效:val date3= new DateTime("2013-01-05T06:24:53.000-05:00") 它使用与反序列化中相同的 JSON 日期字符串。这里发生了什么?

【问题讨论】:

    标签: scala datetime lift datetime-format


    【解决方案1】:

    这似乎是 Lift 默认使用的 DateParser 格式。在深入研究the code 时,您可以看到解析器在将结果传递给org.joda.time.DateTime 的构造函数之前尝试使用DateParser.parse(s, format)

    object DateParser {
      def parse(s: String, format: Formats) = 
        format.dateFormat.parse(s).map(_.getTime).getOrElse(throw new MappingException("Invalid date format " + s))
    }
    
    case object DateTimeSerializer extends CustomSerializer[DateTime](format => (
      {
        case JString(s) => new DateTime(DateParser.parse(s, format))
        case JNull => null
      },
      {
        case d: DateTime => JString(format.dateFormat.format(d.toDate))
      }
    ))
    

    Lift 似乎使用的格式是:yyyy-MM-dd'T'HH:mm:ss.SSS'Z'

    要解决这个问题,您可以指定正确的模式并将其添加到您的序列化选项中,或者如果您希望让 JodaTime 构造函数完成所有工作,您可以创建自己的序列化程序,例如:

    case object MyDateTimeSerializer extends CustomSerializer[DateTime](format => (
      {
        case JString(s) => tryo(new DateTime(s)).openOr(throw new MappingException("Invalid date format " + s))
        case JNull => null
      },
      {
        case d: DateTime => JString(format.dateFormat.format(d.toDate))
      }
    ))
    

    然后将其添加到您的格式列表中,而不是 net.liftweb.json.ext.JodaTimeSerializers.all

    【讨论】:

    • 我有 2 个后续问题:(1)这是“YYYY-MM-dd'T'HH:mm:ss.SSS'-'Z”我的日期格式,如“2013- 01-02T10:48:41.000-05:00" (2) 这是将我的格式添加到格式的正确方法:`implicit val formats = Serialization.formats(NoTypeHints) ++ MyDateTimeSerializer
    • 想通了(2):将 MyDateTimeSerializer 包装在一个列表中:对于那些感兴趣的人来说,它看起来像这样:implicit val formats = Serialization.formats(NoTypeHints) ++ List(MyDateTimeSerializer)
    • 我对 DateFormat 模式的所有复杂性并不十分熟悉,但您的建议看起来很接近。有两件事,年份应该是小写的y,而“-”是时区的一部分(IE 距 UTC -5 小时),因此您可能应该删除它。 yyyy-MM-dd'T'HH:mm:ss.SSSZ 可能与您要查找的内容接近,但这可能与 TZ 中的 : 存在问题。至于添加自定义序列化程序,将其包装在 List 中应该适合您。
    • 好的,我选择了 (2),但它不起作用,但我认为解析很好,但 JSON 字符串中可能有一些需要转义的时髦字符。我推断是因为这可以工作 new DateTime(parse(""" { "creationDate": "2013-01-05T06:24:53.000-05:00" }""").extract[Post3].creationDate) 但是当 JSON 作为用户输入时它不起作用 val date3= new DateTime(parse(Text(name).toString()).extract[Post3].creationDate)
    【解决方案2】:

    也许不是 100% 优雅,但只有几行,可读性强且有效:

    val SourISODateTimeFormat = DateTimeFormat.forPattern("YYYY-MM-dd'T'HH:mm:ss.SSSZ")
    val IntermediateDateTimeFormat = DateTimeFormat.forPattern("YYYY-MM-dd'T'HH:mm:ss'Z'")
    
    def transformTimestamps(jvalue: JValue) = jvalue.transform {
      case JField(name @ ("createdTime" | "updatedTime"), JString(value)) =>
        val dt = SourceISODateTimeFormat.parseOption(value).get
        JField(name, JString(IntermediateDateTimeFormat.print(dt)))
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-07
      • 2011-06-29
      • 2013-12-27
      • 1970-01-01
      相关资源
      最近更新 更多