Play & Joda: 如何使用给定的"写入"序列化选项[日期时间]



我的日期的内部表示应始终是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

有没有办法序列化提供特定Writes Option[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之外,还有其他选择吗?

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

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

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
}

试试这些:

implicit val dateWrites = jodaDateWrites("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
implicit val dateReads = jodaDateReads("yyyy-MM-dd'T'HH:mm:ss.SSSZ")

https://github.com/playframework/playframework/blob/master/framework/src/play-json/src/main/scala/play/api/libs/json/Writes.scala#L411

https://github.com/playframework/playframework/blob/master/framework/src/play-json/src/main/scala/play/api/libs/json/Reads.scala#L645

最新更新