# C[omp]ute

Welcome to my blog, which was once a mailing list of the same name and is still generated by mail. Please reply via the "comment" links.

Always interested in offers/projects/new ideas. Eclectic experience in fields like: numerical computing; Python web; Java enterprise; functional languages; GPGPU; SQL databases; etc. Based in Santiago, Chile; telecommute worldwide. CV; email.

© 2006-2017 Andrew Cooke (site) / post authors (content).

## A Specification For Repeating Events

From: andrew cooke <andrew@...>

Date: Thu, 5 Jul 2018 16:21:50 -0400

Introduction

Calendars need to specify repeating events - things like "the second
Tuesday in every month".  I give a way to specify these, with a simple
text format, and also consider some efficiency issues.

Frames and Locations

Repeating events usually consist of a repeating frame and some
location within that frame.  For example, in "the second Tuesday in
every month", the repeating frame is the month and the location is the
second Tuesday.

Frames may repeat with spacing.  For example, "the second Tuesday in
alternate months".  And there may be multiple locations.  For example
"the first Monday and second Tuesday in ...".

Granularity

I am only considering day / week / month repetition, but I think
things should extend to finer granularities if needed.

Date Formats and Timezones

I am ignoring timezones (because of the granularity), but if needed a
timezone code could be appended to the following formats.

Calendar dates are ISO format: YYYY-MM-DD.

It is useful to define ordinals for days, weeks and months.  I base
these on the Unix epoch, so day 0 is 1970-01-01, week 0 is the week
(Mon-Sun) that includes that, month 0 is Jan 1970.  To identify the
frame type, when necessary, I used d/w/m.  So 10d is 1970-01-11, 1m is
Feb 1970, etc.

To label days of the week I use the first two letters of the English
name (Mo, Tu etc).  Code should be case agnostic.

Frame Specification

The specification has the form:

Offset / Repetition FrameType

where offset can be a general data or epoch ordinal that includes a
typical frame or (in the normalized case) the reduced epoch ordinal
(modulo the repetition).  The repetition can be omitted if 1 and
"Offset /" can be omitted if the offset is zero.

So, for example,

1970-02-01/3m  is a frame that repeats ever three months and
includes Feb 1970.

1/3m  is the normalized form for the above.

More examples:

d  is a frame that repeats every day.

1/2d  is a frame for alternate days, starting on 1970-01-02

Nested Frames

At this point a design decision is necessary.  How do we identify
weekdays within a month?  This could be handled with nested frames,
which locate a week within the month, and which could be extended to
locating months within years if the framework were extended to have
years as frames.

Instead, for readability and simplicity of the specification, I will
use a special syntax for this case (see below).

Location Specification

These are grouped in square brackets, comma-separated.

Days of the week or month are numbered, with an optional trailing "d".
So [15] or [15d] is the 15th day of the month.  Monday is the first
day of the week.

It is also possible to identify a week relative to a month using a
number (optional when 1) followed by "w".  So [2w] is the second week.

The above could be extended to included ordinal years, with month
locations.  I don't plan to support this, but the location would be
[3m] for the third month.

For both days and weeks, the number is optional when 1 except in the
case when the "d" is also omitted (so the first day must be either [d]
or [1]).

Days of the week are named, with an ordinal prefix (again, optional
for first).  So [1Mo] or [Mo] is the first Monday, [2Mo,3Tu] is second
Monday and third Tuesday.  This is the special syntax mentioned earlier.

Range Constraints

A specification may only apply for a certain range of dates.  This is
specified as two dates separated by a dash.  Either date is optional
(indicating open ranges) and the dash may be omitted when no dates are
present.

The first date is inclusive, the second exclusive.

The dates are typically in ISO format, but could also be epoch
ordinals.  Since these must match the type (day, week etc) for the
frame they are specified as simple integers.

So 1970-01-01-1970-01-02 and 0-1 are both valid for a frame of days.

Complete Specification

Combining the above in order, here are some examples:

m[2Tu]  second Tuesday in every month

2m[2Tu]  second Tuesday in alternate months (Jan, Mar, ...)

1/2m[2Tu]  second Tuesday in alternate months (Feb, Apr, ...)

m[2Tu]1970-01-01-1971-01-01  second Tuesday of each month in 1970

m[2Tu]0-12  second Tuesday of each month in 1970

0/1m[2Tu]0-12  second Tuesday of each month in 1970

2018-07-05/5d[1d]  every fifth day, including 2018-07-05

In the above, the location is arguably redundant.  An empty location
specification (ie "[]") means that the whole frame is used:

2018-07-05/5d[]  every fifth day, including 2018-07-05

Efficiency

In the normalized form the specification exposes information that
allows many candidates to be discarded:

* Specifications with a date range that exclude the date of
interest.

* Specifications with a reduced offset that does not match the date
of interest.

* Locations that do not match the day of interest.

In addition, it appears that an implementation that expands
specifications to dates should be relatively efficient providing there
is an efficient method to calculate epoch ordinals (which must surely
be possible).

Andrew

Updates:

* Removed ordinal type from range (must match repeat).