Search code examples
jsonscaladatetimesprayspray-json

Converting DateTime to a JSON string


I want to convert a case class with an Option[DateTime] parameter to a spray-json object which can be served by an API. Using spray-json I have a custom JsonFormat as such

object JsonImplicits extends DefaultJsonProtocol {
  implicit object PostJsonFormat extends RootJsonFormat[Post] {

    def write(p: Post) = JsObject(
      "title" -> JsString(p.title),
      "content" -> JsString(p.content),
      "author" -> JsString(p.author),
      "creationDate" -> JsString(p.creationDate.getOrElse(DateTime.now))
    )
  }
}

But I get:

overloaded method value apply with alternatives:
  (value: String)spray.json.JsString <and>
  (value: Symbol)spray.json.JsString
  cannot be applied to (com.github.nscala_time.time.Imports.DateTime)
    "creationDate" -> JsString(p.creationDate.getOrElse(DateTime.now))

when I try to compile it and no matter what I try I can't seem to convert the DateTime object to a string. For instance, when I try calling toString I get

ambiguous reference to overloaded definition,
  both method toString in class AbstractDateTime of type (x$1: String, x$2: java.util.Locale)String
  and  method toString in class AbstractDateTime of type (x$1: String)String
  match expected type ?
    "creationDate" -> JsString(p.creationDate.getOrElse(DateTime.now.toString)))

Solution

  • You have several problems here.

    First, the toString() method in AbstractDateTime requires one or several arguments see here.

    But I would advise you against this path and recommend using properly Spray-Json.

    Spray-json does not know how to serialize Option[DateTime], therefore you have to provide a RootJsonFormat for it.

    This is what I am doing.

    implicit object DateJsonFormat extends RootJsonFormat[DateTime] {
    
        private val parserISO : DateTimeFormatter = ISODateTimeFormat.dateTimeNoMillis();
    
        override def write(obj: DateTime) = JsString(parserISO.print(obj))
    
        override def read(json: JsValue) : DateTime = json match {
          case JsString(s) => parserISO.parseDateTime(s)
          case _ => throw new DeserializationException("Error info you want here ...")
        }
      }
    

    Adapt it as you want if you do not want to use ISO formatting.