How do I parse a date from a string in EK9?

← Date, Time, and Duration · Ref: Q538

EK9 uses constructor parsing: pass a string to Date(), Time(), or DateTime() and use guard expressions to handle invalid input safely.

CONSTRUCTOR PARSING

Date('2024-01-15') parses ISO 8601 date format.
Time('10:30:00') parses ISO 8601 time format.
DateTime('2024-06-15T10:30:00Z') parses ISO 8601 datetime format.

INVALID INPUT PRODUCES UNSET

If the string is not a valid format, the constructor returns an unset value rather than throwing an exception:

  badDate <- Date('not-a-date')
  badDate? is false

This follows EK9's tri-state design: invalid parsing produces unset, not an error.

GUARD PATTERN FOR SAFE PARSING

Combine constructor parsing with guard expressions for clean error handling:

  if parsed <- Date(userInput)
    stdout.println(`Valid date: ${parsed}`)
  else
    stdout.println('Invalid date format')

The guard only enters the if-block when the parsed value is set.

ROUND-TRIPPING

The $ operator produces a string that can be parsed back:

  original <- 2024-06-15
  asString <- $original
  restored <- Date(asString)
  require restored == original

See Q31 for Date and Time basics. See Q552 for Date-to-DateTime promotion. See Q555 for constructing from components.

Example

defines module qa.parse.date.string

  defines program
    ParseDateStringDemo()
      stdout <- Stdout()

      // Parse valid ISO 8601 strings
      parsedDate <- Date("2024-01-15")
      parsedTime <- Time("10:30:00")
      parsedDT <- DateTime("2024-06-15T10:30:00Z")

      stdout.println(`Parsed date: ${parsedDate}`)
      stdout.println(`Parsed time: ${parsedTime}`)
      stdout.println(`Parsed datetime: ${parsedDT}`)

      require parsedDate?
      require parsedTime?
      require parsedDT?

      // Invalid strings produce unset values
      badDate <- Date("not-a-date")
      badTime <- Time("invalid")
      badDT <- DateTime("garbage")

      require ~badDate?
      require ~badTime?
      require ~badDT?
      stdout.println(`Bad date isSet: ${badDate?}`)
      stdout.println(`Bad time isSet: ${badTime?}`)

      // Guard pattern for safe parsing
      userInput <- "2024-03-20"
      if validDate <- Date(userInput)
        stdout.println(`Valid: ${validDate}`)

      invalidInput <- "31/02/2024"
      if checkedDate <- Date(invalidInput)
        stdout.println(`This won't print`)
      else
        stdout.println("Invalid date format")

      // Round-tripping: $ produces parseable string
      original <- 2024-06-15
      asString <- $original
      restored <- Date(asString)
      require restored == original
      stdout.println(`Round-trip: ${original} -> ${asString} -> ${restored}`)

      // Duration parsing also returns unset on invalid
      validDur <- Duration("P1Y6M")
      invalidDur <- Duration("not-a-duration")
      require validDur?
      require ~invalidDur?
      stdout.println(`Valid duration: ${validDur}`)

Common mistakes

E50001 — Renaming the variable means later references to 'parsedDate' become unresolved, triggering E50001. See ek9 -h E50001 for details.

Incorrect:

parsedDateXYZ <- Date("2024-01-15")

Correct:

parsedDate <- Date("2024-01-15")

E50001 — Renaming the variable means later references to 'userInput' become unresolved, triggering E50001. See ek9 -h E50001 for details.

Incorrect:

userInputXYZ <- "2024-03-20"

Correct:

userInput <- "2024-03-20"
Other ways to ask this
  • How do I convert a string to a date in EK9?
  • How do I handle invalid date strings in EK9?
  • How does Date construction from strings work?

Coming from another language?

Java: LocalDate.parse() throws DateTimeParseException on invalid input, requires try-catch. Python: datetime.strptime() throws ValueError, requires try-except. JavaScript: new Date('invalid') returns 'Invalid Date' object (truthy!). Go: time.Parse() returns error. Rust: NaiveDate::parse_from_str() returns Result. EK9: constructor returns unset value on invalid input, guard expression handles it cleanly.

Keywords: time, date, safe, unset, round-trip, guard, iso8601, constructor, timezone, isset, invalid, null-safe, duration, convert, parse, string