Marcel Taeumel uploaded a new version of Chronology-Core to project The Trunk:
http://source.squeak.org/trunk/Chronology-Core-ct.67.mcz
==================== Summary ====================
Name: Chronology-Core-ct.67
Author: ct
Time: 2 July 2021, 6:11:19.127885 pm
UUID: 7a3d4136-ddb1-ea49-a035-d166391d3fb1
Ancestors: Chronology-Core-dtl.66
Adds Duration >> #busyWait and some explaining prose.
See http://lists.squeakfoundation.org/pipermail/squeak-dev/2021-July/215928.html. Thank you for the feedback!
=============== Diff against Chronology-Core-dtl.66 ===============
Item was added:
+ ----- Method: Duration>>busyWait (in category 'squeak protocol') -----
+ busyWait
+ "Run an infinite loop until the receiver has elapsed. Performance-intensive!! Usually, you will want to use #wait instead which does not stress the interpreter but instead uses a delay, giving other processes the chance to run. However, scheduling a Delay comes with a synchronization overhead which denies its suitability for very short or precise delays. See http://lists.squeakfoundation.org/pipermail/squeak-dev/2021-July/215928.html for further information."
+
+ "[3 seconds busyWait] timeToRun"
+
+ | proceedTime |
+ proceedTime := Time utcMicrosecondClock + self asMicroSeconds.
+ [Time utcMicrosecondClock >= proceedTime] whileFalse!
Item was changed:
----- Method: Duration>>wait (in category 'squeak protocol') -----
wait
+ "Convert this duration in a delay and wait once. Answer the created delay so that the client can wait on it again if needed. While this is the most CPU-friendly implementation, it comes with a small overhead for scheduling the delay as scheduling must be synchronized over all processes (see Delay >> #schedule). For very short, precise delays, consider using #busyWait instead."
- "Convert this duration in a delay and wait once. Answer the created delay so that the client can wait on it again if needed."
"[3 seconds wait] timeToRun"
^self asDelay wait!
Marcel Taeumel uploaded a new version of Kernel to project The Trunk:
http://source.squeak.org/trunk/Kernel-mt.1406.mcz
==================== Summary ====================
Name: Kernel-mt.1406
Author: mt
Time: 5 July 2021, 10:40:27.254527 am
UUID: d14ccb5a-8347-9b44-b428-27b8e64b8637
Ancestors: Kernel-mt.1405
To Delay, adds #busyWait for more precise waits on delays shorter than 50 milliseconds.
Complements Chronology-Core-mt.71.
=============== Diff against Kernel-mt.1405 ===============
Item was added:
+ ----- Method: Delay>>busyWait (in category 'delaying') -----
+ busyWait
+ "BEWARE!! This method is more precise than #wait, but it sacrifices many CPU cycles for that precision. Also note that the GC runs more often. Also note that only processes with a higher priority can run while waiting.
+
+ The following lists the precision (in milliseconds) of #wait on a Microsoft Surface Pro 6, Windows 10 21H1, OSVM 202104182333:
+ 100 -> 100
+ 50 -> 51.1 ... 102.2%
+ 10 -> 11.6 ... 105.5% ... maybe use #busyWait
+ 5 -> 5.93 ... 118.6% ... use #busyWait but check process priorities
+ 1 -> 1.41 ... 141.0% ... use #busyWait but check process priorities
+
+ As of July 2021, the shortest delay that we can guarantee on all platforms is still 1 millisecond as the value of #utcMicrosecondClock might not change any faster than that. For more information, see http://lists.squeakfoundation.org/pipermail/squeak-dev/2021-July/215928.html"
+
+ "[5 milliSeconds busyWait] bench"
+
+ | proceedTime |
+ proceedTime := Time utcMicrosecondClock + (delayDuration "milliseconds" * 1000).
+ [Time utcMicrosecondClock >= proceedTime] whileFalse.!
Item was changed:
----- Method: Delay>>wait (in category 'delaying') -----
wait
+ "Schedule this Delay, then wait on its semaphore. The current process will be suspended for the amount of time specified when this Delay was created. NOTE THAT for delays shorter than 50 milliseconds, you might want to use #busyWait for greater precision if the higher CPU load and restricted process scheduling are not an issue. See commentary in #busyWait."
- "Schedule this Delay, then wait on its semaphore. The current process will be suspended for the amount of time specified when this Delay was created."
self schedule.
[delaySemaphore wait] ifCurtailed:[self unschedule].
!
Marcel Taeumel uploaded a new version of Chronology-Core to project The Trunk:
http://source.squeak.org/trunk/Chronology-Core-mt.71.mcz
==================== Summary ====================
Name: Chronology-Core-mt.71
Author: mt
Time: 5 July 2021, 10:38:58.639527 am
UUID: b03b0fa0-69da-8947-97d1-ec404b609df3
Ancestors: Chronology-Core-mt.70, Chronology-Core-ct.67
Merges #busyWait from Chronology-Core-ct.67 but moves implementation to Delay for better polymorphism.
=============== Diff against Chronology-Core-mt.70 ===============
Item was added:
+ ----- Method: Duration>>busyWait (in category 'squeak protocol') -----
+ busyWait
+ "BEWARE!! This method is more precise than #wait, but it sacrifices many CPU cycles for that precision. Also note that only processes with a higher priority can run while waiting. See more detailed commentary in Delay >> #busyWait."
+
+ ^ self asDelay busyWait!
Item was changed:
----- Method: Duration>>wait (in category 'squeak protocol') -----
wait
+ "Convert this duration in a delay and wait once. Answer the created delay so that the client can wait on it again if needed. NOTE THAT for delays shorter than 50 milliseconds, you might want to use #busyWait for greater precision if the higher CPU load and restricted process scheduling are not an issue. See commentary in #busyWait."
- "Convert this duration in a delay and wait once. Answer the created delay so that the client can wait on it again if needed."
"[3 seconds wait] timeToRun"
^self asDelay wait!
Marcel Taeumel uploaded a new version of Chronology-Core to project The Trunk:
http://source.squeak.org/trunk/Chronology-Core-mt.70.mcz
==================== Summary ====================
Name: Chronology-Core-mt.70
Author: mt
Time: 5 July 2021, 9:01:22.838745 am
UUID: 5450e237-fb63-c04b-90d0-94e40ef57fa4
Ancestors: Chronology-Core-mt.69, Chronology-Core-dtl.68
Merges latest fixes from Chronology-Core-dtl.68, after the update bug was fixed in (the kind of branch'd) Chronology-Core-mt.69.
=============== Diff against Chronology-Core-mt.69 ===============
Item was changed:
Magnitude subclass: #DateAndTime
instanceVariableNames: 'utcMicroseconds localOffsetSeconds'
+ classVariableNames: 'AutomaticTimezone ClockProvider LocalTimeZone PosixEpochJulianDays'
- classVariableNames: 'AutomaticTimezone ClockProvider InitializeFromPrimitive LocalTimeZone PosixEpochJulianDays'
poolDictionaries: 'ChronologyConstants'
category: 'Chronology-Core'!
!DateAndTime commentStamp: 'dtl 3/12/2016 10:32' prior: 0!
I represent a point in UTC time as defined by ISO 8601. I have zero duration.
My implementation uses variables utcMicroseconds and localOffsetSeconds. This represents time magnitude as elapsed microseconds since the Posix epoch, with localOffsetSeconds representing local offset from UTC. The magnitude is used for comparison and duration calculations, and the local offset is used for displaying this magnitude in the context of a local time zone.
The implementation ignores leap seconds, which are adjustments made to maintain earth rotational clock time in synchronization with elapsed seconds.
DateAndTime class>>now will use #primitiveUtcWithOffset to obtain current time in UTC microseconds with current local offset in seconds. The primitive provides an atomic query for UTC time and local offset as measured by the OS platform. If primitiveUtcWithOffset is not available, the traditional implementation is used, which relies on a primitive for microseconds in the local time zone and derives UTC based on the TimeZone setting.
!
Item was removed:
- ----- Method: DateAndTime class>>canInitializeFromPrimitive (in category 'system startup') -----
- canInitializeFromPrimitive
- "Some implementations of primitiveUtcWithOffset do not support passing the
- DateAndTime instance as a parameter to the primitive."
-
- ^self basicNew initializeFromPrimitive utcMicroseconds notNil!
Item was changed:
----- Method: DateAndTime class>>initialize (in category 'initialize-release') -----
initialize
ClockProvider := Time.
+ PosixEpochJulianDays := 2440588.!
- PosixEpochJulianDays := 2440588.
- InitializeFromPrimitive := self canInitializeFromPrimitive.
- Smalltalk addToStartUpList: self.
- self startUp: true
- !
Item was changed:
----- Method: DateAndTime class>>now (in category 'ansi protocol') -----
now
"Answer time now as reported by #primitiveUtcWithOffset. If the primitive is not
available, answer the Posix epoch GMT."
self automaticTimezone
ifTrue: [ ^ self basicNew initializeFromPrimitive ]
ifFalse: [ | timeArray |
timeArray := Time posixMicrosecondClockWithOffset.
^ self utcMicroseconds: timeArray first offset: self localOffsetSeconds ]
!
Item was changed:
----- Method: DateAndTime class>>readFrom: (in category 'squeak protocol') -----
readFrom: aStream
+ | yearMonthDay hourMinuteSecondNano offsetSeconds |
- | offsetSeconds ch yearMonthDay hourMinuteSecondNano offset |
yearMonthDay := Date readYearMonthDayFrom: aStream.
[aStream peek isDigit]
whileFalse: [aStream next].
hourMinuteSecondNano := Time readHourMinuteSecondNanoFrom: aStream.
(aStream atEnd or: [('+-Z' includes: aStream peek) not])
ifTrue: [ self flag: #FIXME.
"Different unit tests have conflicting opinions as to whether the
current local offset should be used as a default. However, the current
local offset cannot be correct due to DST (offset is itself a function
of the point in time). Nevertheless, this is a reasonable default considering
that the offset would have been explicitly part of the date string if it
was a matter of concern. Unit tests will require updates to match this
assumption."
"offsetSeconds := 0"
offsetSeconds := self localOffsetSeconds]
ifFalse: [(aStream peekFor: $Z)
ifTrue: [offsetSeconds := 0]
+ ifFalse: [ | ch offsetString offset |
- ifFalse: [
ch := aStream next.
ch = $+ ifTrue: [ch := Character space].
+ offsetString := aStream upToEnd.
+ (offsetString atLast: 3 ifAbsent: ['']) = $:
+ ifFalse: [offsetString := (offsetString allButLast: 2) , ':' , (offsetString last: 2)].
+ offset := Duration fromString: ch asString, '0:', offsetString, ':0'.
- offset := Duration fromString: ch asString, '0:', aStream upToEnd, ':0'.
offsetSeconds := offset asSeconds]].
^ self
year: yearMonthDay first
month: yearMonthDay second
day: yearMonthDay third
hour: hourMinuteSecondNano first
minute: hourMinuteSecondNano second
second: hourMinuteSecondNano third
nanoSecond: hourMinuteSecondNano fourth
offsetSeconds: offsetSeconds
" '-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
+
+ ' 1970-01-01T00:00:00.000+0000' asDateAndTime
"!
Item was removed:
- ----- Method: DateAndTime class>>startUp: (in category 'system startup') -----
- startUp: startingAfresh
- "Set local timezone"
- startingAfresh
- ifTrue: [InitializeFromPrimitive := self canInitializeFromPrimitive.
- Time initialize. "set LastClockTick to 0".
- self now]!
Item was changed:
----- Method: Time class>>posixMicrosecondClockWithOffset (in category 'clock') -----
posixMicrosecondClockWithOffset
"Answer an array with local microseconds since the Posix epoch and the
current seconds offset from GMT in the local time zone."
| array posixUtcValue |
+ array := self primPosixMicrosecondClockWithOffset: (Array new: 2).
- array := self primPosixMicrosecondClockWithOffset.
posixUtcValue := array at: 1.
(self updateTimeZoneCacheAt: posixUtcValue) ifTrue: [ "Time zone may have changed: fetch again."
self primPosixMicrosecondClockWithOffset: array.
posixUtcValue := array at: 1 ].
ClockPolicy caseOf: {
[#acceptPlatformTime] -> [^ array] .
[#monotonicAllowDuplicates] -> [
posixUtcValue > LastClockTick
ifTrue: [LastClockTick := posixUtcValue]
ifFalse: [array at: 1 put: LastClockTick]] .
[#monotonicForceMicrosecondIncrement] -> [
posixUtcValue > LastClockTick
ifTrue: [LastClockTick := posixUtcValue]
ifFalse: [LastClockTick := LastClockTick + 1. "add one microsecond"
array at: 1 put: LastClockTick]] .
[#monotonicForceNanosecondIncrement] -> [
posixUtcValue > LastClockTick
ifTrue: [LastClockTick := posixUtcValue]
ifFalse: [LastClockTick := LastClockTick + (1 / 1000). "add one nanosecond"
array at: 1 put: LastClockTick]]
} otherwise: [].
^array!
Item was removed:
- ----- Method: Time class>>primPosixMicrosecondClockWithOffset (in category 'private') -----
- primPosixMicrosecondClockWithOffset
- "Answer an array with UTC microseconds since the Posix epoch and the
- current seconds offset from GMT in the local time zone. If the primitive is
- not available, then answer the time and offset of Posix epoch GMT. This enables
- the image to continue running in the absence of #primitiveUtcWithOffset, thus
- avoiding the need to fallback code based on the earlier local microsecond clock
- mechanism."
-
- <primitive: 'primitiveUtcWithOffset'>
- ^{0. 0}!
Item was changed:
+ ----- Method: Time class>>primPosixMicrosecondClockWithOffset: (in category 'clock') -----
- ----- Method: Time class>>primPosixMicrosecondClockWithOffset: (in category 'private') -----
primPosixMicrosecondClockWithOffset: arrayOrObjectWithTwoSlots
"Answer an array with UTC microseconds since the Posix epoch and the
current seconds offset from GMT in the local time zone. If the primitive is
not available, then answer the time and offset of Posix epoch GMT. This enables
the image to continue running in the absence of #primitiveUtcWithOffset, thus
avoiding the need to fallback code based on the earlier local microsecond clock
mechanism.
The parameter may be a two element array, or an object whose first two instance
variables are expected to be UTC microseconds and seconds offset from GMT."
<primitive: 'primitiveUtcWithOffset'>
(arrayOrObjectWithTwoSlots instVarAt: 1)
ifNil: [arrayOrObjectWithTwoSlots instVarAt: 1 put: 0].
(arrayOrObjectWithTwoSlots instVarAt: 2)
ifNil: [arrayOrObjectWithTwoSlots instVarAt: 2 put: 0]!
Item was changed:
+ (PackageInfo named: 'Chronology-Core') postscript: 'Smalltalk removeFromStartUpList: DateAndTime'!
- (PackageInfo named: 'Chronology-Core') postscript: '"Make sure UpdateVMTimeZoneCacheAt of Time is initialized."
- Time classPool at: #UpdateVMTimeZoneCacheAt put: 0.
- "Separated Time''s startup duties from DateAndTime."
- Smalltalk addToStartUpList: Time before: DateAndTime'!
Marcel Taeumel uploaded a new version of Chronology-Core to project The Trunk:
http://source.squeak.org/trunk/Chronology-Core-mt.69.mcz
==================== Summary ====================
Name: Chronology-Core-mt.69
Author: mt
Time: 5 July 2021, 8:58:16.208745 am
UUID: 9bf6a192-d70f-0941-aa38-4a7c2bf2a798
Ancestors: Chronology-Core-dtl.66
Stop using classVar InitializeFromPrimitive before it gets removed in Chronology-Core-dtl.67.
=============== Diff against Chronology-Core-dtl.66 ===============
Item was changed:
----- Method: DateAndTime class>>now (in category 'ansi protocol') -----
now
"Answer time now as reported by #primitiveUtcWithOffset. If the primitive is not
available, answer the Posix epoch GMT."
self automaticTimezone
+ ifTrue: [ ^ self basicNew initializeFromPrimitive ]
- ifTrue: [ InitializeFromPrimitive
- ifTrue: [ ^ self basicNew initializeFromPrimitive ]
- ifFalse: [ | timeArray |
- timeArray := Time posixMicrosecondClockWithOffset.
- ^ self utcMicroseconds: timeArray first offset: timeArray second ] ]
ifFalse: [ | timeArray |
timeArray := Time posixMicrosecondClockWithOffset.
^ self utcMicroseconds: timeArray first offset: self localOffsetSeconds ]
!
David T. Lewis uploaded a new version of Chronology-Core to project The Trunk:
http://source.squeak.org/trunk/Chronology-Core-dtl.68.mcz
==================== Summary ====================
Name: Chronology-Core-dtl.68
Author: dtl
Time: 4 July 2021, 4:17:58.647324 pm
UUID: 583e7bf7-ac3c-4ff3-9217-22e3045ec5b5
Ancestors: Chronology-Core-dtl.67, Chronology-Core-ct.52
Merge Chronology-Core-ct.52
The 'Z' format in Java's SimpleDateFormat is documented as support for RFC 822 time zone specifications (used in email), whereas our DateAndTime class>>readFrom: is used to parse ISO 8601 format date strings. So on the face of it, this enhancement seems out of place for the Squeak parser. However, if we can believe Wikipedia, it would also be considered as a valid ISO 8601 offset specifier. Merged.
References:
https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.htmlhttps://en.wikipedia.org/wiki/ISO_8601#Time_offsets_from_UTC
=============== Diff against Chronology-Core-dtl.67 ===============
Item was changed:
----- Method: DateAndTime class>>readFrom: (in category 'squeak protocol') -----
readFrom: aStream
+ | yearMonthDay hourMinuteSecondNano offsetSeconds |
- | offsetSeconds ch yearMonthDay hourMinuteSecondNano offset |
yearMonthDay := Date readYearMonthDayFrom: aStream.
[aStream peek isDigit]
whileFalse: [aStream next].
hourMinuteSecondNano := Time readHourMinuteSecondNanoFrom: aStream.
(aStream atEnd or: [('+-Z' includes: aStream peek) not])
ifTrue: [ self flag: #FIXME.
"Different unit tests have conflicting opinions as to whether the
current local offset should be used as a default. However, the current
local offset cannot be correct due to DST (offset is itself a function
of the point in time). Nevertheless, this is a reasonable default considering
that the offset would have been explicitly part of the date string if it
was a matter of concern. Unit tests will require updates to match this
assumption."
"offsetSeconds := 0"
offsetSeconds := self localOffsetSeconds]
ifFalse: [(aStream peekFor: $Z)
ifTrue: [offsetSeconds := 0]
+ ifFalse: [ | ch offsetString offset |
- ifFalse: [
ch := aStream next.
ch = $+ ifTrue: [ch := Character space].
+ offsetString := aStream upToEnd.
+ (offsetString atLast: 3 ifAbsent: ['']) = $:
+ ifFalse: [offsetString := (offsetString allButLast: 2) , ':' , (offsetString last: 2)].
+ offset := Duration fromString: ch asString, '0:', offsetString, ':0'.
- offset := Duration fromString: ch asString, '0:', aStream upToEnd, ':0'.
offsetSeconds := offset asSeconds]].
^ self
year: yearMonthDay first
month: yearMonthDay second
day: yearMonthDay third
hour: hourMinuteSecondNano first
minute: hourMinuteSecondNano second
second: hourMinuteSecondNano third
nanoSecond: hourMinuteSecondNano fourth
offsetSeconds: offsetSeconds
" '-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
+
+ ' 1970-01-01T00:00:00.000+0000' asDateAndTime
"!
David T. Lewis uploaded a new version of Chronology-Core to project The Trunk:
http://source.squeak.org/trunk/Chronology-Core-ct.52.mcz
==================== Summary ====================
Name: Chronology-Core-ct.52
Author: ct
Time: 31 January 2020, 11:23:39.214625 am
UUID: 34a31242-e22f-ca42-b8d9-e9f2b37fa169
Ancestors: Chronology-Core-mt.51
Extends DateAndTime readFrom: to accept offset strings without colon. For example, java's zzzz format gives you such a string.
Test will be added on request.
=============== Diff against Chronology-Core-mt.51 ===============
Item was changed:
----- Method: DateAndTime class>>readFrom: (in category 'squeak protocol') -----
readFrom: aStream
+ | yearMonthDay hourMinuteSecondNano offsetSeconds |
- | offsetSeconds ch yearMonthDay hourMinuteSecondNano offset |
yearMonthDay := Date readYearMonthDayFrom: aStream.
[aStream peek isDigit]
whileFalse: [aStream next].
hourMinuteSecondNano := Time readHourMinuteSecondNanoFrom: aStream.
(aStream atEnd or: [('+-Z' includes: aStream peek) not])
ifTrue: [ self flag: #FIXME.
"Different unit tests have conflicting opinions as to whether the
current local offset should be used as a default. However, the current
local offset cannot be correct due to DST (offset is itself a function
of the point in time). Nevertheless, this is a reasonable default considering
that the offset would have been explicitly part of the date string if it
was a matter of concern. Unit tests will require updates to match this
assumption."
"offsetSeconds := 0"
offsetSeconds := self localOffsetSeconds]
ifFalse: [(aStream peekFor: $Z)
ifTrue: [offsetSeconds := 0]
+ ifFalse: [ | ch offsetString offset |
- ifFalse: [
ch := aStream next.
ch = $+ ifTrue: [ch := Character space].
+ offsetString := aStream upToEnd.
+ (offsetString atLast: 3 ifAbsent: ['']) = $:
+ ifFalse: [offsetString := (offsetString allButLast: 2) , ':' , (offsetString last: 2)].
+ offset := Duration fromString: ch asString, '0:', offsetString, ':0'.
- offset := Duration fromString: ch asString, '0:', aStream upToEnd, ':0'.
offsetSeconds := offset asSeconds]].
^ self
year: yearMonthDay first
month: yearMonthDay second
day: yearMonthDay third
hour: hourMinuteSecondNano first
minute: hourMinuteSecondNano second
second: hourMinuteSecondNano third
nanoSecond: hourMinuteSecondNano fourth
offsetSeconds: offsetSeconds
" '-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
+
+ ' 1970-01-01T00:00:00.000+0000' asDateAndTime
"!