scala - 如何通过 fromJson(toJson(date)) 将日期与 specs2 匹配

标签 scala jodatime specs2 playframework-2.1

我遇到了以下问题:我想编写一个 specs2 规范来断言我的 json 转换是对称的。但是,我在 joda datetime 日期上收到错误消息。

'2012-04-17T00:04:00.000+02:00' is not equal to '2012-04-17T00:04:00.000+02:00'. Values have the same string representation but possibly different types like List[Int] and List[String] (TimeSpecs.scala:18) 

这是一个证明问题的极简规范

import org.joda.time.DateTime
import org.specs2.mutable.Specification

class TimeSpecs extends Specification {
  "joda and specs2" should {
    "play nice" in {
      val date = DateTime.parse("2012-04-17T00:04:00+0200")
      val date2 = DateTime.parse("2012-04-17T00:04:00+0200")
      date === date2
    }
    "play nice through play json transform" in {
      import play.api.libs.json._
      import play.api.libs.json.Json._
      val date = DateTime.parse("2012-04-17T00:04:00+0200")
      val jsDate= toJson(date)
      val date2= jsDate.as[DateTime]

      date === date2
    }
  }
}

我应该如何在第二次测试中比较 date 和 date2?它们是相同的,但 specs2 似乎没有看到 :(

---编辑

在运行时使用 date.getClass.getCanonicalName“手动”检查类型会按预期返回 org.joda.time.Datetime

import org.joda.time.DateTime
import org.specs2.mutable.Specification

class TimeSpecs extends Specification {
  "joda and specs2" should {
    "play nice" in {
      val date = DateTime.parse("2012-04-17T00:04:00+0200")
      val date2 = DateTime.parse("2012-04-17T00:04:00+0200")
      date === date2
    }
    "play nice through play json transform" in {
      import play.api.libs.json._
      import play.api.libs.json.Json._
      val date:DateTime = DateTime.parse("2012-04-17T00:04:00+0200")
      val jsDate= toJson(date)
      val date2:DateTim= jsDate.as[DateTime]
      println(date.getClass.getCanonicalName) //prints org.joda.time.DateTime
      println(date2.getClass.getCanonicalName)//prints org.joda.time.DateTime
      date === date2
    }
  }
}

使用 DateTime#isEqual 确实有点工作,但我失去了流畅匹配器的好处以及它们带来的有用错误消息。此外,我实际上要比较的是恰好包含日期的案例类实例,而不是日期本身。

使用

      date should beEqualTo(date2)

产生与 === 相同的错误>

最佳答案

问题是 joda time 定义了一个非常严格的 equals,它考虑了日期的 Chronology 是否相等( DateTime#getChronology )。 Kim Stebel 提出的 isEqual 方法确实忽略了年表。

从那里开始,有 2 种可能性:为 Play 定义自定义读写,然后使用相同的模式创建日期,如以下示例所示

import org.joda.time.DateTime
import org.joda.time.format.DateTimeFormat
import org.specs2.mutable.Specification

class TimeSpecs extends Specification {
    val pattern = "yyyy-MM-dd'T'HH:mm:ssZZ"
  "joda and specs2" should {
    "play nice" in {
      val date = DateTime.parse("2012-04-17T00:04:00+0200",DateTimeFormat.forPattern(pattern))
      val date2 = DateTime.parse("2012-04-17T00:04:00+0200",DateTimeFormat.forPattern(pattern))
      date === date2
    }
    "play nice through play json transform" in {
      import play.api.libs.json.Json._

      //play2 custom write
      implicit def customJodaWrite = play.api.libs.json.Writes.jodaDateWrites(pattern)
      //play2 custom read
      implicit def customJodaRead = play.api.libs.json.Reads.jodaDateReads(pattern) 


      val date:DateTime = DateTime.parse("2012-04-17T00:04:00+0200",DateTimeFormat.forPattern(pattern)) //make sure you parse the initial date with the same pattern
      val jsDate= toJson(date)
      val date2:DateTime= jsDate.as[DateTime]

      println(date.getClass.getCanonicalName)
      println(date2.getClass.getCanonicalName)
      println(jsDate)
      date should beEqualTo(date2)
    }
  }
}

Play 2.1 默认基于没有时区信息的 unix 时间戳(以毫秒为单位)进行解析(并写入 json)。当从 unix 时间戳解析回来时,它将在本地计算机时区(在我的例子中是欧洲/巴黎)中考虑它。因此需要自定义解析器/编写器

Joda 在调用不带解析器参数的解析器时使用特定的格式化程序,似乎不可能仅使用模式字符串创建相同的格式化程序(我还没有找到通过模式激活 DateTimeFormatter#withOffsetParsed 方法的方法字符串)。

另一种可能性是为 jodatime 定义一个自定义的 specs2 匹配器,它将使用 isEqual 而不是 equals。 因为我不想在我的 json 中使用 unix 纪元,所以我会坚持使用自定义 Play 转换器

关于scala - 如何通过 fromJson(toJson(date)) 将日期与 specs2 匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14040375/

相关文章:

java - 在 Scala 中获取 Json 值 scala.util.parsing.json.JSON

java - Joda-Time DateTime.toDate() 恢复时区

scala - 在 Scala 中使用与 Specs2 和 Play 的模式匹配

scala - containTheSameElementsAs 如何在 specs2 中工作

Scala List.filter 有两个条件,只应用一次

scala:在闭包中强制执行不可变类型

scala - 如何在 sbt shell 中设置子项目的设置(不使用项目命令)?

jodatime - 将 Joda-Time 转换为 Hibernate 4 的 Jadira

java - Joda Time - 获取一年中的所有星期

scala - 如何使用 SBT 仅运行单个 Spec2 规范?