How to deserialize a DateTime in an elevator

I am having the problem of deserializing the org.joda.time.DateTime field from JSON to the case class.

JSON:
val ajson=parse(""" { "creationDate": "2013-01-02T10:48:41.000-05:00" }""")

I also set these serialization options:
implicit val formats = Serialization.formats(NoTypeHints) ++ net.liftweb.json.ext.JodaTimeSerializers.all

And deserialization:
val val1=ajson.extract[Post]

where post:
case class Post( createDate : DateTime){ ... }

An exception I get:

  net.liftweb.json.MappingException: No usable value for creationDate Invalid date format 2013-01-02T10:48:41.000-05:00 

How can I deserialize this date string into a DateTime object?

EDIT:
This works: val date3= new DateTime("2013-01-05T06:24:53.000-05:00") which uses the same date string from JSON as for deserialization. What's going on here?

+4
source share
2 answers

It seems like a DateParser format that uses Lift by default. Having revealed the code , you will see that the parser is trying to use DateParser.parse(s, format) before passing the result to the constructor for org.joda.time.DateTime .

 object DateParser { def parse(s: String, format: Formats) = format.dateFormat.parse(s).map(_.getTime).getOrElse(throw new MappingException("Invalid date format " + s)) } case object DateTimeSerializer extends CustomSerializer[DateTime](format => ( { case JString(s) => new DateTime(DateParser.parse(s, format)) case JNull => null }, { case d: DateTime => JString(format.dateFormat.format(d.toDate)) } )) 

The format that Lift seems to be using: yyyy-MM-dd'T'HH:mm:ss.SSS'Z'

To get around this, you can specify the correct template and add it to the serialization options, or if you prefer the JodaTime constructor to do all the work, you could create your own serializer, for example:

 case object MyDateTimeSerializer extends CustomSerializer[DateTime](format => ( { case JString(s) => tryo(new DateTime(s)).openOr(throw new MappingException("Invalid date format " + s)) case JNull => null }, { case d: DateTime => JString(format.dateFormat.format(d.toDate)) } )) 

Then add this to the list of formats instead of net.liftweb.json.ext.JodaTimeSerializers.all

+9
source

Not 100% elegant, but just a few lines, quite readable and works:

 val SourISODateTimeFormat = DateTimeFormat.forPattern("YYYY-MM-dd'T'HH:mm:ss.SSSZ") val IntermediateDateTimeFormat = DateTimeFormat.forPattern("YYYY-MM-dd'T'HH:mm:ss'Z'") def transformTimestamps(jvalue: JValue) = jvalue.transform { case JField(name @ ("createdTime" | "updatedTime"), JString(value)) => val dt = SourceISODateTimeFormat.parseOption(value).get JField(name, JString(IntermediateDateTimeFormat.print(dt))) } 
0
source

All Articles