---- -*- Mode: rpl; -*-
---- vim:syn=rosie
----
---- time.rpl Common time patterns in Rosie Pattern Language
----
---- © Copyright IBM Corporation 2016, 2017.
---- LICENSE: MIT License (https://opensource.org/licenses/mit-license.html)
---- AUTHORS: Jamie A. Jennings, Kevin Zander
rpl 1.1
package time
local alias d = [0-9]
-- RFC3339
--
-- time-hour = 2DIGIT ; 00-23
-- time-minute = 2DIGIT ; 00-59
-- time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on leap second
-- ; rules
-- time-secfrac = "." 1*DIGIT
-- time-numoffset = ("+" / "-") time-hour ":" time-minute
-- time-offset = "Z" / time-numoffset
--
-- partial-time = time-hour ":" time-minute ":" time-second
-- [time-secfrac]
-- full-time = partial-time time-offset
--
-- Note: The "Z" separator may be lowercase.
hour = { [01] [0-9] } /
{ "2" [0-3] }
-- test hour accepts "00", "15", "20", "23"
-- test hour rejects "", "0", "5", "24", "99"
minute = { [0-5] [0-9] }
-- test minute accepts "00", "25", "39", "59"
-- test minute rejects "", "0", "60", "99"
second = { [0-5] [0-9] } / "60" -- time_second must match 60 for leap second
-- test second accepts "00", "24", "47", "59", "60"
-- test second rejects "", "0", "9", "61", "99"
secfrac = { [:,.] [0-9]+ }
-- test secfrac accepts ".00000", ".12435", ".99999999", ".0"
-- test secfrac accepts ",0", ",12435"
-- test secfrac rejects "", "0", ".", ".now", ".0r", ".never"
numoffset = { [+\-] hour ":" minute }
-- test numoffset accepts "+00:10", "-23:59"
-- test numoffset rejects "@12:34", "-55:00", "+2:30"
offset = [Zz] / numoffset
-- test offset accepts "Z", "z", "+00:10", "-23:59"
-- test offset rejects "", "2", "*00:00", "+00:60"
rfc3339_time = { hour ":" minute ":" second secfrac? }
-- test rfc3339_time accepts "00:00:00", "00:00:00.00000", "10:30:02.125", "23:59:60"
-- test rfc3339_time rejects "", "24:10:10", "17:28:33.0r"
rfc3339_strict = { rfc3339_time offset }
-- RFC2822
-- time = time-of-day FWS zone
-- time-of-day = hour ":" minute [ ":" second ]
-- hour = 2DIGIT
-- minute = 2DIGIT
-- second = 2DIGIT
-- zone = (( "+" / "-" ) 4DIGIT) / obs-zone
-- obs-zone = "UT" / "GMT" / ; Universal Time
-- "EST" / "EDT" / "CST" / "CDT" / ; North American
-- "MST" / "MDT" / "PST" / "PDT"
-- Notes:
-- No support for military time zones (which are marked obsolete)
-- Not restricting 'day' value based on the values of month and year. 0-31 is always valid.
alias rfc2822_numeric_zone = { [+\-] d{4} }
-- test rfc2822_numeric_zone accepts "+0000", "-4321", "+9999", "-9870"
-- test rfc2822_numeric_zone rejects "", "@0100", "-1", "+50", "1000"
alias rfc2822_obsolete_zone = "UTC" / "UT" / "GMT" / "CET" / "EST" / "EDT" /
"CST" / "CDT" / "MST" / "MDT" / "PST" / "PDT"
-- test rfc2822_obsolete_zone accepts "UT", "UTC", "PDT"
-- test rfc2822_obsolete_zone rejects "-0500"
rfc2822_zone = rfc2822_numeric_zone / rfc2822_obsolete_zone
rfc2822_time = { hour ":" minute {":" second}? }
-- test rfc2822_time accepts "00:00:00", "12:00", "23:59:60", "16:08:33", "01:55",
-- test rfc2822_time rejects "", "24:10:10", "33:40", "17:28:33.0", "00:00:00.00000", "10:30:02.125"
rfc2822_strict = { rfc2822_time rfc2822_zone }
rfc2822_frac = { hour ":" minute {":" second secfrac?}? } -- Extension to the standard
-- Misc formats
ampm = "AM" / "am" / "PM" / "pm"
sequence = d+
short_hour = { [1] [0-9] } / { [2] [0-3] } / {[0] [0-9]?} / [0-9]
simple = { short_hour ":" minute {":" second secfrac?}? } ampm?
websphere = { rfc2822_time ":" sequence } rfc2822_zone
db2 = { hour "." minute "." second "." sequence }
-- test simple accepts "1:05", "0:00"
-- Useful top-level patterns
rfc2822 = { {rfc2822_frac / rfc2822_time} rfc2822_zone?}
rfc3339 = { rfc3339_time offset? }
any = rfc3339 / rfc2822_frac / websphere / simple / db2
-- test rfc3339 accepts "11:35:38.490", "11:35:38.490z", "11:35:38.490Z", "11:35:38.490-05:00"
-- test rfc2822 accepts "11:35", "11:35:38.490"
-- test rfc2822 accepts "11:35-0800", "11:35:38.490-0500"
-- test rfc2822_strict accepts "11:35:03+0000"
-- test rfc2822_frac accepts "11:35:38.490" --