Squeak
  links to this page:    
View this PageEdit this PageUploads to this PageHistory of this PageTop of the SwikiRecent ChangesSearch the SwikiHelp Guide
Refactored Date and Time Classes
Last updated at 2:12 pm UTC on 16 January 2006
New Squeak Date Classes

New Squeak Date Classes

Abstract

This document proposes a new date and time class library for the Squeak Smalltalk environment.

(Note: These classes have been added to Squeak 3.7.)

Overview and Scope

The package replaces the existing Date and Time classes with ANSI standard DateAndTime and Duration implementations. The existing Date and Time classes are then reused along with Week, Month and Year classes to provide an intuitive classes library which complements the collection class library.

Motivation and Benefits

Almost all commercial development tools provide woefully poor support for manipulating dates and times. Indeed the J++ implementation of Java forces the application programmer to familiarise himself with up to six different classes. These classes are not compatible with each other and lack basic functionality to compare and manipulate instances. Even expensive tools like VisualAge Generator which targets large commercial projects do not provide library code to add or subtract and arbitrary number of days from a date.

Most implementations are closed and cannot be easily extended necessitating awkward conversion methods. The support for iterating over a time span between two dates is usually very poor. The result is verbose code, cluttered with arcane conversion methods, which it preoccupied with the details of the date instances. Enumeration constructs are extremely susceptible to errors at or near the iteration boundaries.

This situation should not be tolerated by developers. The Gregorian calendar with years, months, weeks and dates is almost universal and is most certainly the dominant calendar used in commercial software. The developer should reasonably expect to see classes which endorse these concepts.

Most significantly, such temporal classes should provide robust, stable and elegant mechanism to iterate over these temporal classes in a manne consistent with the iteration protocol for that language.

Opportunity

Regrettably Smalltalk is not exempt from a date time class library which is not optimised to the real needs of commercial software. Fortunately Smalltalk is better positioned than most environments to correct this as the class library can be modified and extended at will and the language supports closures which provide the developer with an extremely functional mechanism to iterate over a collection of objects.

The timing is also superb.

The ANSI specification has been completed which dictates a very usable protocol for representing dates, times and durations. Implementing the DateAndTime and Duration protocols will provide a standard foundation based on UTC.

This implementation can be augmented by additional temporal classes providing the commercial developer with the craven functionality.

Architecture and Concepts

The new temporal class library implements the DateAndTime and Duration protocols.

The Duration class is interpreted to represent some duration of time possibly negative. DateAndTime instances are interpreted to represent a point in Universal Co-ordinated Time space. By definition they have zero duration.

For completeness the implementation will have nanosecond precision. This is fully UTC compliant and provides the high precision needed for database timestamps and GUI events. This should minimize the need for a further class library to be developed.

To support the new temporal library, we introduce the concept of a Timespan which spans UTC time for a specified duration starting from some arbitrary DateAndTime. This information is sufficient to determine the end time of the duration. The timespan is designed to be similar to the Interval class although its elements are interpreted to be a continuous collection of DateAndTime instances.

This concept is further promoted by introducing classes for familiar the timespans of Years, Months, Weeks and individual dates.

We note that the introduction of the DateAndTime class as the preferred representation of time, frees up the Date class for redeployment. The notion of a date 'Date' is familiar to all people and represents a full day, midnight to midnight, 24 hours, a full 86400 seconds. We leverage this and reuse Date and a new subclass of Timespan. The existing Time remains as a subclass of Magnitude for compatibility. It has been enhanced to support the classes.

Class Hierarchy

Magnitude
    Duration
    DateAndTime
    Time
Object
    TimeZone
Magnitude
    Timespan
        Year
        Month
        Week
        Date
        Schedule
Object
    TimeZone
    Stopwatch

Protocol

Instance protocol

The temporal class are designed to be extremely interoperable to minimize the clutter and preoccupation with irrelevant details. The de facto Smalltalk naming convention of verb\noun is used for methods thoughout and conversion methods are provided in abundance.

The timespan classes re-implement much of the ANSI DateAndTime protocol to reduce unnecessary conversion.

Iteration protocol

The iteration protocol provides the application programmer with the power to express enumeration constructs in the functional manner. This is designed to be similar to the #do:, #select: #collect: methods offered by the Collection classes.

Usage

The example code is be displayed in a workspace. It is by no means exhaustive but provides an indication of the functionality.

Duration

Duration zero.
Duration seconds: 90060.
123 asDuration.
(Duration seconds: 5.4) asDelay wait; beep.
5.4 minutes asDelay wait; beep.

DateAndTime

DateAndTime now.
DateAndTime year: 2000 month: 8 day: 17 hour: 16 minute: 34 second: 40.

Dates

DateAndTime now asDate.
Date today.
d := Date year: 2000 month: 5 day: 28.
d start.
d end.
d duration.
d end - d start.
d dayOfWeekName.

Week

Week startDay.
Week current.
DateAndTime now asWeek.
Date today asWeek.
Week current dates.
Week current datesDo: [ :d | Transcript cr; show: d ].
Week current workDatesDo: [ :d | Transcript cr; show: d dayOfWeekName ].

Month

Month current.
DateAndTime now asMonth.
Month current weeks.
Month current dates.

Year

Year current.
Year year: 2000.
Date today asYear.
Month current asYear.
Year months.

Financial Years

Much of the worlds  financial software deals with financial years which do not neccessarily start on the first day of the year. Consider the financial year April 2001 ending March 2002.
financialYear := Year starting: (Date year: 2001 month: 4 day: 1). "e.g.. 1 April 2001"
financialYear start.
financialYear end.
"Produce a report..."
Transcript clear.
aStream := Transcript.
aStream cr; nextPutAll: 'Report. Financial Year Ending: '.
financialYear end asDate printOn: aStream.
aStream cr; nextPutAll: (String new: 60 withAll: $-).
financialYear monthsDo:
[ :aMonth |
    | workDays |
    aStream cr. aMonth printOn: aStream.
    aStream crtab; nextPutAll: aMonth weeks size printString; nextPutAll: ' weeks'.
    workDays := 0.
    aMonth workDatesDo: [ :d | workDays := workDays + 1 ].
    aStream crtab; nextPutAll: workDays printString; nextPutAll: ' work days'.
].
aStream flush.

Arbitrary Timespans

Some applications like law  enforcement may require timespans spanning many years.
jail  := Timespan starting: (Year year: 2000) start ending: (2010 asYear).
jail years.
jail yearsDo: [:y | Transcript cr; show: y asDate]
Other applications need to iterate over a timespan in unusual intervals. Consider the code necessary to inspect a timespan of one second every millisecond:
oneSecond := Timespan starting: DateAndTime now duration: (Duration seconds: 1).
millisecond := Duration nanoSeconds: 1000000.
x := 0.
oneSecond every: millisecond do: [ :t | x := x + 1 ].
x printString.
Sometimes it is useful to create a Timespan around a given DateAndTime:
aboutNow := Time now middleOf: (Duration hour).
leftThisWeek := Time now to: Week current end.

Schedules

It is often neccessary to schedule repeated events, like airline flight schedules, TV programmes, and file backups. Schedule is a Timespan which maintains an array of Durations. The durations specify the offset to the next scheduled DateAndTime. Consider a TV programme scheduled for 8:30pm every Saturday and Sunday for the current year.
"Find the first Saturday and set its time to 20h30"
sat := Year current asMonth dates detect: [ :d | d dayOfWeekName = #Saturday ].
sat := sat start + (Duration hours: 20.5).

"Create a schedule" 
shows := Schedule starting: sat ending: Year current end.
shows schedule: { 1 day. 6 days }.

"To inspect:"
shows dateAndTimes.
shows dateAndTimes collect: [ :dt | dt dayOfWeekName ].

Morphic

The implementation changeset includes changes to the MonthMorph and WeekMorph classes which are part of the base image. The reader should compare the changes with the existing code.

Implementation

The implementation of the DateAndTime class uses julian day numbers.

Testing

The Chonology archive on SqueakMap includes 382 SUnit test cases. In addition, all tests in ANSI test suite on SqueakMap succeed.

Status

This code is stable - I have been using it for over two years now. The code has also been extensively reviews by *Tom Koenig* for inclusion in 3.7.  

06 August 2001 - new changesets. Better filing into 3.1alpha.
07 June 2002 - introduced Schedule class.
06 December 2002 - fix changeset, new examples.
03 September 2003 - introduce Chronology.sar on SqueakMap.
11 September 2003 - bug fixes version 1.1
15 September 2003 - bug fixes and enhancements version 1.2
13 February 2004 - version 14. bug fixes for inclusion in 3.7

Installation

The latest release has been developed using the 3.7 alpha with most recent change set 5657.
 
  • Get a clean 3.7 image
  • Download Chronology Classes from SqueakMap.
  • Install.
  • You can now begin to explore the examples.
  • Download files



    Chronology_1_4.sar

    Thanks



    Other than the usual suspects on the Squeak mailing list, my thanks go to LeandroCaniglia who first introduced the Month and Week classes into the Squeak distribution which triggered the idea to reify timespans. Thanks also to Chris Muller for the terse duration methods on Number. Finally, thanks to Tom Koenig for all his assistance testing the current release.

    Contact



    Brent Pinkney