Scala function to parse json with time fields to appropriate case classes. How can I write this better?
Let this be the definition of your Date types:
sealed trait Date {
  def year: Int
}

case class Year(year: Int) extends Date
case class YearMonth(year: Int, month: Int) extends Date
case class YearWeek(year: Int, week: Int) extends Date
case class YearMonthDay(year: Int, month: Int, day: Int) extends Date

In your question there are problems when value is not defined, or when it is empty string, or when value is present, but it is not a number. So you can use common function readInt to read optional integer from JSON. In case if value is not present or if value is empty or non-integer, the result of function will be scala.util.Failure.
  def parseDate(dateJson: JsValue): Try[Date] = {
    def readInt(fieldName: String): Try[Int] =
      (dateJson \ fieldName).asOpt[String].filter(_.nonEmpty).map(x =&gt; Try(x.toInt))
        .getOrElse(Failure(new IllegalArgumentException(s&quot;$fieldName is empty&quot;)))

    val maybeDay: Try[Int] = readInt(&quot;day&quot;)
    val maybeWeek: Try[Int] = readInt(&quot;week&quot;)
    val maybeMonth: Try[Int] = readInt(&quot;month&quot;)
    val maybeYear: Try[Int] = readInt(&quot;year&quot;)

    maybeYear.map { year: Int =&gt;
      maybeMonth match {
        case Success(month) =&gt; maybeDay match {
          case Success(day) =&gt; YearMonthDay(year, month, day)
          case _ =&gt; YearMonth(year, month)
        }
        case _ =&gt; maybeWeek match {
          case Success(week) =&gt; YearWeek(year, week)
          case _ =&gt; Year(year)
        }
      }
    }
  }

My tests:
val date1 = JsObject(Map(&quot;year&quot; -&gt; JsString(&quot;2001&quot;), &quot;month&quot; -&gt; JsString(&quot;11&quot;), &quot;day&quot; -&gt; JsString(&quot;30&quot;)))
println(parseDate(date1)) // =&gt; Success(YearMonthDay(2001,11,30))
val date2 = JsObject(Map(&quot;year&quot; -&gt; JsString(&quot;2001&quot;), &quot;month&quot; -&gt; JsString(&quot;11&quot;)))
println(parseDate(date2)) // =&gt; Success(YearMonth(2001,11))
val date3 = JsObject(Map(&quot;year&quot; -&gt; JsString(&quot;2001&quot;), &quot;week&quot; -&gt; JsString(&quot;51&quot;)))
println(parseDate(date3)) // =&gt; Success(YearWeek(2001,51))
val date4 = JsObject(Map(&quot;year&quot; -&gt; JsString(&quot;&quot;)))
println(parseDate(date4)) // =&gt; Failure(java.lang.IllegalArgumentException: year is empty)

Sorry for my English