
Keith Wansbrough
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 be clipped. Here is the Java interface: http://java.sun.com/j2se/1.5.0/docs/api/java/util/Calendar.html and the .NET interface: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/... http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/... 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): http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/... * * * 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: | | HOUR_OF_DAY | 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@knm.org.pl ^^ http://qrnik.knm.org.pl/~qrczak/