Bert Freudenberg uploaded a new version of Kernel to project The Inbox:
http://source.squeak.org/inbox/Kernel-bf.700.mcz ==================== Summary ==================== Name: Kernel-bf.700 Author: bf Time: 28 June 2012, 7:34:28.085 pm UUID: 019680d3-785f-43a5-bc2a-9fed7bade3bb Ancestors: Kernel-fbs.699 Make DateAndTime use the Julian Calendar for dates earlier than 15 October 1582. =============== Diff against Kernel-fbs.699 =============== Item was changed: Magnitude subclass: #DateAndTime instanceVariableNames: 'seconds offset jdn nanos' classVariableNames: 'ClockProvider DaysSinceEpoch LastMilliSeconds LastTick LastTickSemaphore LocalTimeZone MilliSecondOffset OffsetsAreValid' poolDictionaries: 'ChronologyConstants' category: 'Kernel-Chronology'! + !DateAndTime commentStamp: 'bf 6/28/2012 19:09' prior: 0! - !DateAndTime commentStamp: 'brp 5/13/2003 08:07' prior: 0! I represent a point in UTC time as defined by ISO 8601. I have zero duration. + In contrast to ISO 8601, which uses the Gregorian Proleptic Calendar exclusively, I use the Julian Proleptic Calendar for dates prior to 15 Oct 1582. However, for seriously dealing with multiple calendars, you should use a more thorough date package (e.g. Calendrica). + My implementation uses three SmallIntegers and a Duration: - My implementation uses three SmallIntegers - and a Duration: jdn - julian day number. seconds - number of seconds since midnight. nanos - the number of nanoseconds since the second. - offset - duration from UTC. The nanosecond attribute is almost always zero but it defined for full ISO compliance and is suitable for timestamping. ! Item was added: + ----- Method: DateAndTime class>>gregorianYear:month:day:hour:minute:second:nanoSecond:offset: (in category 'squeak protocol') ----- + gregorianYear: year month: month day: day hour: hour minute: minute second: second nanoSecond: nanoCount offset: offset + "Return a DateAndTime" + + | daysInMonth p q r s julianDayNumber | + daysInMonth := Month + daysInMonth: month + 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 := (month - 14) quo: 12. + q := year + 4800 + p. + r := month - 2 - (12 * p). + s := (year + 4900 + p) quo: 100. + + julianDayNumber := + ( (1461 * q) quo: 4 ) + + ( (367 * r) quo: 12 ) - + ( (3 * s) quo: 4 ) + + ( day - 32075 ). + + ^self basicNew + setJdn: julianDayNumber + seconds: hour * 60 + minute * 60 + second + nano: nanoCount + offset: offset; + yourself! Item was added: + ----- Method: DateAndTime class>>julianYear:month:day:hour:minute:second:nanoSecond:offset: (in category 'squeak protocol') ----- + julianYear: year month: month day: day hour: hour minute: minute second: second nanoSecond: nanoCount offset: offset + "Return a DateAndTime" + + | days | + days := + (365 * (year - 1)) + "years since epoch" + ((year - 1) // 4) + "leap days since epoch" + (((367 * month) - 362) // 12) + "30/31 day months since newyear" + day. + month > 2 ifTrue: [ "we counted this February as 30 days; correct to 29 or 28" + days := days - ((Year isJulianLeapYear: year) ifTrue: [1] ifFalse: [2])]. + ^self basicNew + setJdn: 1721423 + days + seconds: hour * 60 + minute * 60 + second + nano: nanoCount + offset: offset; + yourself! Item was changed: ----- Method: DateAndTime class>>year:month:day:hour:minute:second:nanoSecond:offset: (in category 'squeak protocol') ----- year: year month: month day: day hour: hour minute: minute second: second nanoSecond: nanoCount offset: offset + "Return a DateAndTime. If date is after 15 Oct 1582, use Gregorian calendar, otherwise the Julian calendar" - "Return a DateAndTime" + | monthIndex | - | monthIndex daysInMonth p q r s julianDayNumber | - monthIndex := month isInteger ifTrue: [month] ifFalse: [Month indexOfMonth: month]. + ^(year > 1582 or: [year = 1582 and: [monthIndex > 10 or: [monthIndex = 10 and: [day >= 15]]]]) + ifTrue: [self gregorianYear: year month: monthIndex day: day hour: hour minute: minute second: second nanoSecond: nanoCount offset: offset] + ifFalse: [self julianYear: year month: monthIndex day: day hour: hour minute: minute second: second nanoSecond: nanoCount offset: offset] + ! - 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 ). - - ^self basicNew - setJdn: julianDayNumber - seconds: hour * 60 + minute * 60 + second - nano: nanoCount - offset: offset; - yourself! Item was changed: ----- Method: DateAndTime>>dayMonthYearDo: (in category 'squeak protocol') ----- dayMonthYearDo: aBlock + "Evaluate the block with three arguments: day, month, year. + For dates since 15 Oct 1582 use Gregorian calendar, before that, the Julian calendar" - "Evaluation the block with three arguments: day month, year." + ^jdn < 2299161 + ifTrue: [self julianDayMonthYearDo: aBlock] + ifFalse: [self gregorianDayMonthYearDo: aBlock]! - | l n i j dd mm yyyy | - l := jdn + 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. - dd := l - (2447 * j // 80). - l := j // 11. - mm := j + 2 - (12 * l). - yyyy := 100 * (n - 49) + i + l. - - ^ aBlock - value: dd - value: mm - value: yyyy! Item was added: + ----- Method: DateAndTime>>gregorianDayMonthYearDo: (in category 'squeak protocol') ----- + gregorianDayMonthYearDo: aBlock + "Evaluate the block with three arguments: day, month, year." + + | l n i j dd mm yyyy | + l := jdn + 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. + dd := l - (2447 * j // 80). + l := j // 11. + mm := j + 2 - (12 * l). + yyyy := 100 * (n - 49) + i + l. + + ^ aBlock + value: dd + value: mm + value: yyyy! Item was added: + ----- Method: DateAndTime>>julianDayMonthYearDo: (in category 'squeak protocol') ----- + julianDayMonthYearDo: aBlock + "Evaluate the block with three arguments: day, month, year" + + | totalDays day month year daysSinceNewYear fakeDaysSinceNewYear daysToFirstOfMonth fakeDaysToFirstOfMonth fakeAmount | + totalDays := jdn - 1721424. "days since epoch 1 January 1" + year := (4 * totalDays + 1464) // 1461. + daysSinceNewYear := totalDays + - (365 * (year - 1)) "years since epoch" + - ((year - 1) // 4) . "leap days since epoch" + "after Feb 28, make Feb look like it was a 30-day month" + fakeAmount := daysSinceNewYear <= 58 + ifTrue: [0] + ifFalse: [(Year isJulianLeapYear: year) ifTrue: [1] ifFalse: [2]]. + fakeDaysSinceNewYear := daysSinceNewYear + fakeAmount. + "month formulas assume 30/31 day months" + month := ((12 * fakeDaysSinceNewYear) + 373) // 367. + fakeDaysToFirstOfMonth := ((367 * month) - 362) // 12. + daysToFirstOfMonth := month > 2 + ifTrue: [fakeDaysToFirstOfMonth - fakeAmount] + ifFalse: [fakeDaysToFirstOfMonth]. + day := daysSinceNewYear - daysToFirstOfMonth + 1. + ^ aBlock + value: day + value: month + value: year! Item was changed: ----- Method: Year class>>daysInYear: (in category 'smalltalk-80') ----- daysInYear: yearInteger + ^ 365 + (self leapYear: yearInteger) - ^ 365 + ((self isLeapYear: yearInteger) ifTrue: [1] ifFalse: [0]). ! Item was added: + ----- Method: Year class>>isGregorianLeapYear: (in category 'squeak protocol') ----- + isGregorianLeapYear: aYearInteger + | adjustedYear | + adjustedYear := aYearInteger > 0 + ifTrue: [aYearInteger] + ifFalse: [(aYearInteger + 1) negated]. + "There was no year 0" + ^ ((adjustedYear \\ 4 ~= 0) or: [(adjustedYear \\ 100 = 0) and: [adjustedYear \\ 400 ~= 0]]) not! Item was added: + ----- Method: Year class>>isJulianLeapYear: (in category 'squeak protocol') ----- + isJulianLeapYear: aYearInteger + ^ aYearInteger \\ 4 = 0! Item was changed: ----- Method: Year class>>isLeapYear: (in category 'squeak protocol') ----- isLeapYear: aYearInteger + ^ aYearInteger >= 1582 + ifTrue: [self isGregorianLeapYear: aYearInteger] + ifFalse: [self isJulianLeapYear: aYearInteger] + ! - - | adjustedYear | - adjustedYear := aYearInteger > 0 - ifTrue: [aYearInteger] - ifFalse: [(aYearInteger + 1) negated]. - - "There was no year 0" - ^ ((adjustedYear \\ 4 ~= 0) or: [(adjustedYear \\ 100 = 0) and: [adjustedYear \\ 400 ~= 0]]) not! |
Free forum by Nabble | Edit this page |