Joda在Play 2.6中的日期时间格式无法正常工作

3

我试图将我的代码迁移到Play 2.6,除了DateTime类型的格式之外,一切都很好。

作为迁移的一部分,我已经添加了play-json-joda依赖。

然而,像这样的问题:

case class GeoArea(id: Option[Int] = None,
                   continentId: Option[Int] = None,
                   countryId: Option[Int] = None,
                   code: String,
                   name: String,
                   discr: Discriminator.Value,
                   createdAt: DateTime = DateTime.now,
                   updatedAt: DateTime = DateTime.now,
                   deletedAt: Option[DateTime] = None,
                   createdBy: Option[String] = None,
                   updatedBy: Option[String] = None)

格式化对象定义如下:

implicit lazy val geoAreaFormat: Format[GeoArea] = Json.format[GeoArea]

我遇到了一个错误:

在隐式范围中未找到play.api.libs.json.Format的实例,其类型参数为org.joda.time.DateTime、org.joda.time.DateTime、scala.Option[org.joda.time.DateTime](提示:如果在同一文件中声明,请确保在它之前声明)[error]
implicit lazy val geoAreaFormat: Format[GeoArea] = Json.format[GeoArea]

我缺少了什么?我需要在哪里添加其他内容以解决这个问题?

我的导入看起来像这样:

import driver.PGDriver.api._
import org.joda.time.DateTime
import play.api.libs.json._
import slick.lifted.Tag
import model.GeoAreas.Discriminator
import converters.{JsonEnumeration, SlickEnumeration}

迁移期间它们并未发生变化,但它们足以使一切正常工作。


1
如何在Play JSON中使用Joda DateTime?没有play.api.libs.json.Format的实例可用于Scala Iterable [Java]models.AccountStatus的no instance of play.api.libs.json.Format可用 - Dmytro Mitin
第一个谈论的是Play 2.3,这与2.6不同。另外两个完全无关。Joda.DateTime有一个标准格式,我可能不知道如何使用它。 - Shurik Agulyansky
1
不,例如这个答案提到了2.6(它来自我的第一个链接): https://dev59.com/QFwZ5IYBdhLWcg3wbv7r#45440349 - Dmytro Mitin
那么,这是否意味着在2.6中我必须定义自己的实现?没有默认实现吗? - Shurik Agulyansky
FYI,Joda-Time 项目现处于维护模式(https://en.wikipedia.org/wiki/Maintenance_mode),该团队建议迁移至 java.time 类。请参见 Oracle 的教程 - Basil Bourque
3个回答

9
在您的build.sbt中添加以下内容:
libraryDependencies += "com.typesafe.play" % "play-json-joda_2.12" % "2.6.0"

接下来,在你的模型文件中导入以下内容:

import play.api.libs.json.JodaWrites._
import play.api.libs.json.JodaReads._

是的,它可以!(Y) - aksappy

2

我也遇到了这个问题,当我转移到新的库时。您可以通过创建一个基于他们新默认设置的隐式格式来解决它。

implicit val dateFormat = new OFormat[DateTime] {
    override def reads(json: JsValue): JsResult[DateTime] = JodaReads.DefaultJodaDateTimeReads.reads(json)
    override def writes(o: DateTime): JsValue = JodaWrites.JodaDateTimeWrites.writes(o)
}

请注意,以上内容不包括使用纪元毫秒的旧默认写入。为确保您的迁移不会破坏现有功能,您可能希望保留旧的默认设置:

implicit val dateFormatDefault = new Format[DateTime] {
    override def reads(json: JsValue): JsResult[DateTime] = JodaReads.DefaultJodaDateTimeReads.reads(json)
    override def writes(o: DateTime): JsValue = JodaDateTimeNumberWrites.writes(o)
}

这是因为play-json中的旧默认值使用了毫秒 (https://github.com/playframework/play-json/blob/master/play-json/jvm/src/main/scala/play/api/libs/json/EnvWrites.scala#L326-L328):

@deprecated("Include play-json-joda as a dependency and use JodaWrites.JodaDateNumberWrites", "2.6.0")
object DefaultJodaDateWrites extends Writes[DateTime] {
    def writes(d: DateTime): JsValue = JsNumber(d.getMillis)
}

新的默认设置使用ISO8601 (https://github.com/playframework/play-json/blob/b4f812df628787e2d83131ceafbecb0d6d769704/play-json-joda/src/main/scala/play/api/libs/json/JodaWrites.scala#L33-L35):

/**
 * Default Serializer LocalDate -> JsString(ISO8601 format (yyyy-MM-dd))
 */
implicit object JodaDateTimeWrites extends Writes[DateTime] {
   def writes(d: DateTime): JsValue = JsString(d.toString)
}

1
你应该使用 nscala-time 时间,它是 Joda 的一个包装器。
然后为了创建一个 Json 格式化对象,你可以这样做。
package formatters

import org.joda.time.{DateTime, DateTimeZone}
import org.joda.time.format.ISODateTimeFormat
import play.api.libs.json.{JsString, JsSuccess, JsValue, Format}

object DateTimeFormatter {
  private lazy val ISODateTimeFormatter = ISODateTimeFormat.dateTime.withZone(DateTimeZone.UTC)
  private lazy val ISODateTimeParser = ISODateTimeFormat.dateTimeParser

  implicit val dateTimeFormatter = new Format[DateTime] {
    def reads(j: JsValue) = JsSuccess(ISODateTimeParser.parseDateTime(j.as[String]))
    def writes(o: DateTime): JsValue = JsString(ISODateTimeFormatter.print(o))
  }
}

而在你的伴生对象中

object GeoArea {
  import formatters.DateTimeFormatter._
  implicit val geoAreaFormat = Json.format[GeoArea]
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接