[m-rev.] calendar module proposal

Ian MacLarty maclarty at csse.unimelb.edu.au
Tue Jan 27 17:19:05 AEDT 2009


On Tue, Jan 27, 2009 at 04:38:52PM +1100, Ralph Becket wrote:
> This looks good.
> 
> Ian MacLarty, Tuesday, 27 January 2009:
> > Hi,
> > 
> > Here's a proposal for a calendar module for the standard library.
> > Could interested people take a look and give me some feedback?
> > Since this module only implements the Gregorian calendar, it might not
> > be suitable for working with dates prior to 1582.  Perhaps it should be
> > renamed to gregorian_calendar or gcalendar?
> > 
> > Ian.
> > 
> > Index: library/calendar.m
> > ===================================================================
> > RCS file: library/calendar.m
> > diff -N library/calendar.m
> > --- /dev/null	1 Jan 1970 00:00:00 -0000
> > +++ library/calendar.m	27 Jan 2009 03:51:25 -0000
> > @@ -0,0 +1,961 @@
> > +%-----------------------------------------------------------------------------%
> > +% vim: ft=mercury ts=4 sw=4 et wm=0 tw=0
> > +%-----------------------------------------------------------------------------%
> > +% Copyright (C) 2009 The University of Melbourne.
> > +% This file may only be copied under the terms of the GNU Library General
> > +% Public License - see the file COPYING.LIB in the Mercury distribution.
> > +%-----------------------------------------------------------------------------%
> > +% 
> > +% File: calendar.m.
> > +% Main authors: maclarty
> > +% Stability: low.
> > +% 
> > +% Proleptic Gregorian calendar utilities.
> 
> Can prolepsy be cured with antibiotics?
> 

No, but it might be cured by implementing a hybrid Julian/Gregorian
calendar.  Such a calendar would use the Julian system before a given
crossover date and the Gregorian system after this date.  The crossover
date would need to be changable, because different countries started
using the Gregorian calendar at different times.  This cure would have
the side-effects of a more complicated interface and implementation.

> > +% 
> > +%-----------------------------------------------------------------------------%
> > +%-----------------------------------------------------------------------------%
> > +
> > +:- module calendar.
> > +:- interface.
> > +
> > +:- import_module io.
> > +
> > +%-----------------------------------------------------------------------------%
> > +
> > +    % A point on the Proleptic Gregorian calendar, to the nearest second.
> > +    %
> > +:- type date.
> 
> What's the start of the epoch?  Or is that irrelevant?
> 

I don't really think it's that relevant, because the calendar extends
indefinitely into the past.  I guess you could regard it as when the
Gregorian calendar was introduced, but I believe this differs from
country to country.

> > +
> > +    % A period of time measured in years, months, days, hours, minutes and
> > +    % seconds.
> > +    %
> > +:- type duration.
> > +
> > +:- type month
> > +    --->    january
> > +    ;       february
> > +    ;       march
> > +    ;       april
> > +    ;       may
> > +    ;       june
> > +    ;       july
> > +    ;       august
> > +    ;       september
> > +    ;       october
> > +    ;       november
> > +    ;       december.
> > +
> > +    
> > +    % Date components.
> > +    %
> > +:- type year == int.         % Year 0 is 1 BC, -1 is 2 BC, etc.
> > +:- type day_of_month == int. % 1..31 depending on the month and year
> > +:- type hour == int.         % 0..23
> > +:- type minute == int.       % 0..59
> > +:- type second == int.       % 0..61 (60 and 61 are for leap seconds)
> > +
> > +:- type day_of_week
> > +    --->    sunday
> > +    ;       monday
> > +    ;       tuesday
> > +    ;       wednesday
> > +    ;       thursday
> > +    ;       friday
> > +    ;       saturday.
> > +
> > +    % Duration components.
> > +    %
> > +:- type years == int.
> > +:- type months == int.
> > +:- type days == int.
> > +:- type hours == int.
> > +:- type minutes == int.
> > +:- type seconds == int.
> > +
> > +    % Functions to retrieve the components of a date.
> > +    %
> > +:- func year(date) = year.
> > +:- func month(date) = month.
> > +:- func day_of_month(date) = day_of_month.
> > +:- func day_of_week(date) = day_of_week.
> > +:- func hour(date) = hour.
> > +:- func minute(date) = minute.
> > +:- func second(date) = second.
> > +
> > +    % init_date(Year, Month, Day, Hour, Minute, Second) = DT.
> > +    % Initialize a new date.  Fails if the given date is invalid.
> > +    %
> > +:- pred init_date(year::in, month::in, day_of_month::in, hour::in,
> > +    minute::in, second::in, date::out) is semidet.
> > +
> > +    % Same as above, but aborts if the date is invalid.
> > +    %
> > +:- func det_init_date(year, month, day_of_month, hour, minute, second) =
> > +    date.
> 
> What about an unpacking predicate for dates?
> 

I've added predicates for unpacking dates and durations.

> > +
> > +    % duration(Date1, Date2) = Duration.
> > +    % Find the duration between two dates using a "greedy" algorithm.  The
> > +    % algorithm is greedy in the sense that it will try to maximise each
> > +    % component in the returned duration in the following order: years, months,
> > +    % days, hours, minutes, seconds.
> > +    % The returned duration is positive if Date2 is after Date1 and negative
> > +    % if Date2 is before Date1.
> > +    % Any leap seconds that occured between the two dates are ignored.
> > +    %
> > +    % If the seconds components of Date1 and Date2 are < 60 then
> > +    % add_duration(Date1, duration(Date1, Date2), Date2) will hold, but
> > +    % add_duration(Date2, negate(duration(Date1, Date2)), Date1) may not
> > +    % hold.  For example if:
> > +    %   Date1 = 2001-01-31
> > +    %   Date2 = 2001-02-28
> > +    %   Duration = 1 month
> > +    % then the following holds:
> > +    %   add_duration(duration(Date1, Date2), Date1, Date2)
> > +    % but the following does not:
> > +    %   add_duration(negate(duration(Date1, Date2), Date2, Date1)
> > +    % (Adding -1 month to 2001-02-28 will yield 2001-01-28).
> > +    %
> > +:- func duration(date, date) = duration.
> > +
> > +    % Same as above, except that the year and month components of the
> > +    % returned duration will always be zero.  The duration will be
> > +    % in terms of days, hours, minutes and seconds only.
> > +    %
> > +:- func day_duration(date, date) = duration.
> 
> Can you use day_duration on dates more than a year apart?
> 

Yes, but the years and months will be converted to days.
Note that you need a separate day_duration function, because you can't
convert a duration with years and months into one with only days, hours,
minutes and seconds.

Ian.
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list