我遇到了以下问题:我想编写一个specs2规范来断言我的json转换和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
}
}
}
我应该如何在第二次测试中比较日期和日期2?它们是相同的,但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)
产生与===
答案 0 :(得分:2)
问题是joda time定义了一个非常严格的equals,它考虑了date的年代表(DateTime#getChronology)。 Kim Stebel提出的isEqual方法确实忽略了年表。
从那时起,有两种可能性:为游戏定义自定义读取和写入,然后使用相同的模式创建日期,如下例所示
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)
}
}
}
播放2.1默认为基于unix时间戳解析(并写入json),以毫秒为单位,没有时区信息。从unix时间戳解析回来时,它将在本地计算机时区(在我的例子中为Europe / Paris)中考虑它。因此需要自定义解析器/编写器
Joda在没有解析器参数的情况下调用parse时使用特定的格式化程序,似乎不可能只使用模式字符串创建相同的格式化程序(我还没有找到通过模式激活DateTimeFormatter #withOffsetParsed方法的方法字符串)。
另一种可能性是为jodatime定义一个自定义specs2匹配器,它将使用isEqual而不是equals。 既然我不想在我的json中使用unix时代,我会坚持使用自定义播放变换器