Marcin 'Qrczak' Kowalczyk
qrczak at knm.org.pl
Mon Jan 24 08:16:16 EST 2005
Keith Wansbrough <Keith.Wansbrough at cl.cam.ac.uk> writes:
> In particular, people often want to compute with time differences:
> next week, next month, next year, etc. These are calendar operations,
> and defining precisely what they mean in edge cases is often tricky.
> Even discounting leap seconds and the like, "next month" is sometimes
> 28 days into the future, sometimes 29, sometimes 30, and sometimes
> 31 - and sometimes makes little sense: when is "31 January 2005 plus
> one month"?
We should look how other languages solve that.
C provides only mktime, conversion from a broken-down time which lets
out-of-range values adjust larger units. This is not sufficient for
implementing adjustment of a single unit in the intuitive way: it
can't be done by the naive algorithm of incrementing the value and
normalizing the resulting date. For example 30 April + 1 day should be
1 May, but 31 March + 1 month should be 30 April. Yet both calculations
would ask to normalize 31 April, and the normalization function doesn't
know which out-of-range units have been just set explicitly and should
be wrapped, and which result from changing the larger unit and should
Here is the Java interface:
and the .NET interface:
Both systems allow to adjust individual fields. Java is more complex
here, it also provides an interface for rolling with wraparound.
Neither language provides a type for representing a timespan which
is not a well-defined number of seconds. Java has no timespan type at
all, while the .NET TimeSpan can be viewed only in units not larger
than a day - no months or years. These languages provide metods for
adjustments of individual fields, without materializing the timespan
as a whole.
* * *
.NET provides some calendars other than the Gregorian calendar, while
Java does not (but it leaves room for them: there is an abstract class
Calendar whose only standard subclass is GregorianCalendar):
* * *
Java attacks a problem which .NET doesn't: specifying the date in
terms of fields which are usually considered derived from other
fields, like day of week and day of year:
| If there is any conflict in calendar field values, Calendar gives
| priorities to calendar fields that have been set more recently. The
| following are the default combinations of the calendar fields. The
| most recent combination, as determined by the most recently set
| single field, will be used.
| For the date fields:
| YEAR + MONTH + DAY_OF_MONTH
| YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK
| YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK
| YEAR + DAY_OF_YEAR
| YEAR + DAY_OF_WEEK + WEEK_OF_YEAR
| For the time of day fields:
| AM_PM + HOUR
Since there are various rules about numbering weeks of a year in use,
attacking the above problem requires to let the programmer specify the
rule. In Java it is done by setting the minimal number of days in the
first week of a year, while .NET provides enum CalendarWeekRule with
values FirstDay, FirstFullWeek and FirstFourDayWeek, corresponding to
the three values actually in use (1, 7 and 4 respectively).
* * *
For my language Kogut I designed a small interface which I believe
is rich enough.
A date can be constructed out of fields year, month, day, hour,
minute, second, and tick (nanosecond in my implementation). A date
also appears to have fields dayOfYear and dayOfWeek, but they are
always computed rather than provided on input.
There are also timezones; I won't describe them here now.
Out-of-range fields are normalized and cause adjustment of other
fields on construction. Dates are immutable.
The generic operation of functional update of selected fields of a
record has a specialized implementation for dates. Since it knows
which fields are being set and which are being kept from the date of
reference, it can distinguish between changing the day of 30 April to
31 (it gives 1 May) and changing the month of 31 March to April (it
gives 30 April).
So there are no operations for adding a specific amount to a field,
since setting it to the old value + the delta has the right semantics,
contrary to mktime.
There are no operations for rolling of fields - it's easy enough to
perform the modulo by hand.
There is no interface for getting or setting the week of a year/month,
because they would require additional complexity of selecting the
rules to use, and it's easy enough to implement them in terms of the
day of the year/month and the day of the week.
There is no interface for setting the day of the year, because it's
equivalent to setting the corresponding day of January.
Time is in 24 hour format - Java provides both formats at once, but
I claim that it's easy enough to convert it by hand when needed.
There is no type for a timespan, and there will not be. It's easy
enough to adjust individual fields.
I haven't yet implemented formatting nor parsing of dates. There are
too many non-obvious design decisions here. But this will have to be
done at some time.
__("< Marcin Kowalczyk
\__/ qrczak at knm.org.pl
More information about the Libraries