[m-rev.] calendar module proposal
Ralph Becket
rafe at csse.unimelb.edu.au
Tue Jan 27 16:38:52 AEDT 2009
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?
> +%
> +%-----------------------------------------------------------------------------%
> +%-----------------------------------------------------------------------------%
> +
> +:- 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?
> +
> + % 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?
> +
> + % Convert a string of the form "YYYY-MM-DD HH:MI:SS" to a date.
> + %
> +:- pred date_from_string(string::in, date::out) is semidet.
> +
> + % Same as above, but aborts if the string is not a valid date.
> + %
> +:- func det_date_from_string(string) = date.
> +
> + % Convert a date to a string of the form "YYYY-MM-DD HH:MI:SS".
> + %
> +:- func date_to_string(date) = string.
> +
> + % Parse a duration string conforming to the representation
> + % described at http://www.w3.org/TR/xmlschema-2/#duration.
> + %
> +:- pred duration_from_string(string::in, duration::out) is semidet.
> +
> + % Same as above, but aborts if the string does not represent
> + % a valid duration.
> + %
> +:- func det_duration_from_string(string) = duration.
> +
> + % Convert a duration to the string representation
> + % described at http://www.w3.org/TR/xmlschema-2/#duration.
> + %
> +:- func duration_to_string(duration) = string.
> +
> + % Get the current local time.
> + %
> +:- pred current_local_time(date::out, io::di, io::uo) is det.
> +
> + % Get the current UTC time.
> + %
> +:- pred current_utc_time(date::out, io::di, io::uo) is det.
> +
> + % Get the difference between the local time and utc time
> + % as a duration.
> + % local_time_offset(TZ, !IO) is equivalent to:
> + % current_local_time(Local, !IO),
> + % current_utc_time(UTC, !IO),
> + % TZ = duration(UTC, Local)
> + % except that it is as if the calls to current_utc_time and
> + % current_local_time occured at the same instant.
> + %
> +:- pred local_time_offset(duration::out, io::di, io::uo) is det.
> +
> + % Functions to retrieve duration components.
> + %
> +:- func years(duration) = years.
> +:- func months(duration) = months.
> +:- func days(duration) = days.
> +:- func hours(duration) = hours.
> +:- func minutes(duration) = minutes.
> +:- func seconds(duration) = seconds.
A predicate to completely unpack a duration would also be useful.
> +
> + % 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?
> +
> + % Add a duration to a date.
> + % First the years and months are added to the date.
> + % If this causes the day to be out of range (e.g. April 31), then it is
> + % decreased until it is in range (e.g. April 30). Next the remaining
> + % days, hours, minutes and seconds components are added. These could
> + % in turn cause the months and years values to change again.
> + % The algorithm used is described in detail at
> + % http://www.w3.org/TR/xmlschema-2/#adding-durations-to-dateTimes.
> + %
> +:- pred add_duration(duration::in, date::in, date::out) is det.
> +
> + % This predicate implements a partial order relation on durations.
> + % The algorithm it uses is described at
> + % http://www.w3.org/TR/xmlschema-2/#duration.
> + % Note that if duration_leq(X, Y) fails, then this does NOT imply
> + % that duration_leq(Y, X) is true. For example a duration of 30 days
> + % is not comparable to a duration of 1 month, so duration_leq will
> + % fail if these are given as inputs in any order.
> + %
> +:- pred duration_leq(duration::in, duration::in) is semidet.
> +
> + % init_{positive|negative}_duration(Years, Months, Days, Hours, Minutes,
> + % Seconds)
> + % Create a new positive or negative duration. All the supplied dimensions
> + % should be non-negative. If they are not the function aborts.
> + %
> +:- func init_positive_duration(years, months, days, hours, minutes, seconds) =
> + duration.
> +:- func init_negative_duration(years, months, days, hours, minutes, seconds) =
> + duration.
> +
> +%----------------------------------------------------------------------------%
> +
--------------------------------------------------------------------------
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