'From Pharo2.0a of ''18 April 2012'' [Latest update: #20216] on 16 July 2012 at 7:12:38 pm'! DateAndTime instVarNames at: 3 put: #julianDayNumber. Magnitude subclass: #DateAndTime instanceVariableNames: 'seconds offset julianDayNumber nanos ' classVariableNames: 'ClockProvider DaysSinceEpoch LastMilliSeconds LastTick LastTickSemaphore LocalTimeZone MilliSecondOffset OffsetsAreValid ' poolDictionaries: 'ChronologyConstants' category: 'Kernel-Chronology'! 'From Pharo2.0a of ''18 April 2012'' [Latest update: #20216] on 16 July 2012 at 7:33 pm'! !Duration methodsFor: 'arithmetic' stamp: 'GuillermoPolito 8/24/2010 11:15'! * operand "operand is a Number" ^ self class nanoSeconds: ( (self asNanoSeconds * operand) asInteger) ! ! !Duration methodsFor: 'arithmetic' stamp: 'GuillermoPolito 8/24/2010 11:15'! + operand "operand is a Duration" ^ self class nanoSeconds: (self asNanoSeconds + operand asNanoSeconds) ! ! !Duration methodsFor: 'arithmetic' stamp: 'GuillermoPolito 8/24/2010 11:15'! - operand "operand is a Duration" ^ self + operand negated ! ! !Duration methodsFor: 'arithmetic' stamp: 'sd 3/16/2008 15:36'! / operand "operand is a Duration or a Number" ^ operand isNumber ifTrue: [ self class nanoSeconds: (self asNanoSeconds / operand) asInteger ] ifFalse: [ self asNanoSeconds / operand asDuration asNanoSeconds ] ! ! !Duration methodsFor: 'arithmetic' stamp: 'brp 5/13/2003 08:00'! < comparand ^ self asNanoSeconds < comparand asNanoSeconds ! ! !Duration methodsFor: 'arithmetic' stamp: 'brp 1/9/2004 06:25'! = comparand "Answer whether the argument is a representing the same period of time as the receiver." ^ self == comparand ifTrue: [true] ifFalse: [self species = comparand species ifTrue: [self asNanoSeconds = comparand asNanoSeconds] ifFalse: [false] ]! ! !Duration methodsFor: 'accessing' stamp: 'brp 5/13/2003 08:01'! abs ^ self class seconds: seconds abs nanoSeconds: nanos abs ! ! !Duration methodsFor: 'accessing' stamp: 'GuillermoPolito 8/24/2010 11:22'! days "Answer a number that represents the number of complete days in the receiver" ^ seconds quo: SecondsInDay ! ! !Duration methodsFor: 'accessing' stamp: 'GuillermoPolito 8/24/2010 11:14'! hash ^seconds bitXor: nanos ! ! !Duration methodsFor: 'accessing' stamp: 'GuillermoPolito 8/24/2010 11:21'! hours "Answer a number that represents the number of complete hours in the receiver, after the number of complete days has been removed." ^ (seconds rem: SecondsInDay) quo: SecondsInHour ! ! !Duration methodsFor: 'accessing' stamp: 'GuillermoPolito 8/24/2010 11:22'! minutes "Answer a number that represents the number of complete minutes in the receiver, after the number of complete hours has been removed." ^ (seconds rem: SecondsInHour) quo: SecondsInMinute ! ! !Duration methodsFor: 'accessing' stamp: 'brp 5/13/2003 08:02'! negated ^ self class seconds: seconds negated nanoSeconds: nanos negated ! ! !Duration methodsFor: 'accessing' stamp: 'brp 5/13/2003 08:02'! negative ^ self positive not ! ! !Duration methodsFor: 'accessing' stamp: 'brp 5/13/2003 08:02'! positive ^ seconds = 0 ifTrue: [ nanos positive ] ifFalse: [ seconds positive ] ! ! !Duration methodsFor: 'accessing' stamp: 'GuillermoPolito 8/24/2010 11:23'! seconds "Answer a number that represents the number of complete seconds in the receiver, after the number of complete minutes has been removed." ^ (seconds rem: SecondsInMinute)! ! !Number methodsFor: 'arithmetic' stamp: 'CamilloBruni 7/13/2012 19:09'! quo: aNumber "Integer quotient defined by division with truncation toward zero. -9 quo: 4 = -2. -0.9 quo: 0.4 = -2. rem: answers the remainder from this division." ^(self / aNumber) truncated! ! !Number methodsFor: 'mathematical functions' stamp: 'CamilloBruni 7/13/2012 17:37'! % aNumber "modulo. Remainder defined in terms of //. Answer a Number with the same sign as aNumber. e.g. 9\\4 = 1, -9\\4 = 3, 9\\-4 = -3, 0.9\\0.4 = 0.1." ^ self \\ aNumber! ! !DateAndTimeTest methodsFor: 'tests' stamp: 'CamilloBruni 7/13/2012 17:24'! testCreationWithOffsets | dt1 dt2 | dt1 := (DateAndTime year: 2222 month: 1 day: 22 hour: 1 minute: 22 second: 33 offset: 0 hours). dt2 := (DateAndTime year: 2222 month: 1 day: 22 hour: 1 minute: 22 second: 33 offset: 2 hours). "The timepoints are diffferent, AKA their UTC times don't correspond" self deny: dt1 = dt2. "The relative components however are equal" self assert: dt1 year equals: dt2 year. self assert: dt1 month equals: dt2 month. self assert: dt1 day equals: dt2 day. self assert: dt1 hours equals: dt2 hours. self assert: dt1 minutes equals: dt2 minutes. self assert: dt1 seconds equals: dt2 seconds.! ! !DateAndTimeTest methodsFor: 'tests' stamp: 'CamilloBruni 7/13/2012 16:36'! testDateTimeDenotation1 "DateAndTimeTest new testDateTimeDenotation1" "Detroit is 5 hours behind UTC, this offset to UTC is therefore written with a minus sign. This example tests the correct interpretation of the DateAndTime denotation. " | twoPmInLondon twoPmUTCInLocalTimeOfDetroit nineAmInDetroit | twoPmInLondon := DateAndTime year: 2004 month: 11 day: 2 hour: 14 minute: 0 second: 0 offset: 0 hours. twoPmUTCInLocalTimeOfDetroit := twoPmInLondon offset: -5 hours. nineAmInDetroit := '2004-11-02T09:00:00-05:00' asDateAndTime. self assert: twoPmUTCInLocalTimeOfDetroit = nineAmInDetroit. ! ! !DateAndTimeTest methodsFor: 'tests' stamp: 'CamilloBruni 7/13/2012 16:36'! testDateTimeDenotation2 "DateAndTimeTest new testDateTimeDenotation2" "Moscow is 3 hours ahead UTC, this offset to UTC is therefore positive. This example tests the correct interpretation of the DateAndTime denotation." | lateEveningInLondon lateEveningInLocalTimeOfMoscow localMoscowTimeFromDenotation | lateEveningInLondon := DateAndTime year: 2004 month: 11 day: 30 hour: 23 minute: 30 second: 0 offset: 0 hours. lateEveningInLocalTimeOfMoscow := lateEveningInLondon offset: 3 hours. localMoscowTimeFromDenotation := '2004-12-01T02:30:00+03:00' asDateAndTime. self assert: lateEveningInLocalTimeOfMoscow = localMoscowTimeFromDenotation.! ! !DateAndTimeTest methodsFor: 'tests' stamp: 'CamilloBruni 7/13/2012 19:56'! testReadFrom self assert: '-1199-01-05T20:33:14.321-05:00' asDateAndTime printString equals: '-1199-01-05T20:33:14.321-05:00'. self assert: '2002-05-16T17:20:45.1+01:01' asDateAndTime printString equals: '2002-05-16T17:20:45.1+01:01'. self assert: ' 2002-05-16T17:20:45.02+01:01' asDateAndTime printString equals: '2002-05-16T17:20:45.02+01:01'. self assert: '2002-05-16T17:20:45.000000009+01:01' asDateAndTime printString equals: '2002-05-16T17:20:45.000000009+01:01'. self assert: ' 2002-05-16T17:20' asDateAndTime translateToUTC printString equals: '2002-05-16T17:20:00+00:00'. self assert: '2002-05-16T17:20:45' asDateAndTime translateToUTC printString equals: '2002-05-16T17:20:45+00:00' . self assert: ' 2002-05-16T17:20:45+01:57' asDateAndTime printString equals: '2002-05-16T17:20:45+01:57'. self assert: ' 2002-05-16T17:20:45-02:34' asDateAndTime equals: '2002-05-16T17:20:45-02:34' asDateAndTime. self assert: '2002-05-16T17:20:45+00:00' asDateAndTime equals: '2002-05-16T17:20:45+00:00' asDateAndTime. self assert: '1997-04-26T01:02:03+01:02:3' asDateAndTime equals: '1997-04-26T01:02:03+01:02:3' asDateAndTime! ! !DateAndTimeTest methodsFor: 'tests' stamp: 'CamilloBruni 7/13/2012 16:33'! testSecondsRoundTrip | now now2 | now := DateAndTime fromSeconds: 0. now2 := DateAndTime fromSeconds: now asSeconds. self assert: now equals: now2.! ! !DateAndTimeTest methodsFor: 'tests' stamp: 'CamilloBruni 7/13/2012 16:36'! testTimeZoneEquivalence2 "DateAndTimeTest new testTimeZoneEquivalence2" "This example demonstates the fact that 2004-05-24T22:40:00 UTC is 2004-05-25T01:40:00 in Moscow (Moscow is 3 hours ahead of UTC) " | thisMoment thisMomentInMoscow | thisMoment := DateAndTime year: 2004 month: 5 day: 24 hour: 22 minute: 40. thisMomentInMoscow := thisMoment offset: 3 hours. self assert: (thisMoment - thisMomentInMoscow) asSeconds = 0. self assert: thisMoment = thisMomentInMoscow ! ! !DateAndTimeTest methodsFor: 'tests - under design' stamp: 'CamilloBruni 7/13/2012 20:02'! testReadFromSecond "self debug: #testReadFromSecond" self assert: ('-1199-01-05T20:33:14.321-05:00' asDateAndTime printString = '-1199-01-05T20:33:14.321-05:00'). self assert: ('2002-05-16T17:20:45.1+01:01' asDateAndTime printString = '2002-05-16T17:20:45.1+01:01'). self assert: (' 2002-05-16T17:20:45.02+01:01' asDateAndTime printString = '2002-05-16T17:20:45.02+01:01'). self assert: ('2002-05-16T17:20:45.000000009+01:01' asDateAndTime printString = '2002-05-16T17:20:45.000000009+01:01'). self assert: (' 2002-05-16T17:20' asDateAndTime translateToUTC printString = '2002-05-16T17:20:00+00:00'). self assert: ('2002-05-16T17:20:45' asDateAndTime translateToUTC printString = '2002-05-16T17:20:45+00:00' ). self assert: (' 2002-05-16T17:20:45+01:57' asDateAndTime printString = '2002-05-16T17:20:45+01:57'). self assert: (' 2002-05-16T17:20:45-02:34' asDateAndTime printString = '2002-05-16T17:20:45-02:34'). self assert: ('2002-05-16T17:20:45+00:00' asDateAndTime printString = '2002-05-16T17:20:45+00:00'). self assert: ('1997-04-26T01:02:03+01:02:3' asDateAndTime printString = '1997-04-26T01:02:03+01:02:3'). ! ! !DateAndTime methodsFor: '*Fuel' stamp: 'CamilloBruni 3/30/2032 18:26'! fuelSet: julianDay nanoSecond: nanoSeconds seconds: numberOfSeconds offset: anOffset julianDayNumber := julianDay. nanos := nanoSeconds. seconds := numberOfSeconds. offset := anOffset.! ! !DateAndTime methodsFor: 'accessing' stamp: 'sd 3/16/2008 15:04'! dayOfMonth "Answer which day of the month is represented by the receiver." ^ self dayMonthYearDo: [ :d :m :y | d ]! ! !DateAndTime methodsFor: 'accessing' stamp: 'CamilloBruni 3/30/2032 18:26'! dayOfWeek "Sunday=1, ... , Saturday=7" ^ (julianDayNumber + 1 rem: 7) + 1! ! !DateAndTime methodsFor: 'accessing' stamp: 'sd 3/16/2008 15:04'! dayOfWeekAbbreviation ^ self dayOfWeekName copyFrom: 1 to: 3! ! !DateAndTime methodsFor: 'accessing' stamp: 'sd 3/16/2008 15:04'! dayOfWeekName ^ Week nameOfDay: self dayOfWeek ! ! !DateAndTime methodsFor: 'accessing' stamp: 'nice 1/5/2010 15:59'! dayOfYear "This code was contributed by Dan Ingalls. It is equivalent to the terser ^ jdn - (Year year: self year) start julianDayNumber + 1 but much quicker." ^ self dayMonthYearDo: [ :d :m :y | | monthStart | monthStart := #(1 32 60 91 121 152 182 213 244 274 305 335) at: m. (m > 2 and: [ Year isLeapYear: y ]) ifTrue: [ monthStart + d ] ifFalse: [ monthStart + d - 1 ]]! ! !DateAndTime methodsFor: 'accessing' stamp: 'sd 3/16/2008 15:04'! hour ^ self hour24 ! ! !DateAndTime methodsFor: 'accessing' stamp: 'sd 3/16/2008 15:05'! hour12 "Answer an between 1 and 12, inclusive, representing the hour of the day in the 12-hour clock of the local time of the receiver." ^ self hour24 - 1 \\ 12 + 1! ! !DateAndTime methodsFor: 'accessing' stamp: 'CamilloBruni 7/13/2012 19:09'! hour24 "Answer a number that represents the number of complete hours in the receiver's time part, after the number of complete days has been removed." ^ ((self localSeconds rem: SecondsInDay) / SecondsInHour) floor % 24! ! !DateAndTime methodsFor: 'accessing' stamp: 'sd 3/16/2008 15:05'! isLeapYear ^ Year isLeapYear: self year. ! ! !DateAndTime methodsFor: 'accessing' stamp: 'CamilloBruni 7/12/2012 18:52'! julianDayNumber ^ julianDayNumber + self julianDayOffset! ! !DateAndTime methodsFor: 'accessing' stamp: 'CamilloBruni 7/13/2012 18:58'! julianDayOffset "Return the offset in julian days possibly introduced by the timezone offset" ^ ((seconds + self offset asSeconds) / SecondsInDay) floor! ! !DateAndTime methodsFor: 'accessing' stamp: 'CamilloBruni 7/13/2012 19:01'! localSeconds " Return the seconds since the epoch in local time." ^ seconds + self offset asSeconds! ! !DateAndTime methodsFor: 'accessing' stamp: 'sd 3/16/2008 15:05'! meridianAbbreviation ^ self asTime meridianAbbreviation! ! !DateAndTime methodsFor: 'accessing' stamp: 'CamilloBruni 7/13/2012 19:10'! minute "Answer a number that represents the number of complete minutes in the receiver' time part, after the number of complete hours has been removed." ^ ((self localSeconds rem: SecondsInHour) / SecondsInMinute) floor % 60! ! !DateAndTime methodsFor: 'accessing' stamp: 'sd 3/16/2008 15:05'! month ^ self dayMonthYearDo: [ :d :m :y | m ].! ! !DateAndTime methodsFor: 'accessing' stamp: 'sd 3/16/2008 15:05'! monthAbbreviation ^ self monthName copyFrom: 1 to: 3 ! ! !DateAndTime methodsFor: 'accessing' stamp: 'sd 3/16/2008 15:05'! monthName ^ Month nameOfMonth: self month ! ! !DateAndTime methodsFor: 'accessing' stamp: 'sd 3/16/2008 15:06'! offset ^ offset ! ! !DateAndTime methodsFor: 'accessing' stamp: 'sd 3/16/2008 15:06'! offset: anOffset "Answer a equivalent to the receiver but with its local time being offset from UTC by offset." ^ self class basicNew ticks: self ticks offset: anOffset asDuration; yourself ! ! !DateAndTime methodsFor: 'accessing' stamp: 'CamilloBruni 7/13/2012 19:02'! second "Answer a number that represents the number of complete seconds in the receiver's time part, after the number of complete minutes has been removed." ^ (self localSeconds rem: SecondsInMinute) % 60! ! !DateAndTime methodsFor: 'accessing' stamp: 'CamilloBruni 7/13/2012 16:44'! timeZone ^ TimeZone offset: self offset! ! !DateAndTime methodsFor: 'accessing' stamp: 'CamilloBruni 7/13/2012 16:43'! timeZoneAbbreviation ^ self timeZone abbreviation ! ! !DateAndTime methodsFor: 'accessing' stamp: 'CamilloBruni 7/13/2012 16:43'! timeZoneName ^ self timeZone name ! ! !DateAndTime methodsFor: 'accessing' stamp: 'sd 3/16/2008 15:06'! year ^ self dayMonthYearDo: [:d :m :y | y ]! ! !DateAndTime methodsFor: 'converting' stamp: 'CamilloBruni 7/13/2012 19:26'! asDuration "Answer the duration since midnight." ^ Duration seconds: self localSeconds nanoSeconds: nanos ! ! !DateAndTime methodsFor: 'converting' stamp: 'CamilloBruni 7/13/2012 16:35'! asLocal ^ (self offset = self class localOffset) ifTrue: [self] ifFalse: [self offset: self class localOffset] ! ! !DateAndTime methodsFor: 'converting' stamp: 'CamilloBruni 7/13/2012 17:15'! asSeconds "Return the number of seconds since the Squeak epoch" ^ (self - (self class epoch)) asSeconds! ! !DateAndTime methodsFor: 'converting' stamp: 'CamilloBruni 7/13/2012 19:26'! asTime ^ Time seconds: self localSeconds nanoSeconds: nanos! ! !DateAndTime methodsFor: 'converting' stamp: 'CamilloBruni 7/13/2012 19:57'! asUTC ^ offset isZero ifTrue: [ self ] ifFalse: [ self offset: 0 ] ! ! !DateAndTime methodsFor: 'enumerating' stamp: 'CamilloBruni 7/13/2012 18:32'! dayMonthYearDo: aBlock "Return the value of executing block with the Gregorian Calender day, month and year as arguments, as computed from my Julian Day Number, julianDayNumber. See http://en.wikipedia.org/wiki/Julian_date#Gregorian_calendar_from_Julian_day_number A short Description for the Constants used below: - 400 years span 146097 days in gregorian calendar. - 100 years span 36524 days, except every 400 years. - 4 years span 1461 days, except every 100 years. - 1 year spans 365 days, except every four years " | l n i j monthDay month fullYear | l := self julianDayNumber + 68569. n := 4 * l // 146097. l := l - (146097 * n + 3 // 4). i := 4000 * (l + 1) // 1461001. l := l - (1461 * i // 4) + 31. j := 80 * l // 2447. monthDay := l - (2447 * j // 80). l := j // 11. month := j + 2 - (12 * l). fullYear := 100 * (n - 49) + i + l. ^ aBlock value: monthDay value: month value: fullYear.! ! !DateAndTime methodsFor: 'maintime' stamp: 'CamilloBruni 7/13/2012 20:43'! midnight "Answer a DateAndTime starting at midnight local time" self dayMonthYearDo: [ :day :month :year| ^self class year: year month: month day: day offset: offset ].! ! !DateAndTime methodsFor: 'offset' stamp: 'CamilloBruni 7/13/2012 21:07'! translateTo: anOffset "Keep myself's representation and move it to another timezone offset. Note that unlike #offset: this will change the absolute time in utc |t| t := DateAndTime now. t = (t offset: 2 hours). t = (t translateTo: 2 hours). " self dayMonthYearDo: [ :day :month :year| ^ self class year: year month: month day: day hour: self hour minute: self minute second: self second nanoSecond: self nanoSecond offset: anOffset asDuration ]! ! !DateAndTime methodsFor: 'offset' stamp: 'CamilloBruni 7/13/2012 19:52'! translateToUTC " Move this reprsenation to UTC" ^ self translateTo: 0 asDuration ! ! !DateAndTime methodsFor: 'offset' stamp: 'CamilloBruni 7/13/2012 16:37'! utcOffset: anOffset self deprecated: 'Use offset: instead' on: '7/13/2012 16:36' in: 'Pharo 2.0'. ^ self offset: anOffset! ! !DateAndTime methodsFor: 'offset' stamp: 'CamilloBruni 7/13/2012 16:37'! withoutOffset ^ self offset: 0 ! ! !DateAndTime methodsFor: 'private' stamp: 'CamilloBruni 3/30/2032 18:26'! hasEqualTicks: aDateAndTime ^ (julianDayNumber = aDateAndTime julianDayNumber) and: [ (seconds = aDateAndTime secondsSinceMidnight) and: [ nanos = aDateAndTime nanoSecond ] ] ! ! !DateAndTime methodsFor: 'private' stamp: 'CamilloBruni 3/30/2032 18:26'! hash | totalSeconds | totalSeconds := seconds - offset asSeconds. ^ ((totalSeconds // 86400 + julianDayNumber) hashMultiply bitXor: totalSeconds \\ 86400) bitXor: nanos! ! !DateAndTime methodsFor: 'private' stamp: 'CamilloBruni 7/13/2012 20:17'! normalize: i ticks: ticks base: base | tick div quo rem | tick := ticks at: i. div := tick digitDiv: base neg: tick negative. quo := (div at: 1) normalize. rem := (div at: 2) normalize. rem < 0 ifTrue: [ quo := quo - 1. rem := base + rem ]. ticks at: (i-1) put: ((ticks at: i-1) + quo). ticks at: i put: rem ! ! !DateAndTime methodsFor: 'private' stamp: 'CamilloBruni 8/12/-4693 18:26'! setJdn: julDays seconds: secs nano: nanoSecs offset: anOffset julianDayNumber := julDays. seconds := secs. nanos := nanoSecs. offset := anOffset.! ! !DateAndTime methodsFor: 'private' stamp: 'CamilloBruni 3/30/2032 18:26'! ticks "Private - answer an array with our instance variables. Assumed to be UTC " ^ Array with: julianDayNumber with: seconds with: nanos.! ! !DateAndTime methodsFor: 'private' stamp: 'CamilloBruni 7/13/2012 20:18'! ticks: ticks offset: utcOffset "ticks is {julianDayNumber. secondCount. nanoSeconds}" self normalize: 3 ticks: ticks base: NanosInSecond. self normalize: 2 ticks: ticks base: SecondsInDay. julianDayNumber := ticks at: 1. seconds := ticks at: 2. nanos := ticks at: 3. offset := utcOffset! ! !DateAndTime methodsFor: 'arithmetic' stamp: 'CamilloBruni 7/13/2012 20:12'! + operand "operand conforms to protocol Duration" | ticks | ticks := self ticks with: (operand asDuration ticks) collect: [:ticks1 :dticks | ticks1 + dticks ]. ^ self class basicNew ticks: ticks offset: self offset; yourself. ! ! !DateAndTime methodsFor: 'arithmetic' stamp: 'brp 1/9/2004 05:39'! - operand "operand conforms to protocol DateAndTime or protocol Duration" ^ (operand respondsTo: #asDateAndTime) ifTrue: [ | lticks rticks | lticks := self asLocal ticks. rticks := operand asDateAndTime asLocal ticks. Duration seconds: (SecondsInDay *(lticks first - rticks first)) + (lticks second - rticks second) nanoSeconds: (lticks third - rticks third) ] ifFalse: [ self + (operand negated) ]. ! ! !DateAndTime methodsFor: 'arithmetic' stamp: 'CamilloBruni 7/13/2012 20:29'! < comparand "comparand conforms to protocol DateAndTime, or can be converted into something that conforms." | other utcSeconds otherUTCSeconds | other := comparand asDateAndTime. julianDayNumber < other julianDayNumber ifTrue: [ ^ true ]. utcSeconds := self asSeconds. otherUTCSeconds := other asSeconds. ^ utcSeconds = otherUTCSeconds ifFalse: [ utcSeconds < otherUTCSeconds ] ifTrue: [ nanos < other nanoSecond ]! ! !DateAndTime methodsFor: 'arithmetic' stamp: 'CamilloBruni 7/13/2012 18:54'! = other self == other ifTrue: [ ^ true ]. (self species = other species) ifFalse: [ ^ false ]. ^ self asSeconds = other asSeconds and: [ self nanoSecond = other nanoSecond ]! ! !TimeStamp methodsFor: 'squeak protocol' stamp: 'CamilloBruni 7/13/2012 19:30'! storeOn: aStream aStream nextPut: $'; print: self; nextPut: $'; nextPutAll: ' asTimeStamp'! ! !TimeZone class methodsFor: 'accessing' stamp: 'CamilloBruni 7/13/2012 20:54'! abbreviated: aString "Return the timezone whose abbreviation is aString." ^ self timeZones detect: [ :tz | tz abbreviation = aString ].! ! !TimeZone class methodsFor: 'accessing' stamp: 'CamilloBruni 7/13/2012 20:54'! offset: anOffset "Return the timezone with the given offset" ^ self timeZones detect: [ :tz | tz offset = anOffset ] ifNone: [ self new offset: anOffset ]! ! !DateTest methodsFor: 'tests' stamp: 'CamilloBruni 7/13/2012 21:14'! testAsSeconds | secondsSinceEpoch dateUTC dateEDT datePST | self useTimeZone: 'UTC' during: [ dateUTC := Date readFrom: '01-23-2004' readStream. secondsSinceEpoch := (dateUTC start - DateAndTime epoch) asSeconds. self assert: dateUTC asSeconds equals: secondsSinceEpoch. self assert: (Date fromSeconds: dateUTC asSeconds) equals: dateUTC ]. self useTimeZone: 'EDT' during: [ dateEDT := Date readFrom: '01-23-2004' readStream. secondsSinceEpoch := (dateEDT start - DateAndTime epoch) asSeconds. self assert: dateEDT asSeconds equals: secondsSinceEpoch. self assert: (Date fromSeconds: dateEDT asSeconds) equals: dateEDT ]. self useTimeZone: 'PST' during: [ datePST := Date readFrom: '01-23-2004' readStream. secondsSinceEpoch := (datePST start - DateAndTime epoch) asSeconds. self assert: datePST asSeconds equals: secondsSinceEpoch. self assert: (Date fromSeconds: datePST asSeconds) equals: datePST ]. self assert: dateUTC asSeconds equals: dateEDT asSeconds - (4*3600). self assert: dateUTC asSeconds equals: datePST asSeconds - (8*3600). ! ! !DateAndTimeEpochTest methodsFor: 'testing' stamp: 'CamilloBruni 7/13/2012 16:36'! testAsLocal self assert: aDateAndTime asLocal = aDateAndTime. self assert: aDateAndTime asLocal = (aDateAndTime offset: aDateAndTime class localOffset) ! ! !DateAndTimeEpochTest methodsFor: 'testing' stamp: 'CamilloBruni 7/13/2012 19:21'! testOffset self assert: aDateAndTime offset = '0:00:00:00' asDuration. self assert: (aDateAndTime offset: '-0:12:00:00') equals: '1900-12-31T12:00:00-12:00' asDateAndTime. self assert: (aDateAndTime offset: '0:12:00:00') equals: '1901-01-01T12:00:00+12:00' asDateAndTime! ! !DateAndTimeEpochTest methodsFor: 'testing' stamp: 'CamilloBruni 7/13/2012 16:52'! testTimeZone self assert: aDateAndTime timeZoneName = 'Universal Time'. self assert: aDateAndTime timeZoneAbbreviation = 'UTC' ! ! !DateAndTimeEpochTest methodsFor: 'testing' stamp: 'CamilloBruni 7/13/2012 16:36'! testUtcOffset self assert: (aDateAndTime offset: '0:12:00:00') = '1901-01-01T12:00:00+12:00' asDateAndTime! ! !Timespan methodsFor: 'conversion' stamp: 'brp 5/13/2003 08:49'! to: anEnd "Answer an Timespan. anEnd must be aDateAndTime or a Timespan" ^ Timespan starting: (self start) ending: (anEnd asDateAndTime). ! ! !Timespan methodsFor: 'conversion' stamp: 'CamilloBruni 7/13/2012 21:06'! translateTo: aTimeZone ^ self class starting: (start translateTo: aTimeZone)! ! !Timespan methodsFor: 'conversion' stamp: 'CamilloBruni 7/13/2012 21:06'! translateToUTC ^ self translateTo: 0! ! !Timespan methodsFor: 'enumerating' stamp: 'brp 7/27/2003 17:47'! intersection: aTimespan "Return the Timespan both have in common, or nil" | aBegin anEnd | aBegin := self start max: aTimespan start. anEnd := self end min: aTimespan end. anEnd < aBegin ifTrue: [^nil]. ^ self class starting: aBegin ending: anEnd. ! ! !Timespan methodsFor: 'enumerating' stamp: 'brp 1/9/2004 16:46'! union: aTimespan "Return the Timespan spanned by both" | aBegin anEnd | aBegin := self start min: aTimespan start. anEnd := self end max: aTimespan end. ^ Timespan starting: aBegin ending: (anEnd + DateAndTime clockPrecision). ! ! !Timespan methodsFor: 'arithmetic' stamp: 'brp 9/15/2003 14:05'! + operand "operand conforms to protocol Duration" ^ self class starting: (self start + operand) duration: self duration ! ! !Timespan methodsFor: 'arithmetic' stamp: 'brp 9/15/2003 14:07'! - operand "operand conforms to protocol DateAndTime or protocol Duration" ^ (operand respondsTo: #asDateAndTime) ifTrue: [ self start - operand ] ifFalse: [ self + (operand negated) ]. ! ! !Timespan methodsFor: 'arithmetic' stamp: 'brp 5/13/2003 08:43'! < comparand ^ self start < comparand ! ! !Timespan methodsFor: 'arithmetic' stamp: 'CamilloBruni 7/13/2012 20:45'! = comparand ^ self species = comparand species and: [ self start = comparand start and: [ self duration = comparand duration ]] ! ! !Timespan methodsFor: 'accessing' stamp: 'brp 5/13/2003 08:44'! asDate ^ start asDate ! ! !Timespan methodsFor: 'accessing' stamp: 'brp 5/13/2003 08:44'! asDateAndTime ^ start ! ! !Timespan methodsFor: 'accessing' stamp: 'brp 7/1/2003 14:09'! day "Answer the day of the year represented by the receiver." ^ self dayOfYear! ! !Timespan methodsFor: 'accessing' stamp: 'brp 7/27/2003 17:49'! dayOfMonth "Answer the day of the month represented by the receiver." ^ start dayOfMonth! ! !Timespan methodsFor: 'accessing' stamp: 'brp 8/6/2003 18:42'! dayOfWeek "Answer the day of the week represented by the receiver." ^ start dayOfWeek! ! !Timespan methodsFor: 'accessing' stamp: 'brp 8/6/2003 18:42'! dayOfWeekName "Answer the day of the week represented by the receiver." ^ start dayOfWeekName! ! !Timespan methodsFor: 'accessing' stamp: 'brp 8/24/2003 11:50'! dayOfYear "Answer the day of the year represented by the receiver." ^ start dayOfYear! ! !Timespan methodsFor: 'accessing' stamp: 'brp 5/13/2003 08:45'! daysInMonth ^ start daysInMonth ! ! !Timespan methodsFor: 'accessing' stamp: 'brp 5/13/2003 08:45'! daysInYear "Answer the number of days in the month represented by the receiver." ^ start daysInYear ! ! !Timespan methodsFor: 'accessing' stamp: 'brp 7/1/2003 17:50'! daysLeftInYear ^ start daysLeftInYear! ! !Timespan methodsFor: 'accessing' stamp: 'brp 5/13/2003 08:45'! duration "Answer the Duration of this timespan" ^ duration ! ! !Timespan methodsFor: 'accessing' stamp: 'brp 9/23/2004 09:53'! end ^ self duration asNanoSeconds = 0 ifTrue: [ self start ] ifFalse: [ self next start - DateAndTime clockPrecision ]! ! !Timespan methodsFor: 'accessing' stamp: 'brp 7/1/2003 17:55'! firstDayOfMonth ^ start firstDayOfMonth! ! !Timespan methodsFor: 'accessing' stamp: 'brp 5/13/2003 08:44'! hash ^ start hash + duration hash ! ! !Timespan methodsFor: 'accessing' stamp: 'brp 5/13/2003 08:44'! isLeapYear ^ start isLeapYear ! ! !Timespan methodsFor: 'accessing' stamp: 'brp 5/13/2003 08:47'! julianDayNumber ^ start julianDayNumber ! ! !Timespan methodsFor: 'accessing' stamp: 'brp 5/13/2003 08:44'! month ^ start month ! ! !Timespan methodsFor: 'accessing' stamp: 'brp 1/7/2004 16:25'! monthAbbreviation ^ start monthAbbreviation ! ! !Timespan methodsFor: 'accessing' stamp: 'brp 5/13/2003 08:47'! monthIndex ^ self month ! ! !Timespan methodsFor: 'accessing' stamp: 'brp 5/13/2003 08:44'! monthName ^ start monthName ! ! !Timespan methodsFor: 'accessing' stamp: 'brp 5/13/2003 08:47'! next ^ self class starting: (start + duration) duration: duration ! ! !Timespan methodsFor: 'accessing' stamp: 'brp 5/13/2003 08:48'! previous ^ self class starting: (start - duration) duration: duration ! ! !Timespan methodsFor: 'accessing' stamp: 'brp 5/13/2003 08:48'! start "Answer the start DateAndTime of this timespan" ^ start ! ! !Timespan methodsFor: 'accessing' stamp: 'brp 5/13/2003 08:48'! start: aDateAndTime "Store the start DateAndTime of this timespan" start := aDateAndTime asDateAndTime ! ! !Timespan methodsFor: 'accessing' stamp: 'brp 5/13/2003 08:44'! year ^ start year ! ! !Timespan methodsFor: 'testing' stamp: 'brp 1/7/2004 16:05'! includes: aDateAndTime ^ (aDateAndTime isKindOf: Timespan) ifTrue: [ (self includes: aDateAndTime start) and: [ self includes: aDateAndTime end ] ] ifFalse: [ aDateAndTime asDateAndTime between: start and: self end ] ! ! !Timespan methodsFor: 'testing' stamp: 'brp 7/27/2003 17:54'! includesAllOf: aCollection "Answer whether all the elements of aCollection are in the receiver." aCollection do: [:elem | (self includes: elem) ifFalse: [^ false]]. ^ true ! ! !Timespan methodsFor: 'testing' stamp: 'brp 1/7/2004 15:59'! includesAnyOf: aCollection "Answer whether any element of aCollection is included in the receiver" aCollection do: [ :elem | (self includes: elem) ifTrue: [^ true]]. ^false ! ! !Timespan methodsFor: 'printing' stamp: 'brp 9/25/2003 09:17'! printOn: aStream super printOn: aStream. aStream nextPut: $(; print: start; nextPut: $D; print: duration; nextPut: $). ! ! !Date class methodsFor: 'instance creation' stamp: 'CamilloBruni 7/13/2012 21:16'! fromSeconds: seconds "Answer an instance of me which is 'seconds' seconds after January 1, 1901." ^ self starting: (DateAndTime fromSeconds: seconds)! ! !DateAndTimeDosEpochTest methodsFor: 'running' stamp: 'CamilloBruni 7/13/2012 19:11'! setUp localTimeZoneToRestore := DateAndTime localTimeZone. aDateAndTime := DateAndTime localTimeZone: TimeZone default; dosEpoch. aTimeZone := TimeZone offset: (Duration minutes: 135) name: 'DOS Epoch Test Time Zone' abbreviation: 'DTZ'. aDuration := Duration days: 1 hours: 2 minutes: 3 seconds: 4 nanoSeconds: 5 ! ! !DateAndTimeDosEpochTest methodsFor: 'running' stamp: 'CamilloBruni 7/13/2012 19:12'! tearDown "wish I could remove the time zones I added earlier, but there is no method for that" DateAndTime localTimeZone: localTimeZoneToRestore. ! ! !DateAndTimeDosEpochTest methodsFor: 'testing' stamp: 'CamilloBruni 7/13/2012 16:36'! testAsLocal self assert: aDateAndTime asLocal = aDateAndTime. self assert: aDateAndTime asLocal = (aDateAndTime offset: aDateAndTime class localOffset) ! ! !DateAndTimeDosEpochTest methodsFor: 'testing' stamp: 'CamilloBruni 7/13/2012 19:19'! testOffset self assert: aDateAndTime offset = '0:00:00:00' asDuration. self assert: (aDateAndTime offset: '-0:12:00:00') equals: '1979-12-31T12:00:00-12:00' asDateAndTime. self assert: (aDateAndTime offset: '0:12:00:00') equals: '1980-01-01T12:00:00+12:00' asDateAndTime! ! !DateAndTimeDosEpochTest methodsFor: 'testing' stamp: 'CamilloBruni 7/13/2012 16:53'! testTimeZone self assert: aDateAndTime timeZoneName = 'Universal Time'. self assert: aDateAndTime timeZoneAbbreviation = 'UTC' ! ! !DateAndTimeDosEpochTest methodsFor: 'testing' stamp: 'CamilloBruni 7/13/2012 19:15'! testUtcOffset self assert: (aDateAndTime offset: '0:12:00:00') equals: '1980-01-01T12:00:00+12:00' asDateAndTime! ! !DateAndTimeLeapTest methodsFor: 'running' stamp: 'CamilloBruni 7/13/2012 20:50'! setUp aDateAndTime := (DateAndTime year: 2004 month: 2 day: 29 hour: 13 minute: 33 second: 0 offset: 2 hours). aTimeZone := TimeZone default. aDuration := Duration days: 0 hours: 13 minutes: 33 seconds: 0 nanoSeconds: 0 ! ! !DateAndTimeLeapTest methodsFor: 'testing' stamp: 'CamilloBruni 7/13/2012 21:08'! testAsDate self assert: aDateAndTime asDate equals: ('February 29, 2004' asDate translateTo: 2 hours).! ! !DateAndTimeLeapTest methodsFor: 'testing' stamp: 'CamilloBruni 7/13/2012 19:25'! testAsDuration self assert: aDateAndTime asDuration equals: aDuration ! ! !DateAndTimeLeapTest methodsFor: 'testing' stamp: 'CamilloBruni 7/13/2012 16:36'! testAsLocal self assert: aDateAndTime asLocal = aDateAndTime. self assert: aDateAndTime asLocal = (aDateAndTime offset: aDateAndTime class localOffset) ! ! !DateAndTimeLeapTest methodsFor: 'testing' stamp: 'CamilloBruni 7/13/2012 19:26'! testAsTime self assert: aDateAndTime asTime equals: (Time hour: 13 minute: 33 second: 0) ! ! !DateAndTimeLeapTest methodsFor: 'testing' stamp: 'CamilloBruni 7/16/2012 19:22'! testAsTimeStamp self assert: aDateAndTime asTimeStamp "note that the timestamp string is written in UTC" equals: ((TimeStamp readFrom: '2-29-2004 1:33 pm' readStream) translateTo: 2 hours) ! ! !DateAndTimeLeapTest methodsFor: 'testing' stamp: 'CamilloBruni 7/13/2012 21:09'! testAsWeek self assert: aDateAndTime asWeek equals: ((Week starting: '02-29-2004' asDate) translateTo: 2 hours). ! ! !DateAndTimeLeapTest methodsFor: 'testing' stamp: 'CamilloBruni 7/13/2012 21:10'! testAsYear self assert: aDateAndTime asYear equals: ((Year starting: '02-29-2004' asDate) translateTo: 2 hours ). self deny: aDateAndTime asYear = ((Year starting: '01-01-2004' asDate) translateTo: 2 hours) ! ! !DateAndTimeLeapTest methodsFor: 'testing' stamp: 'CamilloBruni 7/13/2012 16:53'! testHour self assert: aDateAndTime hour equals: aDateAndTime hour24. self assert: aDateAndTime hour equals: 13. self assert: aDateAndTime hour equals: aDateAndTime hours ! ! !DateAndTimeLeapTest methodsFor: 'testing' stamp: 'CamilloBruni 7/13/2012 20:56'! testMidnight self assert: aDateAndTime midnight equals: '2004-02-29T00:00:00+02:00' asDateAndTime. ! ! !DateAndTimeLeapTest methodsFor: 'testing' stamp: 'CamilloBruni 7/13/2012 19:24'! testOffset self assert: aDateAndTime offset = '0:02:00:00' asDuration. self assert: (aDateAndTime offset: '-0:12:00:00') equals: '2004-02-28T23:33:00-12:00' asDateAndTime. self assert: (aDateAndTime offset: '0:12:00:00') equals: '2004-02-29T23:33:00+12:00' asDateAndTime! ! !DateAndTimeLeapTest methodsFor: 'testing' stamp: 'CamilloBruni 7/13/2012 19:35'! testTicks self assert: aDateAndTime ticks equals: ((DateAndTime julianDayNumber: 2453065) + 41580 seconds) ticks. self assert: aDateAndTime ticks equals: #(2453065 41580 0)! ! !DateAndTimeLeapTest methodsFor: 'testing' stamp: 'CamilloBruni 7/13/2012 20:59'! testTimeZone aDateAndTime := '2004-02-29T13:33:00+00:00' asDateAndTime. self assert: aDateAndTime timeZone name equals: 'Universal Time'. self assert: aDateAndTime timeZone abbreviation equals: 'UTC' ! ! !DateAndTimeLeapTest methodsFor: 'testing' stamp: 'CamilloBruni 7/13/2012 16:36'! testUtcOffset self assert: (aDateAndTime offset: '0:02:00:00') = '2004-02-29T13:33:00+02:00' asDateAndTime! ! !DateAndTimeLeapTest methodsFor: 'testing' stamp: 'CamilloBruni 7/13/2012 19:36'! testYearDayHourMinuteSecond self assert: aDateAndTime equals: (DateAndTime year: 2004 day: 60 hour: 13 minute: 33 second: 0 offset: 2 hours). ! ! !DateAndTimeLeapTest methodsFor: 'testing' stamp: 'CamilloBruni 7/13/2012 19:36'! testYearMonthDayHourMinuteSecond self assert: aDateAndTime equals: (DateAndTime year: 2004 month: 2 day: 29 hour: 13 minute: 33 second: 0 offset: 2 hours). ! ! !DateAndTimeUnixEpochTest methodsFor: 'testing' stamp: 'CamilloBruni 7/13/2012 16:36'! testAsLocal self assert: aDateAndTime asLocal = aDateAndTime. self assert: aDateAndTime asLocal = (aDateAndTime offset: aDateAndTime class localOffset) ! ! !DateAndTimeUnixEpochTest methodsFor: 'testing' stamp: 'CamilloBruni 7/13/2012 20:30'! testOffset self assert: aDateAndTime offset = '0:00:00:00' asDuration. self assert: (aDateAndTime offset: '0:12:00:00') equals: '1970-01-01T12:00:00+12:00' asDateAndTime! ! !DateAndTimeUnixEpochTest methodsFor: 'testing' stamp: 'CamilloBruni 7/13/2012 16:51'! testTimeZone self assert: aDateAndTime timeZoneName = 'Universal Time'. self assert: aDateAndTime timeZoneAbbreviation = 'UTC' ! ! !DateAndTimeUnixEpochTest methodsFor: 'testing' stamp: 'CamilloBruni 7/13/2012 16:36'! testUtcOffset self assert: (aDateAndTime offset: '0:12:00:00') = '1970-01-01T12:00:00+12:00' asDateAndTime! ! !DateAndTime class methodsFor: 'instance creation' stamp: 'CamilloBruni 7/13/2012 16:45'! fromSeconds: seconds "Answer a DateAndTime since the Squeak epoch: 1 January 1901 for the seconds in UTC time" ^ self fromSeconds: seconds offset: self localOffset! ! !DateAndTime class methodsFor: 'instance creation' stamp: 'CamilloBruni 7/13/2012 16:50'! fromSeconds: seconds offset: aUTCOffset "Answer a DateAndTime since the Squeak epoch: 1 January 1901 for the given timeZone" | integerSeconds nanos | integerSeconds := seconds truncated. integerSeconds = seconds ifTrue: [nanos := 0] ifFalse: [nanos := (seconds - integerSeconds * NanosInSecond) asInteger]. ^ self basicNew ticks: (Array with: SqueakEpoch with: integerSeconds with: nanos) offset: aUTCOffset asDuration! ! !DateAndTime class methodsFor: 'instance creation' stamp: 'ul 11/6/2010 23:57'! now | nanoTicks msm | nanoTicks := (msm := self milliSecondsSinceMidnight) * 1000000. (LastTick < nanoTicks) ifTrue: [ LastTick := nanoTicks. ^ self todayAtMilliSeconds: msm]. LastTickSemaphore critical: [ LastTick := LastTick + 1. ^ self todayAtNanoSeconds: LastTick] " [ 10000 timesRepeat: [ self now. ] ] timeToRun / 10000.0 . If calls to DateAndTime-c-#now are within a single millisecond the semaphore code to ensure that (self now <= self now) slows things down considerably by a factor of about 20. The actual speed of a single call to DateAndTime-now in milliseconds is demonstrated by the unguarded method below. [ 100000 timesRepeat: [ self todayAtMilliSeconds: (self milliSecondsSinceMidnight) ] ] timeToRun / 100000.0 . 0.00494 0.00481 0.00492 0.00495 "! ! !DateAndTime class methodsFor: 'instance creation' stamp: 'CamilloBruni 7/13/2012 20:43'! year: year month: month day: day hour: hour minute: minute offset: anOffset "Return a DateAndTime" ^ self year: year month: month day: day hour: hour minute: minute second: 0 offset: anOffset! ! !DateAndTime class methodsFor: 'instance creation' stamp: 'CamilloBruni 7/13/2012 19:15'! year: year month: month day: day hour: hour minute: minute second: second nanoSecond: nanoCount offset: utcOffset "Return a DateAndTime with the values in the given TimeZone (UTCOffset)" | monthIndex daysInMonth p q r s julianDayNumber localSeconds utcSeconds| monthIndex := month isInteger ifTrue: [ month ] ifFalse: [ Month indexOfMonth: month ]. daysInMonth := Month daysInMonth: monthIndex forYear: year. day < 1 ifTrue: [ self error: 'day may not be zero or negative' ]. day > daysInMonth ifTrue: [ self error: 'day is after month ends' ]. p := (monthIndex - 14) quo: 12. q := year + 4800 + p. r := monthIndex - 2 - (12 * p). s := (year + 4900 + p) quo: 100. julianDayNumber := ((1461 * q) quo: 4) + ((367 * r) quo: 12) - ((3 * s) quo: 4) + (day - 32075). localSeconds := hour * 60 + minute * 60 + second. utcSeconds := localSeconds - utcOffset asSeconds. ^self basicNew setJdn: julianDayNumber seconds: utcSeconds nano: nanoCount offset: utcOffset; yourself! ! !DateAndTime class methodsFor: 'instance creation' stamp: 'CamilloBruni 7/13/2012 20:42'! year: year month: month day: day offset: anOffset "Return a DateAndTime, midnight in the timezone with the given offset" ^ self year: year month: month day: day hour: 0 minute: 0 offset: anOffset ! ! !Integer methodsFor: 'accessing' stamp: 'CamilloBruni 7/13/2012 18:09'! primeFactors "Return all primeFactors of myself" "( 106260 primeFactors fold: [ :a :b | a * b ]) = 106260" ^ Array streamContents: [ :s | self primeFactorsOn: s ]! ! !Integer methodsFor: 'accessing' stamp: 'CamilloBruni 7/13/2012 18:06'! primeFactorsOn: aStream "Recursively calculate the primefactors of myself and put the factors into the given stream" self = 1 ifTrue: [ ^ self ]. self even ifTrue: [ aStream nextPut: 2. ^ (self / 2) primeFactorsOn: aStream ]. 3 to: self sqrtFloor by: 2 do: [ :each | self \\ each = 0 ifTrue: [ aStream nextPut: each. ^ (self / each) primeFactorsOn: aStream ]]. aStream nextPut: self.! ! !Integer methodsFor: 'mathematical functions' stamp: 'CamilloBruni 7/13/2012 17:45'! take: kk "Return the number of combinations of (self) elements taken kk at a time. For 6 take 3, this is 6*5*4 / (1*2*3). Zero outside of Pascal's triangle. Use a trick to go faster." " 6 take: 3 " | num denom | kk < 0 ifTrue: [^ 0]. kk > self ifTrue: [^ 0]. num := 1. self to: (kk max: self-kk) + 1 by: -1 do: [:factor | num := num * factor]. denom := 1. 1 to: (kk min: self-kk) do: [:factor | denom := denom * factor]. ^ num // denom! ! DateAndTimeUnixEpochTest removeSelector: #testtimeZone! DateAndTimeLeapTest removeSelector: #tearDown! DateAndTimeLeapTest removeSelector: #testtimeZone! DateAndTimeDosEpochTest removeSelector: #testtimeZone! DateAndTimeEpochTest removeSelector: #testtimeZone! DateAndTime removeSelector: #clearOffset! !DateAndTime class methodsFor: 'instance creation' stamp: 'CamilloBruni 7/16/2012 19:24'! new "Answer a DateAndTime representing the Squeak epoch: 1 January 1901" ^ self epoch offset: self localOffset ! ! !DateAndTimeLeapTest methodsFor: 'testing' stamp: 'CamilloBruni 7/16/2012 19:22'! testAsTimeStamp self assert: aDateAndTime asTimeStamp "note that the timestamp string is written in UTC" equals: ((TimeStamp readFrom: '2-29-2004 1:33 pm' readStream) translateTo: 2 hours) ! ! !DateAndTimeLeapTest methodsFor: 'testing' stamp: 'CamilloBruni 7/16/2012 19:22'! testNoon self assert: aDateAndTime noon equals: '2004-02-29T12:00:00+02:00' asDateAndTime! !