【问题标题】:Play & Joda: How to serialize an Option[DateTime] with a given `Writes`Play & Joda:如何使用给定的“Writes”序列化 Option[DateTime]
【发布时间】:2017-09-14 04:23:54
【问题描述】:

我的日期的内部表示应该始终是带有 UTC 时区的 ISO 格式(我使用 Play 提供的 Joda 的 Reads/Writes):

import org.joda.time.{DateTime, DateTimeZone}
import org.joda.time.format.ISODateTimeFormat
import play.api.libs.json._
import play.api.libs.json.Reads._
import play.api.libs.json.Writes._

scala> val dateTime = DateTime.now(DateTimeZone.UTC)
dateTime: org.joda.time.DateTime = 2014-08-12T21:10:24.048Z

scala> val js = Json.toJson(dateTime)(jodaDateWrites("yyyy-MM-dd'T'HH:mm:ss'Z"))
js: play.api.libs.json.JsValue = "2014-08-12T21:10:24Z"

到目前为止一切顺利...但是如果我尝试序列化 Option[DateTime] 我总是会收到此错误:

scala> val js = Json.toJson(Some(dt))(jodaDateWrites("yyyy-MM-dd'T'HH:mm:ss'Z"))
<console>:27: error: type mismatch;
 found   : play.api.libs.json.Writes[org.joda.time.DateTime]
 required: play.api.libs.json.Writes[Some[org.joda.time.DateTime]]
              Json.toJson(Some(dt))(jodaDateWrites("yyyy-MM-dd'T'HH:mm:ss'Z"))

如果我省略 Writes 它可以工作...但格式当然不是我正在寻找的格式:

scala> val js = Json.toJson(Some(dateTime))
js: play.api.libs.json.JsValue = 1407878787365

有没有办法序列化一个提供特定WritesOption[DateTime]

然后,我的最后一个问题是,当我尝试使用 UTC 时区反序列化 JSON ISO 日期时...

val date = Json.parse(""" { "date": "2014-08-12T21:10:24Z" }""")

scala> val dt = date as (__ \ 'date).readNullable[DateTime](jodaDateReads("yyyy-MM-dd'T'HH:mm:ss'Z"))
dt: Option[org.joda.time.DateTime] = Some(2014-08-12T21:10:24.000+02:00)

...即使我指定了模式 "yyyy-MM-dd'T'HH:mm:ss'Z",我也会在本地时区返回 DateTime

除了写我自己的Writes,还有其他选择吗?发送。

【问题讨论】:

    标签: json playframework jodatime


    【解决方案1】:
    Writes.nullable(jodaDateWrites("yyyy-MM-dd'T'HH:mm:ss'Z")) 
    

    这将序列化Option[DateTime],但如果值为None,则不会写入任何字段。

    Writes.optionWithNull(jodaDateWrites("yyyy-MM-dd'T'HH:mm:ss'Z")) 
    

    这也会序列化Option[DateTime],但如果值为None,则会写入null

    【讨论】:

      【解决方案2】:

      你也可以像这样定义你自己的隐式:

      implicit object jodaDateTimeFormat extends Format[DateTime] {
      
          private lazy val dateTimeFormatter = DateTimeFormat.forPattern("yyy-MM-dd'T'HH:mm:ssZ")
      
          def reads(json: JsValue): JsResult[DateTime] = json match {
            case JsNumber(d) => JsSuccess(new DateTime(d.toLong)) // Parse timestamps
            case JsString(d) => JsSuccess(dateTimeFormatter.parseDateTime(d))  // Parse ISO 8601 Dates
            case _ => JsError(Seq(JsPath() -> Seq(JsonValidationError("error.expected.date"))))
          }
          def writes(d: DateTime): JsValue = JsNumber(d.getMillis)
      }
      
      implicit object jodaDateTimeOptionFormat extends Format[Option[DateTime]] {
      
        private lazy val dateTimeFormatter = DateTimeFormat.forPattern("yyy-MM-dd'T'HH:mm:ssZ")
      
        def reads(json: JsValue): JsResult[Option[DateTime]] = json match {
          case JsNumber(d) => JsSuccess(Some(new DateTime(d.toLong))) // Parse timestamps
          case JsString(d) => JsSuccess(Some(dateTimeFormatter.parseDateTime(d)))  // Parse ISO 8601 Dates
          case _ => JsError(Seq(JsPath() -> Seq(JsonValidationError("error.expected.date"))))
        }
        def writes(d: Option[DateTime]): JsValue = if (d.isDefined) JsNumber(d.get.getMillis) else JsNull
      }
      

      【讨论】:

        【解决方案3】:
        猜你喜欢
        • 2015-04-28
        • 1970-01-01
        • 1970-01-01
        • 2015-06-20
        • 2015-01-11
        • 2011-03-17
        • 2015-10-06
        • 2015-10-06
        • 2013-08-17
        相关资源
        最近更新 更多