How do I parse a date and time?

Short answer: “D”$, “T”$, and “Z”$


In general you can parse strings to some particular type by passing the uppercase form of the corresponding type character as the left argument to $ (cast).

q can parse dates in YYYYMMDD, YYYY-MM-DD, or YYYY.MM.DD format:

q)"D"$ ("20070809"; "2007-08-09"; "2007.08.09")
2007.08.09 2007.08.09 2007.08.09
q)

Times must have the form HH:MM:SS.mmm, but you can shorten them:

q)"T"$ ("07:08:09.010"; "07:08:09"; "07:08"; "07")
07:08:09.010 07:08:09.000 07:08:00.000 07:00:00.000
q)

In addition, “T”$ will tolerate a missing zero for hours (and hours only) less than 10:

q)"T"$ "7:08:09"
07:08:09.000
q)

“Z”$ expects (as in XML) that dates and times are joined with a T:

q)"Z"$ "2007-08-09T07:08:09.101"
2007.08.09T07:08:09.101
q)

“Z”$ usually treats the text analogously to “D”$ and “T”$; that is, the date must be complete, but the time may have its finer points elided:

q)"Z"$ "2007"
0Nz
q)"Z"$ "20070809"
2007.08.09T00:00:00.000
q)

Note, however, the “Z”$ – unlike “T”$ – requires that hours less than 10 be prepended with zero:

q)"Z"$ "20070809T7:08:09"
0Nz
q)

You can also parse months with “M”$, minutes with “U”$, and seconds with “V”$:

q)"M"$ ("2007-08"; "2007.08"; "200708")
2007.08 2007.08 2007.08m
q)"U"$ "07:08:09.010"
07:08
q)"V"$ "07:08:09.010"
07:08:09
q)

Make sure you don’t pass any extra text to “M”$, though:

q)"M"$ "2007.08.01"
2007.01m
q)

There are two more type characters for parsing temporal values. “N”$ and “P”$ are for parsing nanosecond-precise time spans and datetimes, respectively:

q)"N"$ "12D07:08:09.123456789"
12D07:08:09.123456789
q)"P"$ "2007-08-09T07:08:09.123456789"
2007.08.09D07:08:09.123456789
q)

You may have discovered that “N”$ can parse floating point numbers, as well, but beware – depending on the range of the input, you might not get what you expect:

q)"N"$ "0.123456789"
0D00:00:00.123456789
q)"N"$ "1.123456789"
0D01:00:00.123456789
q)"N"$ "12.123456789"
0D12:00:00.123456789
q)"N"$ "24.123456789"
1D00:00:00.123456789
q)"N"$ "48.123456789"
2D00:00:00.123456789
q)"N"$ "4800.123456789"
2D00:00:00.123456789
q)

Stick with strings that represent durations in the way q does, and you’ll steer clear of surprises.

Lastly, if you find yourself with a text full of times expressed as seconds (and, optionally, fractions thereof) since the Unix epoch, “P”$, and “Z”$ can parse them, too:

q)unix_time: first system "date +%s"
q)unix_time
"1311635286"
q)"Z"$ unix_time
2011.07.25T23:08:06.000
q)"P"$ unix_time , ".123456789"
2011.07.25D23:08:06.123456789
q)