'From Cuis 1.0 of 2 October 2009 [latest update: #316] on 4 November 2009 at 1:11:56 pm'!
!classDefinition: #DateAndTime category: #'Kernel-Chronology'!
Magnitude subclass: #DateAndTime
	instanceVariableNames: 'seconds offset jdn nanos '
	classVariableNames: 'LocalTimeZone ClockProvider LastTickSemaphore DaysSinceEpoch LastTick LastMilliSeconds MilliSecondOffset '
	poolDictionaries: 'ChronologyConstants'
	category: 'Kernel-Chronology'!

!DateAndTime commentStamp: '<historical>' prior: 0!
I represent a point in UTC time as defined by ISO 8601. I have zero 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.
!


!Duration commentStamp: '<historical>' prior: 0!
I represent a duration of time. I have nanosecond precision!


!Time commentStamp: '<historical>' prior: 0!
This represents a particular point in time during any given day.  For example, '5:19:45 pm'.

If you need a point in time on a particular day, use DateAndTime.  If you need a duration of time, use Duration.!


!TimeZone commentStamp: '<historical>' prior: 0!
TimeZone is a simple class to colect the information identifying a UTC time zone.

offset			-	Duration	- the time zone's offset from UTC
abbreviation	-	String		- the abbreviated name for the time zone.
name			-	String		- the name of the time zone.

TimeZone class >> #timeZones returns an array of the known time zones
TimeZone class >> #default returns the default time zone (Grenwich Mean Time)!


!Timespan commentStamp: '<historical>' prior: 0!
I represent a duration starting on a specific DateAndTime.!


!Year commentStamp: '<historical>' prior: 0!
I represent a year.!


!DateAndTime methodsFor: 'ansi protocol' stamp: 'brp 7/28/2004 16:14'!
= comparand
	"comparand conforms to protocol DateAndTime,
	or can be converted into something that conforms."
	| comparandAsDateAndTime |
	self == comparand
		ifTrue: [^ true].
	[comparandAsDateAndTime := comparand asDateAndTime]
		on: MessageNotUnderstood
		do: [^ false].
	^ self offset = comparandAsDateAndTime offset
		ifTrue: [self hasEqualTicks: comparandAsDateAndTime ]
		ifFalse: [self asUTC ticks = comparandAsDateAndTime asUTC ticks]
! !

!DateAndTime methodsFor: 'squeak protocol' stamp: 'ul 10/15/2009 01:15'!
midnight
	"Answer a DateAndTime starting at midnight local time"

	^self class basicNew
		setJdn: jdn
		seconds: 0
		nano: 0
		offset: self class localOffset
! !

!DateAndTime methodsFor: 'squeak protocol' stamp: 'dtl 10/31/2004 01:20'!
printOn: aStream withLeadingSpace: printLeadingSpaceToo
	"Print as per ISO 8601 sections 5.3.3 and 5.4.1.
	If printLeadingSpaceToo is false, prints either:
		'YYYY-MM-DDThh:mm:ss.s+ZZ:zz:z' (for positive years) or '-YYYY-MM-DDThh:mm:ss.s+ZZ:zz:z' (for negative years)
	If printLeadingSpaceToo is true, prints either:
		' YYYY-MM-DDThh:mm:ss.s+ZZ:zz:z' (for positive years) or '-YYYY-MM-DDThh:mm:ss.s+ZZ:zz:z' (for negative years)
	"

	self printYMDOn: aStream withLeadingSpace: printLeadingSpaceToo.
	aStream nextPut: $T.
	self printHMSOn: aStream.
	self nanoSecond ~= 0 ifTrue:
		[ | z ps |
		ps := self nanoSecond printString padded: #left to: 9 with: $0.
		z := ps findLast: [ :c | c asciiValue > $0 asciiValue ].
		(z > 0) ifTrue: [aStream nextPut: $.].
		ps from: 1 to: z do: [ :c | aStream nextPut: c ] ].
	aStream
		nextPut: (offset positive ifTrue: [$+] ifFalse: [$-]);
		nextPutAll: (offset hours abs asString padded: #left to: 2 with: $0);
		nextPut: $:;
		nextPutAll: (offset minutes abs asString padded: #left to: 2 with: $0).
	offset seconds = 0 ifFalse:
		[ aStream
			nextPut: $:;
			nextPutAll: (offset seconds abs truncated asString) ].
! !

!DateAndTime methodsFor: 'squeak protocol' stamp: 'kph 10/13/2006 04:33'!
setJdn: j seconds: s nano: n offset: o

jdn := j.
seconds := s.
nanos :=  n.
offset :=  o
! !

!DateAndTime methodsFor: 'private' stamp: 'brp 7/28/2004 16:22'!
hasEqualTicks: aDateAndTime
	
	^ (jdn = aDateAndTime julianDayNumber)
		and: [ (seconds = aDateAndTime secondsSinceMidnight)
			and: [ nanos = aDateAndTime nanoSecond ] ]

! !

!DateAndTime methodsFor: 'private' stamp: 'brp 7/28/2004 16:20'!
secondsSinceMidnight

	^ seconds! !


!DateAndTime class methodsFor: 'ansi protocol' stamp: 'KLC 5/9/2008 20:13'!
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: 'squeak protocol' stamp: 'kph 10/20/2007 13:56'!
milliSecondsSinceMidnight
	
	| msm msClock |
	
	msClock := self millisecondClockValue. 

	(
msClock < LastMilliSeconds) 
		ifTrue:[ "rolled over" MilliSecondOffset := MilliSecondOffset + (SmallInteger maxVal // 2) + 1 ].

	LastMilliSeconds := msClock.

	[ msm := msClock + MilliSecondOffset.
 	 (msm >= 86400000) ] 
		whileTrue: [ "next day" 
			LastTick := -1.
			DaysSinceEpoch := DaysSinceEpoch + 1. 
			MilliSecondOffset := MilliSecondOffset - 86400000 ].

	"day rolled over sanity check"
	((LastTick = -1) and: [
		(Duration days: SqueakEpoch hours: 0 minutes: 0 seconds: 								(self clock totalSeconds)) days ~= DaysSinceEpoch ]) 
		ifTrue: 
				[  self initializeOffsets. 
				 ^ self milliSecondsSinceMidnight ].
		
^msm



! !

!DateAndTime class methodsFor: 'squeak protocol' stamp: 'tfel 9/1/2009 22:29'!
readFrom: aStream

	| offset date time ch |

	date := Date readFrom: aStream.
	[aStream peek isDigit]
		whileFalse: [aStream next].
	time := Time readFrom: aStream.
	aStream atEnd
		ifTrue: [ offset := self localOffset ]
		ifFalse: [
			ch := aStream next.
			ch = $+ ifTrue: [ch := Character space].
			offset := Duration fromString: ch asString, '0:', aStream upToEnd, ':0'].
		
	^ self
		year: date year
		month: date monthIndex
		day: date dayOfMonth
		hour: time hour
		minute: time minute
		second: time second
		nanoSecond: time nanoSecond
		offset: offset


	"	'-1199-01-05T20:33:14.321-05:00' asDateAndTime
		' 2002-05-16T17:20:45.1+01:01' asDateAndTime

		' 2002-05-16T17:20:45.02+01:01' asDateAndTime

		' 2002-05-16T17:20:45.003+01:01' asDateAndTime

		' 2002-05-16T17:20:45.0004+01:01' asDateAndTime
  		' 2002-05-16T17:20:45.00005' asDateAndTime
		' 2002-05-16T17:20:45.000006+01:01' asDateAndTime

		' 2002-05-16T17:20:45.0000007+01:01' asDateAndTime
		' 2002-05-16T17:20:45.00000008-01:01' asDateAndTime   
		' 2002-05-16T17:20:45.000000009+01:01' asDateAndTime  
		' 2002-05-16T17:20:45.0000000001+01:01' asDateAndTime  

 		' 2002-05-16T17:20' asDateAndTime
		' 2002-05-16T17:20:45' asDateAndTime
		' 2002-05-16T17:20:45+01:57' asDateAndTime
 		' 2002-05-16T17:20:45-02:34' asDateAndTime
 		' 2002-05-16T17:20:45+00:00' asDateAndTime
		' 1997-04-26T01:02:03+01:02:3' asDateAndTime 
 	"! !

!DateAndTime class methodsFor: 'squeak protocol' stamp: 'kph 12/11/2006 20:36'!
todayAtMilliSeconds: milliSecondsSinceMidnight

	 ^ self basicNew
			setJdn: DaysSinceEpoch 
			seconds: (milliSecondsSinceMidnight // 1000) 
			nano: (milliSecondsSinceMidnight  \\ 1000 * 1000000  ) 
			offset: self localOffset
	 
" 
[ 100000 timesRepeat: [ self fromMilliSeconds: self milliSecondsSinceMidnight. ] ] timeToRun.    
"! !

!DateAndTime class methodsFor: 'squeak protocol' stamp: 'kph 12/11/2006 20:36'!
todayAtNanoSeconds: nanoSecondsSinceMidnight

	^ self basicNew
			setJdn: DaysSinceEpoch 
			seconds: (nanoSecondsSinceMidnight // 1000000000) 
			nano: (nanoSecondsSinceMidnight  \\ 1000000000  ) 
			offset: self localOffset
 ! !

!DateAndTime class methodsFor: 'squeak protocol' stamp: 'ul 10/15/2009 00:58'!
year: year month: month day: day hour: hour minute: minute second: second nanoSecond: nanoCount offset: offset
	"Return a DateAndTime"

	| monthIndex daysInMonth p q r s julianDayNumber |

	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 ).

	^self basicNew
		setJdn: julianDayNumber 
		seconds: hour * 60 + minute * 60 + second
		nano: nanoCount
		offset: offset;
		yourself! !

!DateAndTime class methodsFor: 'smalltalk-80' stamp: 'kph 12/11/2006 21:13'!
millisecondClockValue

	^ self clock millisecondClockValue! !

!DateAndTime class methodsFor: 'smalltalk-80' stamp: 'kph 12/9/2006 23:46'!
totalSeconds

	^ self clock totalSeconds! !

!DateAndTime class methodsFor: 'clock provider' stamp: 'kph 12/11/2006 20:14'!
clock 
	 "the provider of real time seconds/milliseconds."

	^ ClockProvider ! !

!DateAndTime class methodsFor: 'initialize-release' stamp: 'dtl 7/13/2009 13:08'!
initialize

	super initialize.

	ClockProvider := Time.
	LastTickSemaphore := Semaphore forMutualExclusion.
	LastMilliSeconds := 0.
	LastTick := 0.
	Smalltalk addToStartUpList: self.
	self startUp: true
! !

!DateAndTime class methodsFor: 'initialize-release' stamp: 'dtl 7/13/2009 13:08'!
initializeOffsets 

	| epochianSeconds secondsSinceMidnight nowSecs  |
	 
 	LastTick := 0.
  
	nowSecs :=  self clock secondsWhenClockTicks.
	LastMilliSeconds := self millisecondClockValue. 

	epochianSeconds := Duration days: SqueakEpoch hours: 0 minutes: 0 seconds: nowSecs.

	DaysSinceEpoch := epochianSeconds days.

	secondsSinceMidnight := (epochianSeconds - (Duration days: DaysSinceEpoch hours: 0 minutes: 0 seconds: 0)) asSeconds.  

	MilliSecondOffset := (secondsSinceMidnight * 1000 - LastMilliSeconds)
! !

!DateAndTime class methodsFor: 'initialize-release' stamp: 'kph 12/13/2006 21:46'!
startUp: resuming 

	resuming ifFalse: [^ self].
	
	[ self initializeOffsets ] fork.
	
! !


!Duration methodsFor: 'ansi protocol' stamp: 'KLC 5/12/2008 13:42'!
seconds
	"Answer the number of seconds the receiver represents."

	^seconds rem: SecondsInMinute! !


!Duration class methodsFor: 'squeak protocol' stamp: 'jmv 11/4/2009 11:29'!
fromString: aString
	"
	Extended to accept non-ANSI formats, such as:
		Duration fromString: '1:50:00'
		Duration fromString: '5:30.5'
		Duration fromString: '1:6:50:00'
		Duration fromString: '3.5h'
		Duration fromString: '2.5min'
		Duration fromString: '1.5s'
		Duration fromString: '200ms'
	"
	| colons s |

	"If aString includes at least one $:, complete ANSI format"
	colons _ aString occurrencesOf: $:.
	colons > 0 ifTrue: [
		s _ aString.
		[colons < 3] whileTrue: [
			s _ '00:', s.
			colons _ colons + 1 ].
		^ self readFrom: (ReadStream on: s) ].

	"'3.5h' means 3.5 hours"
	(aString endsWith: 'h') ifTrue: [
		^self hours: aString asNumber ].

	"'3.5min' means 3.5 minutes"
	(aString endsWith: 'min') ifTrue: [
		^self minutes: aString asNumber ].

	"'3.5s' means 3.5 seconds"
	(aString endsWith: 's') ifTrue: [
		^self seconds: aString asNumber ].

	"'3ms' means 3 milliseconds"
	(aString endsWith: 'ms') ifTrue: [
		^self milliSeconds: aString asNumber ].
	
	^nil! !

!Duration class methodsFor: 'squeak protocol' stamp: 'tfel 9/1/2009 22:29'!
readFrom: aStream
	"Formatted as per ANSI 5.8.2.16: [-]D:HH:MM:SS[.S]"

	| sign days hours minutes seconds nanos nanosBuffer |
	sign := (aStream peekFor: $-) ifTrue: [-1] ifFalse: [1].
	days := (aStream upTo: $:) asInteger sign: sign.
	hours := (aStream upTo: $:) asInteger sign: sign.
	minutes := (aStream upTo: $:) asInteger sign: sign.
	seconds := (aStream upTo: $.) asInteger sign: sign.
	nanosBuffer := '000000000' copy.
	nanos := WriteStream on: nanosBuffer.
	[aStream atEnd not and: [aStream peek isDigit]]
		whileTrue: [nanos nextPut: aStream next].
		
	^ self 
		days: days 
		hours: hours 
		minutes: minutes 
		seconds: seconds 
		nanoSeconds: (nanosBuffer asInteger sign: sign)

	"	'0:00:00:00' asDuration
		'0:00:00:00.000000001' asDuration
		'0:00:00:00.999999999' asDuration
		'0:00:00:00.100000000' asDuration
		'0:00:00:00.001 ' asDuration
		'0:00:00:00.1' asDuration
		'0:00:00:01 ' asDuration
		'0:12:45:45' asDuration
		'1:00:00:00' asDuration
		'365:00:00:00' asDuration
		'-7:09:12:06.10' asDuration
		'+0:01:02:3' asDuration
 	"! !


!MethodFinder methodsFor: 'initialize' stamp: 'jmv 11/3/2009 14:26'!
initialize
	"The methods we are allowed to use.  (MethodFinder new initialize) "

	Approved _ Set new.
	AddAndRemove _ Set new.
	Blocks _ Set new.
	"These modify an argument and are not used by the MethodFinder: longPrintOn: printOn: storeOn: sentTo: storeOn:base: printOn:base: absPrintExactlyOn:base: absPrintOn:base: absPrintOn:base:digitCount: writeOn: writeScanOn: possibleVariablesFor:continuedFrom: printOn:format:"

"Object"  
	#("in class, instance creation" initialInstance  newFrom: readCarefullyFrom:
"accessing" at: basicAt: basicSize size yourself 
"testing" ifNil: ifNil:ifNotNil: ifNotNil: ifNotNil:ifNil: isColor isFloat isFraction isInMemory isInteger isMorph isNil isNumber isPoint isPseudoContext isText isTransparent isWebBrowser notNil pointsTo: wantsSteps 
"comparing" = == closeTo: hash identityHash identityHashPrintString ~= ~~ 
"copying" clone copy shallowCopy 
"dependents access" canDiscardEdits dependents hasUnacceptedEdits 
"updating" changed changed: okToChange update: windowIsClosing 
"printing" fullPrintString isLiteral longPrintString printString storeString stringForReadout stringRepresentation 
"class membership" class isKindOf: isKindOf:orOf: isMemberOf: respondsTo: xxxClass 
"error handling" 
"user interface" defaultLabelForInspector initialExtent modelWakeUp 
"system primitives" instVarAt: instVarNamed: 
"private" 
"associating" -> 
"converting" as: asOrderedCollection asString 
"casing" caseOf: caseOf:otherwise: 
"binding" bindingOf: 
"macpal" contentsChanged currentEvent currentHand currentWorld flash ifKindOf:thenDo: instanceVariableValues 
"flagging" flag: 
"translation support" "objects from disk" "finalization" ) do: [:sel | Approved add: sel].
	#(at:add: at:modify: at:put: basicAt:put: "NOT instVar:at:"
"message handling" perform: perform:orSendTo: perform:with: perform:with:with: perform:with:with:with: perform:withArguments: perform:withArguments:inSuperclass: 
) do: [:sel | AddAndRemove add: sel].

"Boolean, True, False, UndefinedObject"  
	#("logical operations" & eqv: not xor: |
"controlling" and: ifFalse: ifFalse:ifTrue: ifTrue: ifTrue:ifFalse: or:
"copying" 
"testing" isEmptyOrNil) do: [:sel | Approved add: sel].

"Behavior" 
	#("initialize-release"
"accessing" compilerClass decompilerClass evaluatorClass format methodDict parserClass sourceCodeTemplate subclassDefinerClass
"testing" instSize instSpec isBits isBytes isFixed isPointers isVariable isWeak isWords
"copying"
"printing" printHierarchy
"creating class hierarchy"
"creating method dictionary"
"instance creation" basicNew basicNew: new new:
"accessing class hierarchy" allSubclasses allSubclassesWithLevelDo:startingLevel: allSuperclasses subclasses superclass withAllSubclasses withAllSuperclasses
"accessing method dictionary" allSelectors changeRecordsAt: compiledMethodAt: compiledMethodAt:ifAbsent: firstCommentAt: lookupSelector: selectors selectorsDo: selectorsWithArgs: "slow but useful ->" sourceCodeAt: sourceCodeAt:ifAbsent: sourceMethodAt: sourceMethodAt:ifAbsent:
"accessing instances and variables" allClassVarNames allInstVarNames allSharedPools classVarNames instVarNames instanceCount sharedPools someInstance subclassInstVarNames
"testing class hierarchy" inheritsFrom: kindOfSubclass
"testing method dictionary" canUnderstand: classThatUnderstands: hasMethods includesSelector: scopeHas:ifTrue: whichClassIncludesSelector: whichSelectorsAccess: whichSelectorsReferTo: whichSelectorsReferTo:special:byte: whichSelectorsStoreInto:
"enumerating"
"user interface"
"private" indexIfCompact) do: [:sel | Approved add: sel].

"ClassDescription"
	#("initialize-release" 
"accessing" classVersion isMeta name theNonMetaClass
"copying" 
"printing" classVariablesString instanceVariablesString sharedPoolsString
"instance variables" checkForInstVarsOK: 
"method dictionary" 
"organization" category organization whichCategoryIncludesSelector:
"compiling" acceptsLoggingOfCompilation wantsChangeSetLogging
"fileIn/Out" definition
"private" ) do: [:sel | Approved add: sel].

"Class"
	#("initialize-release" 
"accessing" classPool
"testing"
"copying" 
"class name" 
"instance variables" 
"class variables" classVarAt: classVariableAssociationAt:
"pool variables" 
"compiling" 
"subclass creation" 
"fileIn/Out" ) do: [:sel | Approved add: sel]. 

"Metaclass"
	#("initialize-release" 
"accessing" soleInstance
"copying" "instance creation" "instance variables"  "pool variables" "class hierarchy"  "compiling"
"fileIn/Out"  nonTrivial ) do: [:sel | Approved add: sel].

"Context, BlockContext"
	#(receiver client method receiver tempAt: 
"debugger access" mclass pc selector sender shortStack sourceCode tempNames tempsAndValues
"controlling"  "printing" "system simulation" 
"initialize-release" 
"accessing" hasMethodReturn home numArgs
"evaluating" value value:ifError: value:value: value:value:value: value:value:value:value: valueWithArguments:
"controlling"  "scheduling"  "instruction decoding"  "printing" "private"  "system simulation" ) do: [:sel | Approved add: sel].
	#(value: "<- Association has it as a store" ) do: [:sel | AddAndRemove add: sel].

"Message"
	#("inclass, instance creation" selector: selector:argument: selector:arguments:
"accessing" argument argument: arguments sends:
"printing" "sending" ) do: [:sel | Approved add: sel].
	#("private" setSelector:arguments:) do: [:sel | AddAndRemove add: sel].

"Magnitude"
	#("comparing" < <= > >= between:and:
"testing" max: min: min:max: ) do: [:sel | Approved add: sel].

"Date, Time"
	#("in class, instance creation" fromDays: fromSeconds: fromString: newDay:month:year: newDay:year: today
	"in class, general inquiries" dateAndTimeNow dayOfWeek: daysInMonth:forYear: daysInYear: firstWeekdayOfMonth:year: indexOfMonth: leapYear: nameOfDay: nameOfMonth:
"accessing" day leap monthIndex monthName weekday year
"arithmetic" addDays: subtractDate: subtractDays:
"comparing"
"inquiries" dayOfMonth daysInMonth daysInYear daysLeftInYear firstDayOfMonth previous:
"converting" asSeconds
"printing" mmddyyyy printFormat: 
"private" weekdayIndex 
	"in class, instance creation" fromSeconds: now 
	"in class, general inquiries" dateAndTimeFromSeconds: dateAndTimeNow millisecondClockValue millisecondsToRun: totalSeconds
"accessing" hours minutes seconds
"arithmetic" addTime: subtractTime:
"comparing"
"printing" intervalString print24 
"converting") do: [:sel | Approved add: sel].
	#("private" hours:  ) do: [:sel | AddAndRemove add: sel].

"Number"
	#("in class" readFrom:base: 
"arithmetic" * + - / // \\ abs negated quo: reciprocal rem:
"mathematical functions" arcCos arcSin arcTan arcTan: cos exp floorLog: ln log log: raisedTo: raisedToInteger: sin sqrt squared tan
"truncation and round off" ceiling detentBy:atMultiplesOf:snap: floor roundTo: roundUpTo: rounded truncateTo: truncated
"comparing"
"testing" even isDivisibleBy: isInf isInfinite isNaN isZero negative odd positive sign strictlyPositive
"converting" @ asInteger asNumber asPoint asSmallAngleDegrees degreesToRadians radiansToDegrees
"intervals" to: to:by: 
"printing" printStringBase: storeStringBase: ) do: [:sel | Approved add: sel].

"Integer"
	#("in class" primesUpTo:
"testing" isPowerOfTwo
"arithmetic" alignedTo:
"comparing"
"truncation and round off" atRandom normalize
"enumerating" timesRepeat:
"mathematical functions" degreeCos degreeSin factorial gcd: lcm: take:
"bit manipulation" << >> allMask: anyMask: bitAnd: bitClear: bitInvert bitInvert32 bitOr: bitShift: bitXor: lowBit noMask:
"converting" asCharacter asColorOfDepth: asFloat asFraction asHexDigit
"printing" asStringWithCommas hex hex8 radix:
"system primitives" lastDigit replaceFrom:to:with:startingAt:
"private" "benchmarks" ) do: [:sel | Approved add: sel].

"SmallInteger, LargeNegativeInteger, LargePositiveInteger"
	#("arithmetic" "bit manipulation" highBit "testing" "comparing" "copying" "converting" "printing" 
"system primitives" digitAt: digitLength 
"private" fromString:radix: ) do: [:sel | Approved add: sel].
	#(digitAt:put: ) do: [:sel | AddAndRemove add: sel].

"Float"
	#("arithmetic"
"mathematical functions" reciprocalFloorLog: reciprocalLogBase2 timesTwoPower:
"comparing" "testing"
"truncation and round off" exponent fractionPart integerPart significand significandAsInteger
"converting" asApproximateFraction asIEEE32BitWord asTrueFraction
"copying") do: [:sel | Approved add: sel].

"Fraction, Random"
	#(denominator numerator reduced next nextValue) do: [:sel | Approved add: sel].
	#(setNumerator:denominator:) do: [:sel | AddAndRemove add: sel].

"Collection"
	#("accessing" anyOne
"testing" includes: includesAllOf: includesAnyOf: includesSubstringAnywhere: isEmpty isSequenceable occurrencesOf:
"enumerating" collect: collect:thenSelect: count: detect: detect:ifNone: detectMax: detectMin: detectSum: inject:into: reject: select: select:thenCollect:
"converting" asBag asCharacterSet asSet asSortedArray asSortedCollection asSortedCollection:
"printing"
"private" maxSize
"arithmetic"
"math functions" average max median min range sum) do: [:sel | Approved add: sel].
	#("adding" add: addAll: addIfNotPresent:
"removing" remove: remove:ifAbsent: removeAll: removeAllFoundIn: removeAllSuchThat: remove:ifAbsent:) do: [:sel | AddAndRemove add: sel].

"SequenceableCollection"
	#("comparing" hasEqualElements:
"accessing" allButFirst allButLast at:ifAbsent: atAll: atPin: atRandom: atWrap: fifth first fourth identityIndexOf: identityIndexOf:ifAbsent: indexOf: indexOf:ifAbsent: indexOf:startingAt:ifAbsent: indexOfSubCollection:startingAt: indexOfSubCollection:startingAt:ifAbsent: last second sixth third
"removing"
"copying" , copyAfterLast: copyAt:put: copyFrom:to: copyReplaceAll:with: copyReplaceFrom:to:with: copyUpTo: copyUpToLast: copyWith: copyWithout: copyWithoutAll: forceTo:paddingWith: shuffled sortBy:
"enumerating" collectWithIndex: findFirst: findLast: pairsCollect: with:collect: withIndexCollect: polynomialEval:
"converting" asArray asDictionary asFloatArray asIntegerArray asStringWithCr asWordArray reversed
"private" copyReplaceAll:with:asTokens: ) do: [:sel | Approved add: sel].
	#( swap:with:) do: [:sel | AddAndRemove add: sel].

"ArrayedCollection, Bag"
	#("private" defaultElement 
"sorting" isSorted
"accessing" cumulativeCounts sortedCounts sortedElements "testing" "adding" add:withOccurrences: "removing" "enumerating" 
	) do: [:sel | Approved add: sel].
	#( mergeSortFrom:to:by: sort sort: add: add:withOccurrences:
"private" setDictionary ) do: [:sel | AddAndRemove add: sel].

"Other messages that modify the receiver"
	#(atAll:put: atAll:putAll: atAllPut: atWrap:put: replaceAll:with: replaceFrom:to:with:  removeFirst removeLast) do: [:sel | AddAndRemove add: sel].

	self initialize2.

"
MethodFinder new initialize.
MethodFinder new organizationFiltered: Set
"
! !


!Time class methodsFor: 'benchmarks' stamp: 'brp 8/24/2003 00:06'!
benchmarkMillisecondClock		"Time benchmarkMillisecondClock"

	"Benchmark the time spent in a call to Time>>millisecondClockValue.

	On the VM level this tests the efficiency of calls to ioMSecs()."

	"PII/400 Windows 98: 0.725 microseconds per call"

	| temp1 temp2 temp3 delayTime nLoops time |

	delayTime := 5000. "Time to run benchmark is approx. 2*delayTime"



	"Don't run the benchmark if we have an active delay since

	we will measure the additional penalty in the primitive dispatch

	mechanism (see #benchmarkPrimitiveResponseDelay)."

	Delay anyActive ifTrue:[

		^self notify:'Some delay is currently active.

Running this benchmark will not give any useful result.'].



	"Flush the cache for this benchmark so we will have

	a clear cache hit for each send to #millisecondClockValue below"

	Object flushCache.

	temp1 := 0.

	temp2 := self. "e.g., temp1 == Time"

	temp3 := self millisecondClockValue + delayTime.



	"Now check how often we can run the following loop in the given time"

	[temp2 millisecondClockValue < temp3]

		whileTrue:[temp1 := temp1 + 1].



	nLoops := temp1. "Remember the loops we have run during delayTime"



	"Setup the second loop"

	temp1 := 0.

	temp3 := nLoops.



	"Now measure how much time we spend without sending #millisecondClockValue"

	time := Time millisecondClockValue.

	[temp1 < temp3]

		whileTrue:[temp1 := temp1 + 1].

	time := Time millisecondClockValue - time.



	"And compute the number of microseconds spent per call to #millisecondClockValue"

	^((delayTime - time * 1000.0 / nLoops) truncateTo: 0.001) printString,

		' microseconds per call to Time>>millisecondClockValue'
! !

!Time class methodsFor: 'benchmarks' stamp: 'BP 3/30/2001 15:25'!
benchmarkPrimitiveResponseDelay	"Time benchmarkPrimitiveResponseDelay"

	"Benchmark the overhead for primitive dispatches with an active Delay.

	On the VM level, this tests the efficiency of ioLowResMSecs."



	"PII/400 Windows98: 0.128 microseconds per prim"



	"ar 9/6/1999: This value is *extremely* important for stuff like sockets etc.

	I had a bad surprise when Michael pointed this particular problem out:

	Using the hardcoded clock() call for ioLowResMSecs on Win32 resulted in an overhead

	of 157.4 microseconds per primitive call - meaning you can't get no more than

	approx. 6000 primitives per second on my 400Mhz PII system with an active delay!!

	BTW, it finally explains why Squeak seemed soooo slow when running PWS or 

	other socket stuff. The new version (not using clock() but some Windows function) 

	looks a lot better (see above; approx. 8,000,000 prims per sec with an active delay)."



	| nLoops bb index baseTime actualTime delayTime |

	delayTime := 5000. "Time to run this test is approx. 3*delayTime"



	Delay anyActive ifTrue:[

		^self notify:'Some delay is currently active.

Running this benchmark will not give any useful result.'].



	bb := Array new: 1. "The object we send the prim message to"



	"Compute the # of loops we'll run in a decent amount of time"

	[(Delay forMilliseconds: delayTime) wait] 

		forkAt: Processor userInterruptPriority.



	nLoops := 0.

	[Delay anyActive] whileTrue:[

		bb basicSize; basicSize; basicSize; basicSize; basicSize; 

			basicSize; basicSize; basicSize; basicSize; basicSize.

		nLoops := nLoops + 1.

	].



	"Flush the cache and make sure #basicSize is in there"

	Object flushCache.

	bb basicSize.



	"Now run the loop without any active delay

	for getting an idea about its actual speed."

	baseTime := self millisecondClockValue.

	index := nLoops.

	[index > 0] whileTrue:[

		bb basicSize; basicSize; basicSize; basicSize; basicSize; 

			basicSize; basicSize; basicSize; basicSize; basicSize.

		index := index - 1.

	].

	baseTime := self millisecondClockValue - baseTime.



	"Setup the active delay but try to never make it active"

	[(Delay forMilliseconds: delayTime + delayTime) wait] 

		forkAt: Processor userInterruptPriority.



	"And run the loop"

	actualTime := self millisecondClockValue.

	index := nLoops.

	[index > 0] whileTrue:[

		bb basicSize; basicSize; basicSize; basicSize; basicSize; 

			basicSize; basicSize; basicSize; basicSize; basicSize.

		index := index - 1.

	].

	actualTime := self millisecondClockValue - actualTime.



	"And get us some result"

	^((actualTime - baseTime) * 1000 asFloat / (nLoops * 10) truncateTo: 0.001) printString,

		' microseconds overhead per primitive call'
! !

!Time class methodsFor: 'general inquiries' stamp: 'ar 11/25/2004 11:26'!
millisecondsToRun: timedBlock 
	"Answer the number of milliseconds timedBlock takes to return its value."

	| initialMilliseconds |
	initialMilliseconds := self millisecondClockValue.
	timedBlock value.
	^self millisecondsSince: initialMilliseconds! !

!Time class methodsFor: 'smalltalk-80' stamp: 'tfel 9/1/2009 22:51'!
readFrom: aStream
	"Read a Time from the stream in the form:
		<hour>:<minute>:<second> <am/pm>

	<minute>, <second> or <am/pm> may be omitted.  e.g. 1:59:30 pm; 8AM; 15:30"

	| hour minute second ampm nanos nanosBuffer |
	hour := Integer readFrom: aStream.
	minute := 0.
	second := 0.
	nanosBuffer := '000000000' copy.
	nanos := WriteStream on: nanosBuffer.
	(aStream peekFor: $:) 
		ifTrue: [
			minute := Integer readFrom: aStream.
			(aStream peekFor: $:) 
				ifTrue: [
					second := Integer readFrom: aStream].
					(aStream peekFor: $.)
						ifTrue: [
							[aStream atEnd not and: [aStream peek isDigit]]
								whileTrue: [nanos nextPut: aStream next]]].
	aStream skipSeparators.
	(aStream atEnd not and: [aStream peek isLetter]) ifTrue: 
		[ampm := aStream next asLowercase.
	
	(ampm = $p and: [hour < 12]) ifTrue: [hour := hour + 12].
		(ampm = $a and: [hour = 12]) ifTrue: [hour := 0].
	
	(aStream peekFor: $m) ifFalse: [aStream peekFor: $M ]].
	^ self 
		hour: hour 
		minute: minute 
		second: second 
		nanoSecond: nanosBuffer asInteger

	"Time readFrom: (ReadStream on: '2:23:09 pm')"! !

!Time class methodsFor: 'ansi protocol' stamp: 'kph 12/9/2006 10:17'!
milliSecondsSinceMidnight
	
^ DateAndTime milliSecondsSinceMidnight! !

!Time class methodsFor: 'ansi protocol' stamp: 'kph 12/9/2006 10:18'!
now
	"Answer a Time representing the time right now - this is a 24 hour clock."

	| ms |
	
	ms := self milliSecondsSinceMidnight.

	^ self seconds:  (ms // 1000) nanoSeconds: (ms \\ 1000) * 1000000


! !

!Time class methodsFor: 'clock' stamp: 'kph 12/14/2006 01:43'!
secondsWhenClockTicks

	"waits for the moment when a new second begins"

	| lastSecond delay |

	delay :=  Delay forMilliseconds: 1.
	lastSecond := self primSecondsClock.
	[ lastSecond = self primSecondsClock ] whileTrue: [ delay wait ].
 
	^ lastSecond + 1! !

!Time class methodsFor: '*monticello' stamp: 'nk 11/2/2003 10:51'!
fromString: aString
	^ self readFrom: (ReadStream on: aString).
! !


!TimeStamp class methodsFor: '*monticello-instance creation' stamp: 'stephaneducasse 2/4/2006 20:47'!
fromMethodTimeStamp: aString
	| stream |
	stream := ReadStream on: aString.
	stream skipSeparators.
	stream skipTo: Character space.
	^self readFrom: stream.! !

!TimeStamp class methodsFor: '*monticello-instance creation' stamp: 'stephaneducasse 2/4/2006 20:47'!
readFrom: stream
	| date time |
	stream skipSeparators.
	date := Date readFrom: stream.
	stream skipSeparators.
	time := Time readFrom: stream.
	^self 
		date: date
		time: time! !

!TimeStamp class methodsFor: 'squeak protocol' stamp: 'dtl 7/13/2009 13:45'!
current

	| ts ticks |
	ts := super now asTimeStamp.
	ticks := ts ticks.
	ticks at: 3 put: 0.
	ts ticks: ticks offset: ts offset.
	^ ts
! !

!TimeStamp class methodsFor: 'ansi protocol' stamp: 'fbs 4/20/2004 14:22'!
now
	"Answer the current date and time as a TimeStamp."

	^self current! !


!TimeZone class methodsFor: 'accessing' stamp: 'brp 1/30/2005 09:35'!
timeZones

	^ {
		self offset:  0 hours name: 'Universal Time' abbreviation: 'UTC'.
		self offset:  0 hours name: 'Greenwich Mean Time' abbreviation: 'GMT'.
		self offset:  1 hours name: 'British Summer Time' abbreviation: 'BST'.
		self offset:  2 hours name: 'South African Standard Time' abbreviation: 'SAST'.
		self offset: -8 hours name: 'Pacific Standard Time' abbreviation: 'PST'.
		self offset: -7 hours name: 'Pacific Daylight Time' abbreviation: 'PDT'.
	}

! !


!Timespan methodsFor: 'ansi protocol' stamp: 'lr 4/18/2005 16:39'!
= comparand
	^ self class = comparand class 
		and: [ self start = comparand start ]
		and: [ self duration = comparand duration ]
.! !

!Timespan methodsFor: 'squeak protocol' stamp: 'brp 9/23/2004 09:53'!
end


	^ self duration asNanoSeconds = 0
		ifTrue: [ self start ]
		ifFalse: [ self next start - DateAndTime clockPrecision ]
! !


!Date methodsFor: 'utils' stamp: 'tbn 7/11/2006 10:30'!
addMonths: monthCount 
	|year month maxDaysInMonth day |
	year := self year + (monthCount + self monthIndex - 1 // 12).
	month := self monthIndex + monthCount - 1 \\ 12 + 1.
	maxDaysInMonth := Month daysInMonth: month forYear: year.
	day := self dayOfMonth > maxDaysInMonth
				ifTrue: [maxDaysInMonth]
				ifFalse: [self dayOfMonth].
	^ Date
		newDay: day
		month: month
		year: year! !

!Date methodsFor: 'utils' stamp: 'spfa 3/8/2004 13:52'!
onNextMonth

	^ self addMonths: 1
! !

!Date methodsFor: 'utils' stamp: 'spfa 3/8/2004 13:52'!
onPreviousMonth

	^ self addMonths: -1
! !


!Schedule methodsFor: 'enumerating' stamp: 'jmv 11/3/2009 14:32'!
between: aStart and: anEnd do: aBlock

	| element end i startDate |
	end _ self end min: anEnd.
	element _ self start.
	
	"Performance optimization. Avoid going through unnecesary days if easy."
	startDate _ aStart asDate.
	(startDate > element asDate and: [ self everyDayAtSameTimes ]) ifTrue: [
		element _ DateAndTime date: startDate time: element asTime ].

	i _ 1.
	[ element < aStart ] whileTrue: [
		element _ element + (schedule at: i).
		i _ i + 1.
		i > schedule size ifTrue: [i _ 1]].
	i _ 1.
	[ element <= end ] whileTrue: [
		aBlock value: element.
		element _ element + (schedule at: i).
		i _ i + 1.
		i > schedule size ifTrue: [i _ 1]]! !


!Date class methodsFor: 'squeak protocol' stamp: 'tfel 9/1/2009 07:08'!
readFrom: aStream 
	"Read a Date from the stream in any of the forms:  
		<day> <month> <year>		(15 April 1982; 15-APR-82; 15.4.82; 15APR82)  
		<month> <day> <year>		(April 15, 1982; 4/15/82)
		<year>-<month>-<day>			(1982-04-15) (ISO8601)"
	| day month year parsedNumber prefix |
	aStream peek = $-
		ifTrue: [prefix := -1]
		ifFalse: [prefix := 1].
	[aStream peek isAlphaNumeric]
		whileFalse: [aStream skip: 1].
	aStream peek isDigit
		ifTrue: [
			parsedNumber := (Integer readFrom: aStream) * prefix.
			(parsedNumber < 0 or: [parsedNumber > 31])
				ifTrue: [year := parsedNumber]].
	[aStream peek isAlphaNumeric]
		whileFalse: [aStream skip: 1].
	aStream peek isLetter
		ifTrue: ["MM-DD-YY or DD-MM-YY or YY-MM-DD"
			month := WriteStream on: (String new: 10).
			[aStream peek isLetter]
				whileTrue: [month nextPut: aStream next].
			month := month contents.
			[aStream peek isAlphaNumeric]
				whileFalse: [aStream skip: 1].
			parsedNumber isNil
				ifTrue: ["MM DD YY"
					day := Integer readFrom: aStream]
				ifFalse: [
					year isNil
						ifTrue: ["DD MM YY"
							day := parsedNumber]]]
		ifFalse: ["MM-DD-YY or DD-MM-YY or YY-MM-DD"
			year isNil 
				ifTrue: ["MM-DD-YY or DD-MM-YY"
					parsedNumber > 12
						ifTrue: ["DD-MM-YY"
							day := parsedNumber.
							month := Month nameOfMonth: (Integer readFrom: aStream)]
						ifFalse: ["MM-DD-YY"
							month := Month nameOfMonth: parsedNumber.
							day := Integer readFrom: aStream]]
				ifFalse: ["YY-MM-DD"
					month := Month nameOfMonth: (Integer readFrom: aStream)]].
	[aStream peek isAlphaNumeric]
		whileFalse: [aStream skip: 1].
	year isNil
		ifTrue: [year := Integer readFrom: aStream]
		ifFalse: [day := Integer readFrom: aStream].
	(year < 100 and: [year >= 0]) 
		ifTrue: [
			year < 69 
				ifTrue: [	year := 2000 + year]
				ifFalse: [year := 1900 + year]].

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

!Date class methodsFor: 'general inquiries' stamp: 'BG 3/16/2005 14:57'!
easterDateFor: year

 "  compute the easter date.
    source: Physikalisch-Technische Bundesanstalt Braunschweig.
    Lichtenberg, H.: Zur Interpretation der Gaussschen Osterformel
                     und ihrer Ausnahmeregeln,
                     Historia Mathematica 24 (1997), pp. 441-444
  
    http://www.ptb.de/de/org/4/44/441/oste.htm
  "

  | k m s a d r og sz oe day |

  k := year // 100.
  m := 15 + (3*k + 3//4) - (8*k + 13//25).
   s := 2 - (3*k + 3// 4).
  a := year \\ 19.
  d := 19*a + m \\ 30.
  r := d//29 + ((d//28) - (d//29)* (a// 11)).

  og := 21 + d - r.
  sz := 7 - (year//4 + year + s\\7).
  oe := 7 - (og - sz\\7).
  day := og + oe.
  ^day <= 31
    ifTrue: [Date newDay: day month: 3 year: year ]
    ifFalse: [Date newDay: day - 31 month: 4 year: year].! !

!Date class methodsFor: 'general inquiries' stamp: 'BG 3/16/2005 14:48'!
orthodoxEasterDateFor: year

 "  compute the easter date according to the rules of the orthodox calendar.
    source: 
    http://www.smart.net/~mmontes/ortheast.html 
  "
     | r1 r2 r3 r4 ra rb r5 rc date |

    r1 := year \\ 19.
    r2 := year \\ 4.
    r3 := year \\ 7.
    ra := 19*r1 + 16.
    r4 := ra \\ 30.
    rb := r2 + r2 + (4*r3) + (6*r4).
    r5 := rb \\ 7.
    rc := r4 + r5.
    date := Date newDay: 3 month: 4 year: year.
    ^date addDays: rc.! !


!Week methodsFor: 'squeak protocol' stamp: 'brp 1/30/2005 09:31'!
index

	^ self asMonth dayOfWeek + self dayOfMonth - 2  // 7 + 1
! !

Week class removeSelector: #startMonday!
Week class removeSelector: #toggleStartMonday!
Week removeSelector: #do:!
Week removeSelector: #indexInMonth:!
Date class removeSelector: #absoluteDaysToYear:!
Date class removeSelector: #fromJulianDayNumber:!
Date class removeSelector: #yearAndDaysFromDays:into:!
Timespan class removeSelector: #fromDate:!
Month removeSelector: #eachWeekDo:!
Date removeSelector: #asGregorian!
Date removeSelector: #asJulianDayNumber!
Date removeSelector: #day:year:!
Date removeSelector: #daylightSavingsInEffect!
Date removeSelector: #daylightSavingsInEffectAtStandardHour:!
Date removeSelector: #firstDayOfMonthIndex:!
Date removeSelector: #julianDayNumber:!
Date removeSelector: #mmddyy!
Date removeSelector: #uniqueDateStringBetween:and:!
Date removeSelector: #week!
Timespan removeSelector: #firstDate!
Timespan removeSelector: #lastDate!
TimeStamp class removeSelector: #midnightOn:!
TimeStamp class removeSelector: #noonOn:!
TimeStamp removeSelector: #date:!
TimeStamp removeSelector: #time:!
Time removeSelector: #hours:!
Time removeSelector: #hours:minutes:seconds:!
Time removeSelector: #setSeconds:!
DateAndTime initialize!
!classDefinition: #DateAndTime category: #'Kernel-Chronology'!
Magnitude subclass: #DateAndTime
	instanceVariableNames: 'seconds offset jdn nanos'
	classVariableNames: 'ClockProvider DaysSinceEpoch LastMilliSeconds LastTick LastTickSemaphore LocalTimeZone MilliSecondOffset'
	poolDictionaries: 'ChronologyConstants'
	category: 'Kernel-Chronology'!
"Postscript:
Leave the line above, and replace the rest of this comment by a useful one.
Executable statements should follow this comment, and should
be separated by periods, with no exclamation points (!!).
Be sure to put any further comments in double-quotes, like this one."
ChronologyConstants initialize.
DateAndTime initialize.
!

