Skip to content

hellertime/time-recurrence

Repository files navigation

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])