Class AutoTemporalParser

java.lang.Object
dev.frostlake.functions.scalar.AutoTemporalParser

public final class AutoTemporalParser extends Object
Snowflake's AUTO date/time input detection: a lenient field scanner for the timestamp and date forms Snowflake accepts without an explicit format model. Strict java.time ISO parsing covers only one of them, so the following all used to be rejected outright:
  • a zone designator — 2025-07-19T16:35:12.589000000Z and the documented YYYY-MM-DD"T"HH24:MI:SS.FFTZH:TZM form 2013-04-28T20:57:01.123456789+07:00. The offset is read and DROPPED: these parse to a wall-clock LocalDateTime, which is the TIMESTAMP_NTZ semantic (the caller decides what to do about zones).
  • MM/DD/YYYY [HH24:MI:SS] with a one-digit month or day, e.g. 3/5/2024 12:34:59 (Snowflake's own example is 2/18/2008 02:36:48).
  • DD-MON-YYYY, e.g. 17-DEC-1980.
  • whitespace variation between the date and the time — Snowflake "allows some whitespace differences in order to handle variably-formatted data", so 2024-03-29 15:00:11 (two blanks) is the same instant as with one. The previous implementation swapped a single blank for T, which turned a double blank into TT and could never accept any other spacing.
  • a digit count that does not match the canonical width: fields are read as digit runs and then range-checked, so a zero-padded 00:00:003 reads as 3 seconds while 00:00:599 is still rejected.
Every method returns null for text it does not recognise — it never throws — so callers can fall back to their own handling (or report their own error) rather than surfacing a java.time message.
  • Field Details

  • Method Details

    • hasOverWideIsoFields

      public static boolean hasOverWideIsoFields(String raw)
      Whether an ISO-shaped temporal STRING carries a field wider than its canonical width — a year of more than 4 digits, or a month / day / hour / minute / second of more than 2. Snowflake's DML write path is stricter than its CAST: live-verified on a real account, '9999-12-31 00:00:003'::TIMESTAMP_NTZ is accepted (3 seconds) while INSERTing the same literal into a TIMESTAMP_NTZ column fails "Timestamp '…' is not recognized" — and so do an over-wide month, day, hour, minute and a 5-digit year, while the NARROWER '2024-1-01 00:00:3' inserts fine. Only ISO-shaped text is judged; anything else (an epoch string, MM/DD/YYYY, DD-MON-YYYY) is left to the scanner.
    • parseDateTime

      public static LocalDateTime parseDateTime(String raw)
      Parse a date + optional time (+ optional zone offset, discarded); null if unrecognised.
    • parseDateTime

      public static LocalDateTime parseDateTime(String raw, int[] offsetOut)
      Parse a date + optional time + optional zone, reporting the zone's offset in MINUTES through offsetOut — NO_OFFSET when the text carries none. The scanner still yields the WALL CLOCK; what the offset means is the caller's business, because it depends on the target: a TIMESTAMP_NTZ drops it and a TIMESTAMP_TZ or _LTZ moves the instant by it.

      The accepted spellings are narrow and were measured one at a time: +HHMM, +HH:MM, +HH, +H and an UPPER-CASE Z, with or without a space before them. A lower-case z, a seconds field (+03:00:30), and the zone NAMES UTC, GMT and America/Los_Angeles are all refused on a real account — the last three despite reading like the most obvious spellings of all.

    • parseDate

      public static LocalDate parseDate(String raw)
      Parse a date, tolerating (and discarding) a trailing time and zone; null if unrecognised.