Scala function to parse json with time fields to appropriate case classes. How can I write this better? I have the below function which populates different time-related case classes based on what is present in the JSON input.
def parseTime(timeJson: JsValue) = {
   val day = (timeJson \ &quot;day&quot;).getOrElse(JsString(&quot;&quot;)).as[JsString].value.toInt
   val week = (timeJson \ &quot;month&quot;).getOrElse(JsString(&quot;&quot;)).as[JsString].value.toInt
   val month = (timeJson \ &quot;month&quot;).getOrElse(JsString(&quot;&quot;)).as[JsString].value.toInt
   val year = (timeJson \ &quot;year&quot;).getOrElse(JsString(&quot;&quot;)).as[JsString].value.toInt
   if (day != &quot;&quot;) {
     YearMonthDay(
       year = year,
       month = month,
       day = day)
   }
   else if (month != &quot;&quot;) {
     YearMonth(
       year = year,
       month = month
     )
   }
   else if (week != &quot;&quot;) {
     YearWeek(
       year = year,
       week = week
     )
   }
   else {
     Year(year)
   }
 }

Is there a cleaner way to check whether specific fields are present in my tuple of 4 values (day, week, month, year)
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