# date.script # define date expressions from "Monday, January 1, 1" to "Sunday, # December 31, 9999" and build a shallow parser to mark them define OneToNine [1|2|3|4|5|6|7|8|9]; define ZeroToNine ["0"|OneToNine]; define Even [{0} | 2 | 4 | 6 | 8] ; define Odd [1 | 3 | 5 | 7 | 9] ; define N [Even | Odd]; define Day [{Monday} | {Tuesday} | {Wednesday} | {Thursday} | {Friday} | {Saturday} | {Sunday}] ; define Month29 {February}; define Month30 [{April} | {June} | {September} | {December}]; define Month31 [{January} | {March} | {May} | {July} | {August} | {October} | {December}] ; define Month [Month29 | Month30 | Month31]; # Numbers from 1 to 31 define Date [OneToNine | [1 | 2] ZeroToNine | 3 [%0 | 1]] ; # Numbers from 1 to 9999 define Year [OneToNine ZeroToNine^<4]; # Day or [Month and Date] with optional Day and Year define AllDates [Day | (Day {, }) Month { } Date ({, } Year)]; # Constraints on dates 30 and 31 define MaxDays30 ~$[Month29 { 30}]; define MaxDays31 ~$[[Month29 | Month30] { 31}]; # Combining constraints on dates 30 and 31 define MaxDays [MaxDays30 & MaxDays31]; # Divisible by 4 # Of single digit numbers, 4 and 8 are divisible by 4. # In larger numbers divisible with 4, if the penultimate # is even, the last number is 0, 4, or 8. If the penultimate # is odd, the last number is 2 or 6. define Div4 [4 | 8 | N* [Even [%0 | 4 | 8] | Odd [2 | 6]]]; # Leap years are divisible by 4 but we subtract centuries # that are not divisible by 400. Note the double # subtraction. [[N+ - Div4] {00}] includes 1900 but not 2000. define LeapYear [Div4 - [[N+ - Div4] {00}]] ; # Note the [.#. | \N] at the end of the right context. # 2005 is not a leap year although the year 200 was (in principle). define LeapDates {February 29, } => _ LeapYear [.#. | \N]; define ValidDates [AllDates & MaxDays & LeapDates]; define DateParser [ValidDates @-> "" ... ""] ; echo echo Testing DateParser push DateParser down Today is Wednesday, October 5, 2004. down Yesterday was Tuesday. down February 29, 2000 was a leap day. down but February 29, 1900 was not a leap day. down Next leap day is on February 29, 2008.