Skip to content

Commit

Permalink
Use a regex to parse ISO8601 dates
Browse files Browse the repository at this point in the history
  • Loading branch information
Joey Marianer committed Apr 1, 2021
1 parent 80052e5 commit f774bfc
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 4 deletions.
38 changes: 34 additions & 4 deletions src/builtin.jq
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,6 @@ def _flatten($x): reduce .[] as $i ([]; if $i | type == "array" and $x != 0 then
def flatten($x): if $x < 0 then error("flatten depth must not be negative") else _flatten($x) end;
def flatten: _flatten(-1);
def range($x): range(0;$x);
def fromdateiso8601: strptime("%Y-%m-%dT%H:%M:%SZ")|mktime;
def todateiso8601: strftime("%Y-%m-%dT%H:%M:%SZ");
def fromdate: fromdateiso8601;
def todate: todateiso8601;
def match(re; mode): _match_impl(re; mode; false)|.[];
def match($val): ($val|type) as $vt | if $vt == "string" then match($val; null)
elif $vt == "array" and ($val | length) > 1 then match($val[0]; $val[1])
Expand All @@ -78,6 +74,40 @@ def scan(re):
then [ .captures | .[] | .string ]
else .string
end ;
def fromdateiso8601:
capture
( "^(?<year>[0-9]{4})"
+ "-(?<month>[0-9]{2})"
+ "-(?<day>[0-9]{2})"
+ "T(?<hour>[0-9]{2})"
+ ":(?<minute>[0-9]{2})"
+ ":(?<second>[0-9]{2})"
+ "(?<subseconds>\\.[0-9]+)?" # Support optional subsecond precision
+ "(Z|" # Support Zulu or offset
+ "(?<offset_sign>[-+])"
+ "(?<offset_hours>[0-9]{2})"
+ ":?"
+ "(?<offset_minutes>[0-9]{2})"
+ ")$")

# Subseconds are optional, and so is the offset if Zulu time is specified
| .subseconds //= 0
| .offset_hours //= 0
| .offset_minutes //= 0
| .offset_sign //= "+" # string math ftw

| .offset_sign += "1" # string math ftw

| (.year, .month, .day, .hour, .minute, .second,
.subseconds, .offset_sign, .offset_hours, .offset_minutes) |= tonumber
| .offset = (.offset_hours * 3600 + .offset_minutes * 60)
* .offset_sign * -1 # the Earth rotates eastward

| ([.year, .month - 1, .day, .hour, .minute, .second, 0, 0] | mktime)
+ .offset + .subseconds;
def todateiso8601: strftime("%Y-%m-%dT%H:%M:%SZ");
def fromdate: fromdateiso8601;
def todate: todateiso8601;
#
# If input is an array, then emit a stream of successive subarrays of length n (or less),
# and similarly for strings.
Expand Down
20 changes: 20 additions & 0 deletions tests/man.test
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,22 @@ fromdate
"2015-03-05T23:51:47Z"
1425599507

fromdate
"2015-03-05T23:51:47+00:00"
1425599507

fromdate
"2015-03-05T23:51:47+01:00"
1425595907

fromdate
"2015-03-05T23:51:47-01:00"
1425603107

fromdate
"2015-03-05T23:51:47.123456Z"
1425599507.123456

strptime("%Y-%m-%dT%H:%M:%SZ")
"2015-03-05T23:51:47Z"
[2015,2,5,23,51,47,4,63]
Expand All @@ -651,6 +667,10 @@ strptime("%Y-%m-%dT%H:%M:%SZ")|mktime
"2015-03-05T23:51:47Z"
1425599507

fromdateiso8601
"2015-03-05T23:51:47Z"
1425599507

.[] == 1
[1, 1.0, "1", "banana"]
true
Expand Down

0 comments on commit f774bfc

Please sign in to comment.