...and Y3K, Y4K, Y5K, etc...
Date today addDays: 400 -> "4 August 2000" Date today addDays: 4000 -> "13 June 2010" Date today addDays: 40000 -> "5 January 2109" Date today addDays: 400000 -> "29 August 3094"
Stephen:
Did you check that all those dates are correct? The next step in the iteration yields my birthday! :)
Date today addDays: 4000000 -> 15 February 12951
-Duane
How old will you be on that birthday? :)
Interestingly, to verify those dates, you would need to rely on some algorithm, unless you happen to have calendars for the next mellinium handy (and a lot of spare time). So you would need to verify the algorithm in Squeak with the algorithm accepted as an international standard.
Assuming that the arithmetic and algorithms in the Date class are correct and that you have a reliable source (your OS, accessing primitives, human entry) for dates and times, you should be safe. Storage of the dates should also be a non issue as long as there are no flaws in the internal representation and external conversions.
- Stephen
-----Original Message----- From: Duane T Williams [mailto:duane@cmu.edu] Sent: Thursday, July 01, 1999 11:04 PM To: squeak@cs.uiuc.edu Subject: RE: Is sqeak 2.3 beta ready for Y2K?
...and Y3K, Y4K, Y5K, etc...
Date today addDays: 400 -> "4 August 2000" Date today addDays: 4000 -> "13 June 2010" Date today addDays: 40000 -> "5 January 2109" Date today addDays: 400000 -> "29 August 3094"
Stephen:
Did you check that all those dates are correct? The next step in the iteration yields my birthday! :)
Date today addDays: 4000000 -> 15 February 12951
-Duane
Stephen Pair wrote:
How old will you be on that birthday? :)
Interestingly, to verify those dates, you would need to rely on some algorithm, unless you happen to have calendars for the next mellinium handy (and a lot of spare time). So you would need to verify the algorithm in Squeak with the algorithm accepted as an international standard.
Assuming that the arithmetic and algorithms in the Date class are correct and that you have a reliable source (your OS, accessing primitives, human entry) for dates and times, you should be safe. Storage of the dates should also be a non issue as long as there are no flaws in the internal representation and external conversions.
I decided to actually check the code, and believe I have found some flaws:
Date class>fromDays: dayCount "Answer an instance of me which is dayCount days after January 1, 1901."
^self newDay: 1 + (dayCount asInteger rem: 1461) "There are 1461 days in a 4-year cycle. 2000 is a leap year, so no extra correction is necessary. " year: 1901 + ((dayCount asInteger quo: 1461) * 4)
The problem with the above is that the algorithm deals only with every-4-year leap days, but not with every-100-year anti-leap days nor every-400 year super-leap days. Of course, as the comment notes, this lapse just so happens to give the correct result for the year 2000. The algorithm above is valid only for years in the range 1901 to 2099.
subtractDate: aDate "Answer the number of days between the receiver and aDate."
year = aDate year ifTrue: [^day - aDate day] ifFalse: [^year - 1 // 4 - (aDate year // 4) + day + aDate daysLeftInYear + (year - 1 - aDate year * 365)]
The same flaw is exhibited with the algorithm above: it only accounts for the leap days defined by the Julian calendar, and fails to consider the Gregorian leap days (which fail to occur in 3 out of every 4 century years).
Date class>leapYear: yearInteger "Answer 1 if the year yearInteger is a leap year; answer 0 if it is not."
(yearInteger \ 4 ~= 0 or: [yearInteger \ 100 = 0 and: [yearInteger \ 400 ~= 0]]) ifTrue: [^0] ifFalse: [^1]
And finally, the algorithm (above) that determines whether a year is a leap year does not properly handle dates B.C. This can easily be fixed with the following version:
Date class>leapYear: yearInteger "Answer 1 if the year yearInteger is a leap year; answer 0 if it is not."
| adjustedYear | adjustedYear := yearInteger > 0 ifTrue: [yearInteger] ifFalse: [(yearInteger + 1) negated "There is no year 0!!"]. (adjustedYear \ 4 ~= 0 or: [adjustedYear \ 100 = 0 and: [adjustedYear \ 400 ~= 0]]) ifTrue: [^0] ifFalse: [^1]
Below is an alogorithm that computes the Gregorian year, and the day of the year, from the number of days since (or until) January 1 of the year 1 A.D.:
Date class>gregorianYearAndDaysInYearFromDays: days into: aTwoArgBlock
| quadCentury centuryquadYear year daysInMonth value isInADEra |
value := days. isInADEra := days >= 0.
isInADEra ifTrue: [year := 0] ifFalse: [value := value abs. value >= DaysPerLeapYear ifTrue: [year := 1; value := value - DaysPerLeapYear. "Subtract the year 1 B.C." ] ifFalse: [year := 0]]
quadCentury := value // DaysPerQuadCentury. value := value \ DaysPerQuadCentury. century := value // DaysPerCentury. value := value \ DaysPerCentury. quadYear := value // DaysPerQuadYear. value := value \ DaysPerQuadYear. value >= DaysPerStandardYear ifTrue: ["e.g., 1 AD or 2 BC" value := value - DaysPerStandardYear. year := year + 1. value >= DaysPerStandardYear ifTrue: ["e.g., 2 AD or 3 BC" value := value - DaysPerStandardYear. year := year + 1. value >= DaysPerStandardYear ifTrue: ["e.g., 3 AD or 4 BC" value := value - DaysPerStandardYear. year := year + 1. value >= DaysPerLeapYear ifTrue: ["e.g., 4 AD or 5 BC (although this won't occur in the AD case)" value := value - DaysPerLeapYear. year := year + 1]]]]. year := year + (quadCentury * YearsPerQuadCentury) + (century * YearsPerCentury) + (quadYear * YearsPerQuadYear) + 1; isInADEra ifTrue: [year := year + 1 "Adjust for fact that years are ordinals"] ifFalse: [year := year negated. value > 0 ifTrue: [(Date leapYear: year) = 1 ifTrue: [value := DaysPerLeapYear - value] ifFalse: [value := DaysPerStandardYear - value]]]. ^aTwoArgBlock value: year value: value
And here is an algorithm that computes the number of days from (or until) January 1 of the year 1 A.D. upto (or since) January 1 of a given year:
Date class>daysForYear: gregorianYear | days yearDelta quadCenturies centuries quadYears years isInADEra |
days := 0. isInADEra := gregorianYear > 0.
gregorianYear = 0 ifTrue: [gregorianYear = -1]. "There is no year 0" isInADEra ifTrue: [yearDelta := gregorianYear - 1] ifFalse: [yearDelta := (gregorianYear + 1) negated]. quadCenturies := yearDelta // yearsPerQuadCentury. yearDelta := yearDelta rem: yearsPerQuadCentury. centuries := yearDelta // yearsPerCentury. yearDelta := yearDelta rem: yearsPerCentury. quadYears := yearDelta // yearsPerQuadYear. years := yearDelta rem: yearsPerQuadYear. days := (quadCenturies * DaysPerQuadCentury) + (centuries * DaysPerCentury) + (quadYears * DaysPerQuadYear) + (years * DaysPerStandardYear). isInADEra ifFalse: [days := days + DaysPerLeapYear. "1 B.C. is a leap year" days := days negated]. ^days
These algorithms depend on the following constants:
DaysPerStandardYear := 365. DaysPerLeapYear := DaysPerStandardYear + 1. YearsPerQuadYear := 4. YearsPerCentury := 100. YearsPerQuadCentury := 400. QuadYearsPerCentury = 25. DaysPerQuadYear := DaysPerLeapYear + (3 * DaysPerStandardYear). DaysPerCentury := QuadYearsPerCentury * DaysPerQuadYear - 1. CenturiesPerQuadCentury := 4. DaysPerQuadCentury := CenturiesPerQuadCentury * DaysPerCentury + 1.
Some useful/interesting values:
Number of days (Gregorian, not Julian) from 1/1/1 to 15 Oct 1582 (the date on which the Gregorian Calendar became the official calendar of the Roman Catholic world): 577735.
Number of days (Gregorian, not Julian) from 1/1/1 to 1 Jan 1900: 693,595.
Number of days (ditto) from 1/1/1 to 1 Jan 1901: 693,960 (Squeak's & VW's base date).
Number of days (ditto) from 1/1/1 to 1 Jan 1970: 719,162 (Unix/VMS/MVS/VM base date).
Number of days (ditto) from 1/1/1 to 1 Jan 1980: 722,814 (WinDos/Mac base date).
Number of days (ditto) from 1/1/1 to: 1 Jan 2000: 730,119 (a topical value).
--Alan ("Do I have too much ``time`` on my hands, or what?")
Content-Type: text/x-vcard; charset=us-ascii; name="sourcery.vcf" Content-Transfer-Encoding: 7bit Content-Description: Card for Alan Lovejoy Content-Disposition: attachment; filename="sourcery.vcf"
Attachment converted: Anon:sourcery.vcf 4 (TEXT/R*ch) (0000AD6E)
squeak-dev@lists.squeakfoundation.org