time-recurrence is a Haskell library for working with recurring date/times.
The iCalendar Specifcation (RFC 5545) is used for inspiration of this
library, however the library does not make an effort to track the RFC
at all times. A future Data.Time.Recurrence.RFC5545 library would be
a useful add-on for those in need of strict RFC compliance.
Examples:
> parse822Time :: String -> UTCTime
> parse822Time = ...
> nov1996 = parse822Time "Tue, 05 Nov 1996 09:00:00 -0400"
> mar1997 = parse822Time "Mon, 10 Mar 1997 09:00:00 -0400"
> sep1997 = parse822Time "Tue, 02 Sep 1997 09:00:00 -0400"
> oct1997 = parse822Time "Fri, 10 Oct 1997 00:00:00 -0400"
> dec1997 = parse822Time "Wed, 24 Dec 1997 00:00:00 -0400"
> jan1998 = parse822Time "Thu, 01 Jan 1998 09:00:00 -0400"
> jan2000 = parse822Time "Mon, 31 Jan 2000 09:00:00 -0400"
Daily for 10 occurrences:
> take 10 $ starting sep1997 $ recur daily
Daily until Dec. 24, 1997:
> takeWhile (<= dec1997) $ starting sep1997 $ recur daily
Every other day - forever:
> starting sep1997 $ recur daily `by` 2
Every 10 days, 5 occurrences:
> take 5 $ starting sep1997 $ recur daily `by` 10
Every day in January, for 3 years:
> takeWhile (<= jan2000) $ starting jan1998 $
> recur yearly
> >==> enum (Months [January])
> >==> filter (WeekDays [Monday .. Sunday])
> takeWhile (<= jan2000) $ starting jan1998 $
> recur daily
> >==> enum (Months [January])
Weekly for 10 occurrences:
> take 10 $ starting sep1997 $ recur weekly
Weekly until Dec. 24, 1997:
> takeWhile (<= dec1997) $ starting sep1997 $
> recur weekly `withStartOfWeek` Sunday
Every other week - forever:
> starting sep1997 $ recur weekly `by` 2
Weekly on Tuesday and Thursday for five weeks:
> takeUntil (<= oct1997) $ starting sep1997 $
> recur weekly `withStartOfWeek` Sunday
> >==> enum (WeekDaysInWeek [Tuesday, Thursday])
or
> take 10 $ starting sep1997 $
> recur weekly `withStartOfWeek` Sunday
> >==> enum (WeekDaysInWeek [Tuesday, Thursday])
Every other week (Monday, Wednesday, Firday) until Dec. 24, 1997:
> takeWhile (<= dec1997) $ starting sep1997 $
> recur weekly `withStartOfWeek` Sunday `by` 2
> >==> enum (WeekDaysInWeek [Monday, Wednesday, Friday])
> Every other week on Tuesday and Thursday, for 8 occurrences:
> take 8 $ starting sep1997 $
> recur weekly `by` 2 `withStartOfWeek` Sunday
> >==> enum (WeekDaysInWeek [Tuesday, Thursday])
Monthly on the first Friday for 10 occurrences:
> take 10 $ starting sep1997 $
> recur monthly
> >==> enum (WeekDaysInMonth [Friday])
> >==> select (WeekDaysInMonth [1])
Monthly on the first Friday until Dec. 24, 1997
> takeWhile (<= dec1997) $ starting sep1997 $
> recur monthly
> >==> enum (WeekDaysInMonth [Friday])
> >==> select (WeekDaysInMonth [1])
Every other month on the first and last Sunday of the month for 10 occurrences:
> take 10 $ starting sep1997 $
> recur monthly
> >==> enum (WeekDaysInMonth [Sunday])
> >==> select (WeekDaysInMonth [1,-1])
Monthly on the second-to-last Monday of the month for 6 months:
> take 6 $ starting sep1997 $
> recur monthly
> >==> enum (WeekDaysInMonth [Monday])
> >==> select (WeekDaysInMonth [-2])
Monthly on the third-to-last day of the month, forever:
> starting sep1997 $
> recur monthly
> >==> enum (Days [-3])
Monthly on the 2nd and 15th of the month for 10 occurrences:
> take 10 $ starting sep1997 $
> recur monthly
> >==> enum (Days [2,15])
Monthly on the first and last day of the month for 10 occurrences:
> take 10 $ starting sep1997 $
> recur monthly
> >==> enum (Days [1,-1])
Every 18 months on the 10th thru 15th of the month for 10 occurrences:
> take 10 $ starting sep1997 $
> recur monthly
> >==> enum (Days [10 .. 15])
Every Tuesday, every other month:
> starting sep1997 $
> recur monthly `by` 2
> >==> enum (WeekDaysInMonth [Tuesday])
Yearly in June and July for 10 occurrences:
> take 10 $ starting sep1997 $
> recur yearly
> >==> enum (Months [June, July])
Every other year on January thru March for 10 occurrences:
> take 10 $ starting mar1997 $
> recur yearly `by` 2
> >==> enum (Months [January .. March])
> >==> enum (WeekDaysInMonth [Monday .. Sunday])
Every third year on the 1st, 100th, and 200th day for 10 occurrences:
> take 10 $ starting sep1997 $
> recur yearly `by` 3
> >==> enum (YearDays [1,100,200])
Every 20th Monday of the year, forever:
> starting sep1997 $
> recur montly
> >==> enum (WeekDaysInMonth [Monday])
> >==> select (WeekDays [20])
Monday of week number 20, forever:
> starting mar1997 $
> recur yearly
> >==> enum (Weeks [20])
> >==> filter (WeekDays [Monday])
or
> starting mar1997 $
> recur weekly
> >==> filter (Weeks [20])
> >==> filter (WeekDays [Monday])
Every Thursday in March, forever:
> starting mar1997 $
> recur yearly
> >==> enum (Months [March])
> >==> enum (WeekDaysInMonth [Thursday])
Every Thursday, but only during June thru August, forever:
> starting mar1997 $
> recur yearly
> >==> enum (Months [June .. August])
> >==> enum (WeekDaysInMonth [Thursday])
Friday the 13th, Forever:
> starting sep1997
> recur monthly
> >==> enum (Days [13])
> >==> filter (WeekDays [Friday])
The first Saturday that follows the first Sunday of the month, forever:
> recur monthly sep1997 $
> enumDays [7 .. 13] >=>
> filterWeekDays [Saturday]
U.S. Presidential Election Day:
Every 4 years, the first Tuesday after a Monday in November, forever:
> starting nov1996 $
> recur yearly `by` 4
> >==> enum (Months [November])
> >==> enum (Days [2 .. 8])
> >==> filter (WeekDays [Tuesday])
The third instance into the month of one of Tuesday, Wednesday, or Thursday, for the next 3 months.
> take 3 $ starting sep1997 $
> recur monthly
> >==> enum (WeekDaysInMonth [Tuesday .. Thursday])
> >==> select (WeekDaysInMonth [3])
The second-to-last weekday of the month:
> starting sep1997 $
> recur monthly
> >==> enum (WeekDaysInMonth [Monday .. Friday])
> >==> select (WeekDaysInMonth [-2])
Every 3 hours from 9:00 AM to 5:00 PM on a specific day:
> takeWhile (<= addSeconds sep1997 (8 * oneHour)) $
> starting sep1997 $
> recur hourly `by` 3
Every 15 minutes for 6 occurrences:
> take 6 $ starting sep1997 $
> recur minutely `by` 15
Every hour and a half for 4 occurrences:
> take 4 $ starting sep1997 $ recur minutely `by` 90
Every 20 minutes from 9:00 AM to 4:40 PM every day:
> staring sep1997 $
> recur daily $
> >==> enum (Hours [9 .. 16])
> >==> enum (Minutes [0,20,40])
or
> starting sep1997 $
> recur minutely `by` 20
> >==> enum (Hours [9 .. 16])
The following two examples will generate different results due to changes in the start of the week.
> take 4 $
> recur weekly `by` 2 `withStartOfWeek` Monday
> >==> enum (WeekDaysInWeek [Tuesday, Sunday])
vs
> take 4 $
> recur weekly `by` 2 `withStartOfWeek` Sunday
> >==> enum (WeekDaysInWeek [Tuesday, Sunday])
An example where an invalid date (Feb. 30) is ignored:
> take 5 $ starting jan2000 $
> recur monthly
> >==> enum (Days [15,30])
The 15th and the 30th of the month, forever:
> starting sep1997 $
> recur monthly
> >==> enum (Days [15,30])
The 15th and the 30th of the month, but only during the work week:
> starting sep1997 $
> recur monthly
> >==> enum (Days [15,30])
> >==> filter (WeekDays [Monday .. Friday])