Read and write a LocalDateTime in a JSON object using a custom date/time format
15:11 11 Sep 2026

In my Play JSON application, I have a custom type with a LocalDateTime field that I want to have written to and from a String in a custom date format (i.e. not the ISO-8601 format).

case class MyType(id: Int, value: LocalDateTime)

val myValue = MyType(1, LocalDateTime.parse("2026-09-11T10:11:12"))

// Desired date/time format
val MyFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")

// Should return "2026-09-11 10:11:12"
Json.toJson(myValue).as[JsObject].value("value").as[JsString].value

// Should return a value identical to myValue
Json.obj("id" -> 1, "value" -> "2026-09-11 10:11:12").as[MyType]
{ "id": 1, "value": "2026-09-11 10:11:12" }

I know that can achieve this by adding a custom formatter to the companion object:

private object MyType {
  implicit lazy val jsonFormat: OFormat[MyType] = Json.format

  implicit val localDateTimeFormat: Format[LocalDateTime] = new Format[LocalDateTime] {
    override def reads(json: JsValue): JsResult[LocalDateTime] =
      Try(LocalDateTime.parse(json.as[String], MyFormat)) match {
        case Success(value) => JsSuccess(value)
        case Failure(_)     => JsError(s"Parse failure")
      }

    override def writes(o: LocalDateTime): JsValue = Json.toJson(o.format(MyFormat))
  }
}

That all said, it feels like this is something I should be able to do more simply using functionality built in to Play JSON. In addition to streamlining things, it would make things such as error handling consistent with what Play does.

I'm not having luck finding this in the Play documentation.

Stuff in the Play JSON library

Digging around the Play JSON library, I see things that make it look like it should be possible, though I don't know if it's possible to make use of it.

For example, the following all look promising:

  • play.api.libs.json.EnvReads#DefaultLocalDateReads
trait EnvReads {
  def localDateReads[T](parsing: T, corrector: String => String = identity)(
      implicit p: T => TemporalParser[LocalDate])
object TemporalParser {
  /** Instance of local date/time based on specified pattern. */
  implicit def LocalDateTimePatternParser(pattern: String): TemporalParser[LocalDateTime] =
    LocalDateTimeFormatterParser(DateTimeFormatter.ofPattern(pattern))

There are Writes equivalents to these as well.

Question

Is there a simple, built-in way to specify that LocalDateTime values be parsed using a particular DateTimeFormatter?

As a side note, it would be ideal but not a deal-breaker if I could also disable Play's functionality of reading in JSON numeric values as LocalDateTime, and only accept String values. But if a simple solution exists that keeps that behavior, I'd prefer that over a more complex one that didn't.

scala play-json