Date.st
author claus
Tue, 11 Apr 1995 16:52:00 +0200
changeset 326 d2902942491d
parent 275 a76029ddaa98
child 328 7b542c0bf1dd
permissions -rw-r--r--
*** empty log message ***

"
 COPYRIGHT (c) 1989 by Claus Gittinger
	      All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"

Magnitude subclass:#Date
       instanceVariableNames:'dateEncoding'
       classVariableNames:'DayNames MonthNames DayAbbrevs MonthAbbrevs
			   EnvironmentChange'
       poolDictionaries:''
       category:'Magnitude-General'
!

Date comment:'
COPYRIGHT (c) 1989 by Claus Gittinger
	      All Rights Reserved

$Header: /cvs/stx/stx/libbasic/Date.st,v 1.18 1995-04-11 14:49:00 claus Exp $
'!

!Date class methodsFor:'documentation'!

copyright
"
 COPYRIGHT (c) 1989 by Claus Gittinger
	      All Rights Reserved

 This software is furnished under a license and may be used
 only in accordance with the terms of that license and with the
 inclusion of the above copyright notice.   This software may not
 be provided or otherwise made available to, or used by, any
 other person.  No title to or ownership of the software is
 hereby transferred.
"
!

version
"
$Header: /cvs/stx/stx/libbasic/Date.st,v 1.18 1995-04-11 14:49:00 claus Exp $
"
!

documentation
"
    Instances of Date represent dates as year, month and day encoded in the 
    (private & hidden) instance dateEncoding. The value found there is 
    year*100*100 + month*100 + day (which makes magnitude-like comparison of 
    dates easy, but is not guaranteed for future versions).

    The old representation used days since 1st Jan. 1901 internally - 
    with the new implementation, it is possible to reasonably represent almost 
    any Date.  (which insurance companies will like, since they can now 
    represent even very old peoples birthday :-)
    Notice: no correction for pre-Julian dates is done.

    The printed representation of dates is controlled by resource definitions -
    thus national variants are already supported (see file 'resources/Date.rs').

    Compatibility notice:
	due to some historic reasons, there are some methods found twice
	with different names in this class. The old ST/X methods will vanish in
	one of the next releases, and kept for a while to support existing
	applications (the info on how these methods should be named came 
	somewhat late from the testers ..).

	Please do not use methods marked as obsolete in their comment.

    Most useful methods:

	Date today
	(Date today) addDays:
	(Date today) subtractDays:
"
! !

!Date class methodsFor:'private'!

initNames
    "read the language specific names"

    |resources|

    DayNames := #('monday'
		  'tuesday'
		  'wednesday'
		  'thursday'
		  'friday'
		  'saturday'
		  'sunday').

    DayAbbrevs := #('mon' 
		    'tue' 
		    'wed'
		    'thu' 
		    'fri' 
		    'sat' 
		    'sun').

    MonthNames := #('january'
		    'february'
		    'march'
		    'april'
		    'may'
		    'june'
		    'july'
		    'august'
		    'september'
		    'october'
		    'november'
		    'december').

    MonthAbbrevs := #('jan'
		      'feb'
		      'mar'
		      'apr'
		      'may'
		      'jun'
		      'jul'
		      'aug'
		      'sep'
		      'oct'
		      'nov'
		      'dec').

    "check for case where Resource-classes are absent"
    ResourcePack notNil ifTrue:[
	resources := ResourcePack for:self.

	DayNames := resources array:DayNames.
	DayAbbrevs := resources array:DayAbbrevs.
	MonthNames := resources array:MonthNames.
	MonthAbbrevs := resources array:MonthAbbrevs.
    ].

    EnvironmentChange := false

    "Date initNames"
!

daysInMonthIndex: monthIndex forYear: yearInteger
    "return the number of days in month monthIndex of
     year yearInteger (modified GNU).
     Return 0 for invalid month index.
     This is the internal version of daysInMonth:forYear:"

    |days|

    (monthIndex between:1 and:12) ifFalse:[^ 0].

    days := #(31 28 31           "Jan Feb Mar"
	      30 31 30           "Apr May Jun"
	      31 31 30           "Jul Aug Sep"
	      31 30 31           "Oct Nov Dec"
	     ) at: monthIndex.

    (monthIndex == 2) ifTrue:[
	(self leapYear:yearInteger) ifTrue:[
	    ^ days + 1
	]
    ].
    ^ days

    "
     Date daysInMonthIndex:2 forYear:1994
     Date daysInMonthIndex:2 forYear:1980
     Date daysInMonthIndex:2 forYear:1981
    "
! !

!Date class methodsFor:'handling language changes'!

initialize
"/    super initialize.

    "check for case where Resource-classes are absent"
    ResourcePack isNil ifTrue:[
	self initNames
    ] ifFalse:[
	Smalltalk addDependent:self.
	EnvironmentChange := true
    ]
!

update:something
    ((something == #Language) or:[something == #LanguageTerritory]) ifTrue:[
	"just remember change for next access"
	EnvironmentChange := true
    ]
! !

!Date class methodsFor:'general queries'!

dateAndTimeNow
    "return an array containing the date and time of now"

    ^ Time dateAndTimeNow

    "
     Date dateAndTimeNow
    "
!

dayOfWeek:dayName
    "given the name of a day (either string or symbol),
     return the day-index (1 for monday; 7 for sunday).
     Return 0 for invalid day name"

    EnvironmentChange ifTrue:[
	self initNames
    ].
    ^ DayNames indexOf:dayName

    "
     Date dayOfWeek:'wednesday'
    "
!

nameOfDay:dayIndex
    "given a day index (1..7), return the name of the day" 

    EnvironmentChange ifTrue:[
	self initNames
    ].
    ^ DayNames at:dayIndex

    "
     Date nameOfDay:4
    "
!

abbreviatedNameOfDay:dayIndex
    "given a day index (1..7), return the abbreviated name
     of the day"

    EnvironmentChange ifTrue:[
	self initNames
    ].
    ^ DayAbbrevs at:dayIndex

    "
     Date abbreviatedNameOfDay:4
    "
!

indexOfMonth:aMonthString
    "given the name of a month (either string or symbol),
     return the month-index (1 for jan; 12 for december).
     The given string may be a full or abbreviated name,
     case is ignored.
     Return 0 for invalid month name."

    |idx name|

    EnvironmentChange ifTrue:[
	self initNames
    ].
    name := aMonthString asLowercase.
    idx := MonthAbbrevs indexOf:name.
    idx ~~ 0 ifTrue:[^ idx].
    idx := MonthNames indexOf:name.
    idx ~~ 0 ifTrue:[^ idx].

    name at:1 put:(name at:1) asUppercase.
    idx := MonthAbbrevs indexOf:name.
    idx ~~ 0 ifTrue:[^ idx].
    idx := MonthNames indexOf:name.
    idx ~~ 0 ifTrue:[^ idx].

    ^ idx

    "
     Date indexOfMonth:'jan'
     Date indexOfMonth:'Jan'
     Date indexOfMonth:'December'
    "
!

nameOfMonth:monthIndex
    "given a month index (1..12), return the name of the month"

    EnvironmentChange ifTrue:[
	self initNames
    ].
    ^ MonthNames at:monthIndex

    "
     Date nameOfMonth:11
     Date nameOfMonth:12
     Date nameOfMonth:4
    "
!

abbreviatedNameOfMonth:monthIndex
    "given a month index (1..12), return the abbreviated name
     of the month"

    EnvironmentChange ifTrue:[
	self initNames
    ].
    ^ MonthAbbrevs at:monthIndex

    "
     Date abbreviatedNameOfMonth:11
     Date abbreviatedNameOfMonth:12
    "
!

daysInMonth:month forYear:yearInteger
    "given the name of a month and a year, return the number 
     of days this month has (modified GNU).
     return 0 if the month name was invalid.
     For your convenience, month maybe an integer or name-string."

    |monthIndex "{ Class: SmallInteger }"|

    month isInteger ifTrue:[
	monthIndex := month
    ] ifFalse:[
	monthIndex := self indexOfMonth:month
    ].

    ^ self daysInMonthIndex:monthIndex forYear:yearInteger

    "
     Date daysInMonth:2 forYear:1980
     Date daysInMonth:2 forYear:1981
     Date daysInMonth:'feb' forYear:1981
    "
!

daysUntilMonth:month forYear:yearInteger
    "given the name of a month and a year, return the number 
     of days from 1st january to last of prev month of that year.
     Return 0 if the month name/index is invalid or is january.
     For your convenience, month maybe an integer or name-string."

    |monthIndex "{ Class: SmallInteger }"
     sumDays    "{ Class: SmallInteger }" |

    month isInteger ifTrue:[
	monthIndex := month
    ] ifFalse:[
	monthIndex := self indexOfMonth:month
    ].
    (monthIndex between:1 and:12) ifFalse:[^ 0].

    sumDays := 0.
    1 to:monthIndex-1 do:[:m |
	sumDays := sumDays + (self daysInMonthIndex:m forYear:yearInteger)
    ].
    ^ sumDays

    "
     Date daysUntilMonth:'feb' forYear:1993
     Date daysUntilMonth:'jan' forYear:1993
    "
!

monthAndDayFromDayInYear:aDayInYear forYear:yearInteger
    "given a day-in-year (1..365) return an Array containing the
     month index and the day-in-month. Return nil if the argument is invalid."

    |restDays daysInMonth|

    restDays := aDayInYear.
    restDays < 1 ifTrue:[^ nil].

    1 to:12 do:[:m |
	daysInMonth := self daysInMonthIndex:m forYear:yearInteger.
	restDays <= daysInMonth ifTrue:[
	    ^ Array with:m with:restDays
	].
	restDays := restDays - daysInMonth 
    ].
    restDays > daysInMonth ifTrue:[^ nil].
    ^ Array with:12 with:restDays

    "
     Date monthAndDayFromDayInYear:66 forYear:1980
     Date monthAndDayFromDayInYear:66 forYear:1981
    "
! 

daysInYear:yearInteger
    "return the number of days in a year"

    (self leapYear:yearInteger) ifTrue:[^ 366].
    ^ 365

    "
     Date daysInYear:1900  
     Date daysInYear:1901 
     Date daysInYear:1904 
     Date daysInYear:1980 
     Date daysInYear:1981
    "
!

yearAsDays: yearInteger
    "Returns the number of days since Jan 1, 1901. (GNU)
     to the first Jan of the year, yearInteger.
     For 1901 this is zero, for 1902 its 365.
     Defined for years >= 1901"

    |y "{ Class: SmallInteger }"|

    y := yearInteger - 1900.
    y := y - 1.
    ^ (y * 365)
	+ (y // 4)
	- (y // 100)
	+ ((y + 300) // 400)

    "
     Date yearAsDays:1901 
     Date yearAsDays:1902   
     Date yearAsDays:1903   
     Date yearAsDays:1904    
     Date yearAsDays:1905     
     Date yearAsDays:1994   
     (Date yearAsDays:2001) - (Date yearAsDays:2000)   
    "
!

leapYear:yearInteger
    "return true, if yearInteger is a leap year."

    |y "{ Class: SmallInteger }"|

    y := yearInteger.
    (y \\ 4 == 0) ifTrue:[
	(y \\ 100 ~~ 0) ifTrue:[^ true].
	(y \\ 400 == 0) ifTrue:[^ true]
    ].
    ^ false

    "
     Date leapYear:1992
     Date leapYear:1994
     Date leapYear:1900
     Date leapYear:2000
    "
!

isLeapYear:yearInteger
    "Return true, if a year is a leap year.
     Obsolete:
	 Please use the ST-80 compatible #leapYear for new programs, 
	 since this method will vanish."

    ^ self leapYear:yearInteger
! !

!Date class methodsFor:'instance creation'!

fromOSTime:osTime
    "return a date, representing the date given by the operatingSystem time.
     This somewhat clumsy implementation hides the OS's date representation
     (i.e. makes this class independent of what the OS starts its time values with).
     Dont use this method, the osTime representation is totally unportable."

    ^ self basicNew fromOSTime:osTime

    "
     Date fromOSTime:#(0 0)      -> on UNIX: this should return 1st Jan 1970
				    thats where Unix time starts
				    On other systems, it may be something different.

     Date fromOSTime:#(86400 0)  -> on UNIX: the day after
    "
!

today
    "return a date, representing today"

    ^ self fromOSTime:OperatingSystem getTimeParts

    "
     Date today
    "
!

fromDays:dayCount
    "return a new Date, given the day-number starting with 0 at 1.Jan 1901;
     (i.e. 'Date fromDays:0' returns 1st Jan. 1901).
     Date asDays is the reverse operation.
     for GNU/ST-80 compatibility"

    |yr rest d|

    "approx. year"
    yr := (dayCount // 366) + 1901.
    rest := dayCount - (self yearAsDays:yr) + 1. "+1 for ST-80 compatibility"
    d := self daysInYear:yr.
    (rest > d) ifTrue:[
	"adjust"
	yr := yr + 1.
	rest := rest - d.
    ].

    ^ self day:rest year:yr

    "
     Date fromDays:0     -> 1 jan 1901
     Date fromDays:365   -> 1 jan 1902
     Date fromDays:730   -> 1 jan 1903
     Date fromDays:1095  -> 1 jan 1903
     Date fromDays:1460  ->31 dec 1904 since 1904 was a leap year
    "
!

day:dayInYear year:year
    "return a new Date, given the year and the day-in-year (starting at 1).
     Obsolete:
	use newDay:year: for ST-80 compatibility"

    ^ self newDay:dayInYear year:year
!

newDay:dayInYear year:year
    "return a new Date, given the year and the day-in-year (starting at 1).
     ST-80 compatibility"

    |monthAndDay|

    (dayInYear between:1 and:365) ifFalse:[
	((dayInYear == 366) and:[self leapYear:year]) ifFalse:[
	    "
	     this error is triggered, when you try to create a
	     day from an invalid day-in-year; 
	     for example, 366 in a non-leap year.
	     I dont know, if ST-80 wraps to the next year(s) in this case.
	    "
	    ^ self error:'invalid date'
	]
    ].
    monthAndDay := self monthAndDayFromDayInYear:dayInYear forYear:year.
    ^ self day:(monthAndDay at:2) month:(monthAndDay at:1) year:year

    "
     Date newDay:150 year:1994
     Date newDay:1 year:1994
     Date newDay:1 year:1901
     Date newDay:1 year:1902
     Date newDay:365 year:1992
     Date newDay:366 year:1992
     Date newDay:365 year:1994
     Date newDay:366 year:1994
    "
!

day:day month:month year:year
    "return a new Date, given the day, month and year.
     Obsolete:
	use newDay:month:year: for ST-80 compatibility"

    ^ self newDay:day month:month year:year
!

newDay:day month:month year:year
    "return a new Date, given the day, month and year.
     For your convenience, month may be either an integer 
     or the months name as a string. 
     Year may be the actual year (such as 1890, 2001) or the number 
     of years since 1900 (which is rubbish ST-80 compatibility: 
     it will be totally useless in a few years ...).
     You better not use this short-year feature in your programs."

    |monthIndex ok yr|

    yr := year.
    yr < 100 ifTrue:[
	yr := yr + 1900.
    ].

    month isInteger ifTrue:[
	monthIndex := month
    ] ifFalse:[
	monthIndex := self indexOfMonth:month
    ].
    (monthIndex == 2 and:[day == 29]) ifTrue:[
	ok := self leapYear:yr
    ] ifFalse:[
	ok := day <= (self daysInMonth:month forYear:yr)
    ].
    ((day > 0) and:[ok]) ifTrue:[
	^ self basicNew dateEncoding:(((yr * 100) + monthIndex) * 100) + day
    ].

    "this error is triggered if you try to create a date from an
     invalid year/month/day combination;
     Such as 29-feb-year, where year is no leap year
    "
    self error:'invalid date'

    "
     Date newDay:8  month:'may' year:1993
     Date newDay:8  month:5     year:1994
     Date newDay:29 month:'feb' year:1994
     Date newDay:29 month:'feb' year:1993
     Date newDay:28 month:'feb' year:5
     Date newDay:28 month:'feb' year:95
    "
!

readFromString:aString onError:exceptionBlock
    "return a new Date, reading a printed representation from aStream.
     Notice, that this is not the storeString format and 
     is different from the format expected by readFrom:.
     BUG:
       This method assumes american format (i.e. month-day-year) instead
       of the german/french and other day-month-year.
       There ought to be a nationalized variant of this."
    
    |month day year aStream|

    aStream := ReadStream on:aString.
    [aStream peek isLetterOrDigit] whileFalse:[aStream next].
    (aStream peek isDigit) ifTrue:[
	day := Integer readFrom:aStream onError:[^ exceptionBlock value]
    ].
    [aStream peek isLetterOrDigit] whileFalse:[aStream next].
    (aStream peek isLetter) ifTrue:[
	month := aStream nextAlphaNumericWord.
	day isNil ifTrue:[
	    [aStream peek isLetterOrDigit] whileFalse:[aStream next].
	    day := Integer readFrom:aStream onError:[^ exceptionBlock value].
	]
    ] ifFalse:[
	month := self nameOfMonth:day.
	day := Integer readFrom:aStream onError:[^ exceptionBlock value]
    ].
    [aStream peek isLetterOrDigit] whileFalse:[aStream next].
    year := Integer readFrom:aStream onError:[^ exceptionBlock value].
    ^ self newDay:day month:month year:year

    "
     Date readFromString:'31 December 1992'  
     Date readFromString:'December, 5, 1992'  
     Date readFromString:'December, 5 1992'  
     Date readFromString:'3-jan-95'           
     Date readFromString:'12/31/1992'        
     Date readFromString:'15.4.1992'         -> german; leads to an error
     Date readFromString:'10.4.1992'         -> german; leads to a wrong date
     Date readFromString:'10.4.1992' onError:['wrong date']
    "
! !

!Date class methodsFor:'private encoding'!

encodeYear:y month:m day:d
    "the internal encoding is stricktly private, 
     and should not be used outside."

    ^ (((y * 100) + m) * 100) + d
! !

!Date methodsFor:'private accessing'!

dateEncoding
    "the internal encoding is stricktly private, 
     and should not be used outside."

    ^ dateEncoding
!

dateEncoding:anInteger
    "the internal encoding is stricktly private, 
     and should not be used outside."

    dateEncoding := anInteger
!

fromOSTime:osTime
    "set my dateEncoding from an OS time.
     This somewhat clumsy implementation hides the OS's date representation
     (i.e. makes this class independent of what the OS starts its time values with).
     Dont use this method, the osTime representation is totally unportable."

    OperatingSystem computeDatePartsOf:osTime 
				   for:[:year :month :day |
	dateEncoding := (((year * 100) + month) * 100) + day
    ]
! !

!Date methodsFor:'arithmetic'!

plusDays:days
    "return a new date representing 'days' after the receiver.
     The argument should be some kind of integer.
     Obsolete:
	 Please dont use this method since it will vanish.
	 Use #addDays: instead for ST-80 compatibility."

    ^ self addDays:days
!

addDays:days
    "return a new date representing 'days' after the receiver.
     The argument should be some kind of integer.
     For ST-80 compatibility."

    ^ self class fromDays:(self asDays + days)

    "
     Date today addDays:7
    "
!

minusDays:days
    "return a new date representing 'days' before the receiver.
     The argument should be some kind of integer.
     Obsolete:
	 Please dont use this method since it will vanish.
	 Use #subtractDays: instead for ST-80 compatibility."

    ^ self subtractDays:days
!

subtractDays:days
    "return a new date representing 'days' before the receiver.
     The argument should be some kind of integer.
     For ST-80 compatibility"

    ^ self class fromDays:(self asDays - days)

    "
     Date today subtractDays:7
    "
!

subtractDate:aDate
    "return the number of days between the receiver and aDate"

    ^ self asDays - aDate asDays

    "
    (Date day:1 month:1 year:1995) subtractDate:(Date day:24 month:12 year:1994)
    (Date day:1 month:3 year:1992) subtractDate:(Date day:1 month:2 year:1992)
    (Date day:1 month:3 year:1994) subtractDate:(Date day:1 month:2 year:1994)
    "
!

daysUntil:aDate
    "return the number of days between the receiver and the argument,
     aDate, whuch should be some kind of date"

    ^ aDate asDays - self asDays

    "
     (Date day:24 month:12 year:1994) daysUntil:(Date day:1 month:1 year:1995)
     (Date day:1 month:2 year:1992) daysUntil:(Date day:1 month:3 year:1992)
     (Date day:1 month:2 year:1994) daysUntil:(Date day:1 month:3 year:1994)
    
     |delta|
     delta := Date today
		daysUntil:(Date day:25 month:12 year:Date today year).
     Transcript show:'still ';
		show:delta ;
		showCr:' days till xmas'
    "
! !
    
!Date methodsFor:'accessing'!

day
    "return the day (1..31) of the receiver"

    ^ dateEncoding \\ 100

    "
     Date today day
    "
!

month
    "return the month (1..12) of the receiver"

    ^ (dateEncoding // 100) \\ 100

    "
     Date today month
    "
!

year
    "return the year (1..12) of the receiver"

    ^ dateEncoding // (100*100)

    "
     Date today year
    "
!

leap
    "return true, if the receivers year is a leap year"

    ^ Date leapYear:(self year)

    "
     Date today leap
     (Date day:1 month:1 year:1992) leap
    "
!

dayCount
    "return the number of days since 1st. Jan. 1901;
     starting with 0 for this date.
     Date>>fromDays: is the reverse operation.
     Obsolete:
	 please use asDays for ST-80 compatibility"

    ^ self asDays.

    "
     (Date day:1 month:1 year:1901) dayCount
     Date fromDays:(Date day:1 month:1 year:1994) dayCount
     Date today dayCount
    "
!

asDays
    "return the number of days elapsed since 01-Jan-1901
     and the receiver's day; starts with 0 for 1-1-1901.
     Date>>fromDays: is the reverse operation.
     For ST-80 compatibility."

    |yr|

    yr := self year.
    ^ (self class yearAsDays:yr)
      + (self class daysUntilMonth:self month forYear:yr)
      + self day
      - 1

    "
     (Date day: 5 month: 8 year: 1962) asDays  -> should be 22496
     (Date day: 1 month: 1 year: 1901) asDays  -> 0
     Date today asDays
     Date fromDays:(Date today asDays + 7)
    "
!

asSeconds
    "return the seconds between 1.jan.1901 and the same time in the receivers 
     day. (i.e. midnight to midnight).
     ST-80 compatibility."

    ^ 60*60*24 * self asDays

    "
     (Date day: 5 month: 8 year: 1962) asSeconds
     (Date day: 1 month: 1 year: 1901) asSeconds
     (Date today addDays:7) asSeconds - Date today asSeconds
    "  
! 

dayOfMonth
    "Answer the day of the month represented by me.
     Same as day; for ST-80 compatibility."

    ^ self day

    "
     Date today dayOfMonth
    "
!

daysInMonth
    "return the number of days in the month of the receiver"

    ^ Date daysInMonth:(self month) forYear:(self year)

    "
     Date today daysInMonth
    "
!

daysInYear
    "return the number of days in the year of the receiver"

    ^ Date daysInYear:(self year)

    "
     Date today daysInYear
    "
!

daysLeftInYear
    "return the number of days left in the year of the receiver"

    ^ Date daysInYear:(self year) - self day

    "
     Date today daysLeftInYear
    "
!

dayInWeek
    "return the week-day of the receiver - 1 for monday, 7 for sunday"

    ^ (1 "know, that 1st Jan 1901 was a tuesday"
      + self asDays) \\ 7 + 1

    "
     Date today dayInWeek
     (Date day:15 month:4 year:1959) dayInWeek
    "
!

dayName
    "return the week-day of the receiver as a string.
     The returned string depends on the language setting.
     Expect things like 'monday', 'tuesday' ...
     Obsolete:
	use #weekday for ST-80 compatibility"

    ^ self weekday
!

weekday
    "return the week-day of the receiver as a string.
     The returned string depends on the language setting.
     Expect things like 'monday', 'tuesday' ...
     For ST-80 compatibility"

    ^ self class nameOfDay:(self dayInWeek)

    "
     Date today weekday
     (Date day:15 month:4 year:1959) weekday
    "
!

abbreviatedDayName
    "return the short week-day of the receiver as a string.
     The returned string depends on the language setting.
     Expect things like 'mon', 'tue' ..."

    ^ self class abbreviatedNameOfDay:(self dayInWeek)

    "
     Date today abbreviatedDayName
     (Date day:15 month:4 year:1959) abbreviatedDayName
    "
!

monthIndex
    "return the index of the month (e.g. Feb.=2).
     Same as month; for ST-80 compatibility."

    ^ self month  
!

monthName
    "return the month of the receiver as a string.
     The returned string depends on the language setting.
     Expect things like 'january', 'february' ..."

    ^ self class nameOfMonth:(self month)

    "
     Date today monthName
     (Date day:15 month:4 year:1959) monthName
    "
!

abbreviatedMonthName
    "return the month of the receiver as a string.
     The returned string depends on the language setting.
     Expect things like 'jan', 'feb' ..."

    ^ self class abbreviatedNameOfMonth:(self month)

    "
     Date today abbreviatedMonthName
     (Date day:15 month:4 year:1959) abbreviatedMonthName
    "
! !

!Date methodsFor:'comparing'!

< aDate
    "return true, if the date represented by the receiver
     is before the argument, aDate"

    (aDate isMemberOf:Date) ifTrue:[
	^ dateEncoding < aDate dateEncoding
    ].

    "the argument must understand year, month and day to be
     comparable, whatever it is"

    ^ dateEncoding < (Date encodeYear:aDate year
				month:aDate month
				  day:aDate day)

    "Date today < (Date day:24 month:12 year:2000)"
    "Date today < (Date day:24 month:12 year:1900)"
!

> aDate
    "return true, if the date represented by the receiver
     is after the argument, aDate"

    (aDate isMemberOf:Date) ifTrue:[
	^ dateEncoding > aDate dateEncoding
    ].

    "the argument must understand year, month and day to be
     comparable, whatever it is"

    ^ dateEncoding > (Date encodeYear:aDate year
				month:aDate month
				  day:aDate day)

    "Date today > (Date day:24 month:12 year:2000)"
    "Date today > (Date day:24 month:12 year:1900)"
!

= aDate
    "return true, if the date represented by the receiver
     is the same as the one represented by argument, aDate"

    (aDate isMemberOf:Date) ifFalse:[^ false].

    ^ dateEncoding = aDate dateEncoding

    "the argument must understand year, month and day to be
     comparable, whatever it is"

"
    ^ dateEncoding = (Date encodeYear:aDate year
				month:aDate month
				  day:aDate day)
"
    "Date today = ((Date today plusDays:7) minusDays:7)"
!

hash
    "return an integer useful for hashing on dates"

    ^ dateEncoding
! !

!Date methodsFor:'printing & storing'!

storeOn:aStream
    "append a representation to aStream, from which the receiver
     can be reconstructed"

    aStream nextPutAll:'('.
    aStream nextPutAll:'Date day:'.
    self day printOn:aStream.
    aStream nextPutAll:' month:'.
    self month printOn:aStream.
    aStream nextPutAll:' year:'.
    self year printOn:aStream.
    aStream nextPutAll:')'

    "Date today storeOn:Transcript"
!

printOn:aStream
    "append a printed representation of the receiver to aStream"

    self day printOn:aStream.
    aStream nextPutAll:'-'.
    (Date abbreviatedNameOfMonth:self month) printOn:aStream.
    aStream nextPutAll:'-'.
    self year printOn:aStream

    "Date today printOn:Transcript"
    "Date today printNL"
! !