UTCDateAndTime is a UTC based implementation of class DateAndTime with one instance variable representing the magnitude of the point in time, and another representing local time zone offset.
I recommend loading with the SAR from http://wiki.squeak.org/squeak/6197, as maintaining this in Montecello is problematic.
After the 4.6/5.0 release, I would like to suggest moving Chronology out of the Kernel package into its own package, so that changes in Chronology can be maintained in Montecello without conflicting with the rest of Kernel.
Spur notes: The Spur image provides a huge performance when loading this set of changes. There are two steps in the loading process in which all DateAndTime instances need to be #becomed into new instances. This is painfully slow in the traditional image (with or without Cog), and it is amazing fast in Spur.
That said, there is a bug in the Spur VM (easily resolved I think) that produces incorrect time values. I'll post note about that on vm-dev. I would not recommend using UTCDateAndTime in Spur yet, other than just to see how amazingly fast it is compared to loading the same thing in a non-Spur image.
Dave
On Sun, 24 May 2015, David T. Lewis wrote:
UTCDateAndTime is a UTC based implementation of class DateAndTime with one instance variable representing the magnitude of the point in time, and another representing local time zone offset.
I recommend loading with the SAR from http://wiki.squeak.org/squeak/6197, as maintaining this in Montecello is problematic.
After the 4.6/5.0 release, I would like to suggest moving Chronology out of the Kernel package into its own package, so that changes in Chronology can be maintained in Montecello without conflicting with the rest of Kernel.
Spur notes: The Spur image provides a huge performance when loading this set of changes. There are two steps in the loading process in which all DateAndTime instances need to be #becomed into new instances. This is painfully slow in the traditional image (with or without Cog), and it is amazing fast in Spur.
Similar speed can be achieved in V3 images (on any VM), if all instances are exchanged in one shot. In LX-2.2.cs:
| oldInstances newInstances | oldInstances := DateAndTime allInstances, TimeStamp allInstances. newInstances := oldInstances collect: [ :each | each class == DateAndTime ifTrue: [ each asLXDateAndTime ] ifFalse: [ each asLXTimeStamp ] ]. oldInstances elementsForwardIdentityTo: newInstances.
And in LX-4.1.cs:
| oldInstances newInstances | oldInstances := LXDateAndTime allInstances, LXTimeStamp allInstances. newInstances := oldInstances collect: [ :each | each class == LXDateAndTime ifTrue: [ each asDateAndTime ] ifFalse: [ each asTimeStamp ] ]. oldInstances elementsForwardIdentityTo: newInstances.
Levente
That said, there is a bug in the Spur VM (easily resolved I think) that produces incorrect time values. I'll post note about that on vm-dev. I would not recommend using UTCDateAndTime in Spur yet, other than just to see how amazingly fast it is compared to loading the same thing in a non-Spur image.
Dave
On Sun, May 24, 2015 at 11:22:48PM +0200, Levente Uzonyi wrote:
On Sun, 24 May 2015, David T. Lewis wrote:
UTCDateAndTime is a UTC based implementation of class DateAndTime with one instance variable representing the magnitude of the point in time, and another representing local time zone offset.
I recommend loading with the SAR from http://wiki.squeak.org/squeak/6197, as maintaining this in Montecello is problematic.
After the 4.6/5.0 release, I would like to suggest moving Chronology out of the Kernel package into its own package, so that changes in Chronology can be maintained in Montecello without conflicting with the rest of Kernel.
Spur notes: The Spur image provides a huge performance when loading this set of changes. There are two steps in the loading process in which all DateAndTime instances need to be #becomed into new instances. This is painfully slow in the traditional image (with or without Cog), and it is amazing fast in Spur.
Similar speed can be achieved in V3 images (on any VM), if all instances are exchanged in one shot. In LX-2.2.cs:
| oldInstances newInstances | oldInstances := DateAndTime allInstances, TimeStamp allInstances. newInstances := oldInstances collect: [ :each | each class == DateAndTime ifTrue: [ each asLXDateAndTime ] ifFalse: [ each asLXTimeStamp ] ]. oldInstances elementsForwardIdentityTo: newInstances.
And in LX-4.1.cs:
| oldInstances newInstances | oldInstances := LXDateAndTime allInstances, LXTimeStamp allInstances. newInstances := oldInstances collect: [ :each | each class == LXDateAndTime ifTrue: [ each asDateAndTime ] ifFalse: [ each asTimeStamp ] ]. oldInstances elementsForwardIdentityTo: newInstances.
Levente,
Thank you! I was not aware of that.
Dave
On Mon, May 25, 2015 at 10:48:20AM -0400, David T. Lewis wrote:
On Sun, May 24, 2015 at 11:22:48PM +0200, Levente Uzonyi wrote:
On Sun, 24 May 2015, David T. Lewis wrote:
UTCDateAndTime is a UTC based implementation of class DateAndTime with one instance variable representing the magnitude of the point in time, and another representing local time zone offset.
I recommend loading with the SAR from http://wiki.squeak.org/squeak/6197, as maintaining this in Montecello is problematic.
After the 4.6/5.0 release, I would like to suggest moving Chronology out of the Kernel package into its own package, so that changes in Chronology can be maintained in Montecello without conflicting with the rest of Kernel.
Spur notes: The Spur image provides a huge performance when loading this set of changes. There are two steps in the loading process in which all DateAndTime instances need to be #becomed into new instances. This is painfully slow in the traditional image (with or without Cog), and it is amazing fast in Spur.
Similar speed can be achieved in V3 images (on any VM), if all instances are exchanged in one shot. In LX-2.2.cs:
| oldInstances newInstances | oldInstances := DateAndTime allInstances, TimeStamp allInstances. newInstances := oldInstances collect: [ :each | each class == DateAndTime ifTrue: [ each asLXDateAndTime ] ifFalse: [ each asLXTimeStamp ] ]. oldInstances elementsForwardIdentityTo: newInstances.
And in LX-4.1.cs:
| oldInstances newInstances | oldInstances := LXDateAndTime allInstances, LXTimeStamp allInstances. newInstances := oldInstances collect: [ :each | each class == LXDateAndTime ifTrue: [ each asDateAndTime ] ifFalse: [ each asTimeStamp ] ]. oldInstances elementsForwardIdentityTo: newInstances.
Levente,
Thank you! I was not aware of that.
I updated the SAR at http://wiki.squeak.org/squeak/6197. Indeed it now loads very quickly in a V3 image.
Dave
On Mon, 25 May 2015, David T. Lewis wrote:
On Mon, May 25, 2015 at 10:48:20AM -0400, David T. Lewis wrote:
On Sun, May 24, 2015 at 11:22:48PM +0200, Levente Uzonyi wrote:
On Sun, 24 May 2015, David T. Lewis wrote:
UTCDateAndTime is a UTC based implementation of class DateAndTime with one instance variable representing the magnitude of the point in time, and another representing local time zone offset.
I recommend loading with the SAR from http://wiki.squeak.org/squeak/6197, as maintaining this in Montecello is problematic.
After the 4.6/5.0 release, I would like to suggest moving Chronology out of the Kernel package into its own package, so that changes in Chronology can be maintained in Montecello without conflicting with the rest of Kernel.
Spur notes: The Spur image provides a huge performance when loading this set of changes. There are two steps in the loading process in which all DateAndTime instances need to be #becomed into new instances. This is painfully slow in the traditional image (with or without Cog), and it is amazing fast in Spur.
Similar speed can be achieved in V3 images (on any VM), if all instances are exchanged in one shot. In LX-2.2.cs:
| oldInstances newInstances | oldInstances := DateAndTime allInstances, TimeStamp allInstances. newInstances := oldInstances collect: [ :each | each class == DateAndTime ifTrue: [ each asLXDateAndTime ] ifFalse: [ each asLXTimeStamp ] ]. oldInstances elementsForwardIdentityTo: newInstances.
And in LX-4.1.cs:
| oldInstances newInstances | oldInstances := LXDateAndTime allInstances, LXTimeStamp allInstances. newInstances := oldInstances collect: [ :each | each class == LXDateAndTime ifTrue: [ each asDateAndTime ] ifFalse: [ each asTimeStamp ] ]. oldInstances elementsForwardIdentityTo: newInstances.
Levente,
Thank you! I was not aware of that.
I updated the SAR at http://wiki.squeak.org/squeak/6197. Indeed it now loads very quickly in a V3 image.
Cool. I've got another change set, which makes instance creation more than twice as fast: http://leves.web.elte.hu/squeak/DateAndTimeCreationSpeedup.1.cs
Levente
Dave
Excellent, thank you Levente. I'll make the update as soon as I can (late today).
FYI, I added you as developer on the SS3 repository http://ss3.gemstone.com/ss/UTCDateAndTime.html (but that does not mean I expect you to keep it updated, doing this in MC is a pain right now).
Dave
On Mon, 25 May 2015, David T. Lewis wrote:
On Mon, May 25, 2015 at 10:48:20AM -0400, David T. Lewis wrote:
On Sun, May 24, 2015 at 11:22:48PM +0200, Levente Uzonyi wrote:
On Sun, 24 May 2015, David T. Lewis wrote:
UTCDateAndTime is a UTC based implementation of class DateAndTime with one instance variable representing the magnitude of the point in time, and another representing local time zone offset.
I recommend loading with the SAR from http://wiki.squeak.org/squeak/6197, as maintaining this in Montecello is problematic.
After the 4.6/5.0 release, I would like to suggest moving Chronology out of the Kernel package into its own package, so that changes in Chronology can be maintained in Montecello without conflicting with the rest of Kernel.
Spur notes: The Spur image provides a huge performance when loading this set of changes. There are two steps in the loading process in which all DateAndTime instances need to be #becomed into new instances. This is painfully slow in the traditional image (with or without Cog), and it is amazing fast in Spur.
Similar speed can be achieved in V3 images (on any VM), if all instances are exchanged in one shot. In LX-2.2.cs:
| oldInstances newInstances | oldInstances := DateAndTime allInstances, TimeStamp allInstances. newInstances := oldInstances collect: [ :each | each class == DateAndTime ifTrue: [ each asLXDateAndTime ] ifFalse: [ each asLXTimeStamp ] ]. oldInstances elementsForwardIdentityTo: newInstances.
And in LX-4.1.cs:
| oldInstances newInstances | oldInstances := LXDateAndTime allInstances, LXTimeStamp allInstances. newInstances := oldInstances collect: [ :each | each class == LXDateAndTime ifTrue: [ each asDateAndTime ] ifFalse: [ each asTimeStamp ] ]. oldInstances elementsForwardIdentityTo: newInstances.
Levente,
Thank you! I was not aware of that.
I updated the SAR at http://wiki.squeak.org/squeak/6197. Indeed it now loads very quickly in a V3 image.
Cool. I've got another change set, which makes instance creation more than twice as fast: http://leves.web.elte.hu/squeak/DateAndTimeCreationSpeedup.1.cs
Levente
Dave
On Tue, May 26, 2015 at 03:39:01AM +0200, Levente Uzonyi wrote:
On Mon, 25 May 2015, David T. Lewis wrote:
On Mon, May 25, 2015 at 10:48:20AM -0400, David T. Lewis wrote:
On Sun, May 24, 2015 at 11:22:48PM +0200, Levente Uzonyi wrote:
On Sun, 24 May 2015, David T. Lewis wrote:
UTCDateAndTime is a UTC based implementation of class DateAndTime with one instance variable representing the magnitude of the point in time, and another representing local time zone offset.
I recommend loading with the SAR from http://wiki.squeak.org/squeak/6197, as maintaining this in Montecello is problematic.
After the 4.6/5.0 release, I would like to suggest moving Chronology out of the Kernel package into its own package, so that changes in Chronology can be maintained in Montecello without conflicting with the rest of Kernel.
Spur notes: The Spur image provides a huge performance when loading this set of changes. There are two steps in the loading process in which all DateAndTime instances need to be #becomed into new instances. This is painfully slow in the traditional image (with or without Cog), and it is amazing fast in Spur.
Similar speed can be achieved in V3 images (on any VM), if all instances are exchanged in one shot. In LX-2.2.cs:
| oldInstances newInstances | oldInstances := DateAndTime allInstances, TimeStamp allInstances. newInstances := oldInstances collect: [ :each | each class == DateAndTime ifTrue: [ each asLXDateAndTime ] ifFalse: [ each asLXTimeStamp ] ]. oldInstances elementsForwardIdentityTo: newInstances.
And in LX-4.1.cs:
| oldInstances newInstances | oldInstances := LXDateAndTime allInstances, LXTimeStamp allInstances. newInstances := oldInstances collect: [ :each | each class == LXDateAndTime ifTrue: [ each asDateAndTime ] ifFalse: [ each asTimeStamp ] ]. oldInstances elementsForwardIdentityTo: newInstances.
Levente,
Thank you! I was not aware of that.
I updated the SAR at http://wiki.squeak.org/squeak/6197. Indeed it now loads very quickly in a V3 image.
Cool. I've got another change set, which makes instance creation more than twice as fast: http://leves.web.elte.hu/squeak/DateAndTimeCreationSpeedup.1.cs
Thanks Levente,
Added to the SAR at http://wiki.squeak.org/squeak/6197 and to the repository at http://ss3.gemstone.com/ss/UTCDateAndTime.html. I also updated #hasUtcPrim for startup processing to use your #primPosixMicrosecondClockWithOffset change.
Dave
On Tue, 26 May 2015, David T. Lewis wrote:
On Tue, May 26, 2015 at 03:39:01AM +0200, Levente Uzonyi wrote:
On Mon, 25 May 2015, David T. Lewis wrote:
On Mon, May 25, 2015 at 10:48:20AM -0400, David T. Lewis wrote:
On Sun, May 24, 2015 at 11:22:48PM +0200, Levente Uzonyi wrote:
On Sun, 24 May 2015, David T. Lewis wrote:
UTCDateAndTime is a UTC based implementation of class DateAndTime with one instance variable representing the magnitude of the point in time, and another representing local time zone offset.
I recommend loading with the SAR from http://wiki.squeak.org/squeak/6197, as maintaining this in Montecello is problematic.
After the 4.6/5.0 release, I would like to suggest moving Chronology out of the Kernel package into its own package, so that changes in Chronology can be maintained in Montecello without conflicting with the rest of Kernel.
Spur notes: The Spur image provides a huge performance when loading this set of changes. There are two steps in the loading process in which all DateAndTime instances need to be #becomed into new instances. This is painfully slow in the traditional image (with or without Cog), and it is amazing fast in Spur.
Similar speed can be achieved in V3 images (on any VM), if all instances are exchanged in one shot. In LX-2.2.cs:
| oldInstances newInstances | oldInstances := DateAndTime allInstances, TimeStamp allInstances. newInstances := oldInstances collect: [ :each | each class == DateAndTime ifTrue: [ each asLXDateAndTime ] ifFalse: [ each asLXTimeStamp ] ]. oldInstances elementsForwardIdentityTo: newInstances.
And in LX-4.1.cs:
| oldInstances newInstances | oldInstances := LXDateAndTime allInstances, LXTimeStamp allInstances. newInstances := oldInstances collect: [ :each | each class == LXDateAndTime ifTrue: [ each asDateAndTime ] ifFalse: [ each asTimeStamp ] ]. oldInstances elementsForwardIdentityTo: newInstances.
Levente,
Thank you! I was not aware of that.
I updated the SAR at http://wiki.squeak.org/squeak/6197. Indeed it now loads very quickly in a V3 image.
Cool. I've got another change set, which makes instance creation more than twice as fast: http://leves.web.elte.hu/squeak/DateAndTimeCreationSpeedup.1.cs
Thanks Levente,
Added to the SAR at http://wiki.squeak.org/squeak/6197 and to the repository at http://ss3.gemstone.com/ss/UTCDateAndTime.html. I also updated #hasUtcPrim for startup processing to use your #primPosixMicrosecondClockWithOffset change.
Thanks Dave!
Levente
On Sun, May 24, 2015 at 12:36:02PM -0400, David T. Lewis wrote:
UTCDateAndTime is a UTC based implementation of class DateAndTime with one instance variable representing the magnitude of the point in time, and another representing local time zone offset.
I have updated the UTCDateAndTime package to make it loadable in the latest Squeak trunk and Spur.
A new Monticello repository is at http://www.squeaksource.com/UTCDateAndTime. The home page (with a new SAR) is at http://wiki.squeak.org/squeak/6197.
Starting with an updated trunk image, you can load UTCDateAndTime in two ways:
1) Open the http://www.squeaksource.com/UTCDateAndTime repository, and load the MCZ files in sequence beginning with Chronology-Core-dtl.3.
2) In a preferences browser, in category 'updates' set the 'Update URL' preference to 'http://www.squeaksource.com/UTCDateAndTime', and do world -> help... -> update code from server.
The main objective of UTCDateAndTime is to make DateAndTime conceptually simpler, but a happy side effect is that it is also significantly faster than the old implementation.
Dave
The main objective of UTCDateAndTime is to make DateAndTime conceptually simpler, but a happy side effect is that it is also significantly faster than the old implementation.
Hi Dave, when you first introduced UTCDateAndTime, it was originally significantly faster than legacy Chronology because legacy had a gross inefficiency in it. You work exposed that inefficiency, which was then fixed, pretty much neutralizing the performance advantage of UTCDateAndTime, of that time.
If you have made further improvements since then, I would be interested to see your benchmarks again.
One thing I wondered was, due to greater SmallInteger range, whether your implementation would be significantly faster in 64-bit image. In 32-bit though, IIRC, it no longer is..
Hi Chris,
I did a quick check last night and it seemed to be about 2x faster overall on 32 bit Spur, except for DateAndTime>>= which is now slower. The performance check utility is in the squeaksource repository if you want to take a look at it. YMMV.
Dave
The main objective of UTCDateAndTime is to make DateAndTime conceptually simpler, but a happy side effect is that it is also significantly faster than the old implementation.
Hi Dave, when you first introduced UTCDateAndTime, it was originally significantly faster than legacy Chronology because legacy had a gross inefficiency in it. You work exposed that inefficiency, which was then fixed, pretty much neutralizing the performance advantage of UTCDateAndTime, of that time.
If you have made further improvements since then, I would be interested to see your benchmarks again.
One thing I wondered was, due to greater SmallInteger range, whether your implementation would be significantly faster in 64-bit image. In 32-bit though, IIRC, it no longer is..
That's great news, I'll check it out. Thanks.
On Mon, Mar 7, 2016 at 12:17 PM, David T. Lewis lewis@mail.msen.com wrote:
Hi Chris,
I did a quick check last night and it seemed to be about 2x faster overall on 32 bit Spur, except for DateAndTime>>= which is now slower. The performance check utility is in the squeaksource repository if you want to take a look at it. YMMV.
Dave
The main objective of UTCDateAndTime is to make DateAndTime conceptually simpler, but a happy side effect is that it is also significantly faster than the old implementation.
Hi Dave, when you first introduced UTCDateAndTime, it was originally significantly faster than legacy Chronology because legacy had a gross inefficiency in it. You work exposed that inefficiency, which was then fixed, pretty much neutralizing the performance advantage of UTCDateAndTime, of that time.
If you have made further improvements since then, I would be interested to see your benchmarks again.
One thing I wondered was, due to greater SmallInteger range, whether your implementation would be significantly faster in 64-bit image. In 32-bit though, IIRC, it no longer is..
On Mon, Mar 07, 2016 at 12:21:38AM -0500, David T. Lewis wrote:
On Sun, May 24, 2015 at 12:36:02PM -0400, David T. Lewis wrote:
UTCDateAndTime is a UTC based implementation of class DateAndTime with one instance variable representing the magnitude of the point in time, and another representing local time zone offset.
I have updated the UTCDateAndTime package to make it loadable in the latest Squeak trunk and Spur.
Has anyone looked at this yet? Any interest?
Dave
A new Monticello repository is at http://www.squeaksource.com/UTCDateAndTime. The home page (with a new SAR) is at http://wiki.squeak.org/squeak/6197.
Starting with an updated trunk image, you can load UTCDateAndTime in two ways:
- Open the http://www.squeaksource.com/UTCDateAndTime repository, and load
the MCZ files in sequence beginning with Chronology-Core-dtl.3.
- In a preferences browser, in category 'updates' set the 'Update URL'
preference to 'http://www.squeaksource.com/UTCDateAndTime', and do world -> help... -> update code from server.
The main objective of UTCDateAndTime is to make DateAndTime conceptually simpler, but a happy side effect is that it is also significantly faster than the old implementation.
Dave
Hi David,
I just loaded the code into the latest 64-bit Spur image and VM. Everything works so far, and the overall performance is better as well. For those who care about performance, the speedups are
#testNow->3.01. #testEquals->1.83. #testGreaterThan->1.86. #testLessThan->1.92. #testPrintString->0.85. #testStringAsDateAndTime->1.75.
So, #testPrintString is slighly slower, but everything else is significanlty quicker. I haven't reviewed the code yet, but I'll do.
Levente
On Sat, 12 Mar 2016, David T. Lewis wrote:
On Mon, Mar 07, 2016 at 12:21:38AM -0500, David T. Lewis wrote:
On Sun, May 24, 2015 at 12:36:02PM -0400, David T. Lewis wrote:
UTCDateAndTime is a UTC based implementation of class DateAndTime with one instance variable representing the magnitude of the point in time, and another representing local time zone offset.
I have updated the UTCDateAndTime package to make it loadable in the latest Squeak trunk and Spur.
Has anyone looked at this yet? Any interest?
Dave
A new Monticello repository is at http://www.squeaksource.com/UTCDateAndTime. The home page (with a new SAR) is at http://wiki.squeak.org/squeak/6197.
Starting with an updated trunk image, you can load UTCDateAndTime in two ways:
- Open the http://www.squeaksource.com/UTCDateAndTime repository, and load
the MCZ files in sequence beginning with Chronology-Core-dtl.3.
- In a preferences browser, in category 'updates' set the 'Update URL'
preference to 'http://www.squeaksource.com/UTCDateAndTime', and do world -> help... -> update code from server.
The main objective of UTCDateAndTime is to make DateAndTime conceptually simpler, but a happy side effect is that it is also significantly faster than the old implementation.
Dave
Hi Levente,
I had not checked the 64-bit image yet, thanks. I did notice from the 32-bit image that the DateAndTime>>= test shows that we might have an opportunity to improve #digitCompare: performance, or maybe think of a better way to do the #= implementation. Your 64-bit results show that it is not a problem for the 64-bit image (because we would be dealing with immediate small integers there).
It's interesting to see that Spur is speeding up overall performance to the point that some primitives are starting to appear relatively slow in comparison. That is very nice problem to have :-)
Dave
On Sat, Mar 12, 2016 at 07:39:14PM +0100, Levente Uzonyi wrote:
Hi David,
I just loaded the code into the latest 64-bit Spur image and VM. Everything works so far, and the overall performance is better as well. For those who care about performance, the speedups are
#testNow->3.01. #testEquals->1.83. #testGreaterThan->1.86. #testLessThan->1.92. #testPrintString->0.85. #testStringAsDateAndTime->1.75.
So, #testPrintString is slighly slower, but everything else is significanlty quicker. I haven't reviewed the code yet, but I'll do.
Levente
On Sat, 12 Mar 2016, David T. Lewis wrote:
On Mon, Mar 07, 2016 at 12:21:38AM -0500, David T. Lewis wrote:
On Sun, May 24, 2015 at 12:36:02PM -0400, David T. Lewis wrote:
UTCDateAndTime is a UTC based implementation of class DateAndTime with one instance variable representing the magnitude of the point in time, and another representing local time zone offset.
I have updated the UTCDateAndTime package to make it loadable in the latest Squeak trunk and Spur.
Has anyone looked at this yet? Any interest?
Dave
A new Monticello repository is at http://www.squeaksource.com/UTCDateAndTime. The home page (with a new SAR) is at http://wiki.squeak.org/squeak/6197.
Starting with an updated trunk image, you can load UTCDateAndTime in two ways:
- Open the http://www.squeaksource.com/UTCDateAndTime repository, and
load the MCZ files in sequence beginning with Chronology-Core-dtl.3.
- In a preferences browser, in category 'updates' set the 'Update URL'
preference to 'http://www.squeaksource.com/UTCDateAndTime', and do world -> help... -> update code from server.
The main objective of UTCDateAndTime is to make DateAndTime conceptually simpler, but a happy side effect is that it is also significantly faster than the old implementation.
Dave
Hi Dave,
I ran the tests and found that there are three types of failures. 1. Some tests assume that the default offset is #localOffset. I don't think it's correct, but that's how is it in Trunk. 2. Hashes have changed. This implies that HashedCollections containing DateAndTime instances as key will have to be rehashed. In the base Trunk image there are appear to be no such HashedCollections, but not rehashing such collections will break images with custom packages in them after update. 3. Loss of resolution and strict monotonicity. In Trunk [DateAndTime now < DateAndTime now] is always true. This is possible because DateAndTime has nanosecond resolution, but the source clock only has microsecond resolution, and our machines are so slow that it takes more than a nanosecond to execute the primitive. All these allow us to use the sub-microsecond part of the timestamp to create intermediate strictly monotonic values.
Levente
On Sat, 12 Mar 2016, David T. Lewis wrote:
Hi Levente,
I had not checked the 64-bit image yet, thanks. I did notice from the 32-bit image that the DateAndTime>>= test shows that we might have an opportunity to improve #digitCompare: performance, or maybe think of a better way to do the #= implementation. Your 64-bit results show that it is not a problem for the 64-bit image (because we would be dealing with immediate small integers there).
It's interesting to see that Spur is speeding up overall performance to the point that some primitives are starting to appear relatively slow in comparison. That is very nice problem to have :-)
Dave
On Sat, Mar 12, 2016 at 07:39:14PM +0100, Levente Uzonyi wrote:
Hi David,
I just loaded the code into the latest 64-bit Spur image and VM. Everything works so far, and the overall performance is better as well. For those who care about performance, the speedups are
#testNow->3.01. #testEquals->1.83. #testGreaterThan->1.86. #testLessThan->1.92. #testPrintString->0.85. #testStringAsDateAndTime->1.75.
So, #testPrintString is slighly slower, but everything else is significanlty quicker. I haven't reviewed the code yet, but I'll do.
Levente
On Sat, 12 Mar 2016, David T. Lewis wrote:
On Mon, Mar 07, 2016 at 12:21:38AM -0500, David T. Lewis wrote:
On Sun, May 24, 2015 at 12:36:02PM -0400, David T. Lewis wrote:
UTCDateAndTime is a UTC based implementation of class DateAndTime with one instance variable representing the magnitude of the point in time, and another representing local time zone offset.
I have updated the UTCDateAndTime package to make it loadable in the latest Squeak trunk and Spur.
Has anyone looked at this yet? Any interest?
Dave
A new Monticello repository is at http://www.squeaksource.com/UTCDateAndTime. The home page (with a new SAR) is at http://wiki.squeak.org/squeak/6197.
Starting with an updated trunk image, you can load UTCDateAndTime in two ways:
- Open the http://www.squeaksource.com/UTCDateAndTime repository, and
load the MCZ files in sequence beginning with Chronology-Core-dtl.3.
- In a preferences browser, in category 'updates' set the 'Update URL'
preference to 'http://www.squeaksource.com/UTCDateAndTime', and do world -> help... -> update code from server.
The main objective of UTCDateAndTime is to make DateAndTime conceptually simpler, but a happy side effect is that it is also significantly faster than the old implementation.
Dave
On Sat, Mar 12, 2016 at 08:48:21PM +0100, Levente Uzonyi wrote:
Hi Dave,
I ran the tests and found that there are three types of failures.
- Some tests assume that the default offset is #localOffset. I don't
think it's correct, but that's how is it in Trunk.
There are 10 failing tests in my image. These are cases in which either I was uncertain how to handle the issue, or where I thought that the current behaviour in trunk may be wrong.
- Hashes have changed. This implies that HashedCollections containing
DateAndTime instances as key will have to be rehashed. In the base Trunk image there are appear to be no such HashedCollections, but not rehashing such collections will break images with custom packages in them after update.
I am not expert in this area at all. But part of the update process (in the MC postscripts) finds all instances of the old style DateAndTime, and becomes them into the new ones. Would the HashedCollections contianing DateAndTime instances as key still require rehash in that case?
Related to DateAndTime>>hash, I would also like to ask for guidance as to how DateAndTime>>= should be defined. Maybe this is an ANSI Smalltalk question, but I was not sure if we should be thinking of DateAndTime as a magnitude, such that two instances are equal if their utcMicroseconds are the same? Or are two instances equal if they have the same magnitude and also the same localOffsetSeconds?
I implemented the first approach (two instances are #= if they represent the same UTC time, regardless of timezone). There may be use cases where the other approach makes sense. But my thinking was that when comparing two instances of DateAndTime, they should not be considered the same unless they both represent the same point in time, hence UTC time regardless of the time zone in which the instance was created.
- Loss of resolution and strict monotonicity. In Trunk [DateAndTime now <
DateAndTime now] is always true. This is possible because DateAndTime has nanosecond resolution, but the source clock only has microsecond resolution, and our machines are so slow that it takes more than a nanosecond to execute the primitive. All these allow us to use the sub-microsecond part of the timestamp to create intermediate strictly monotonic values.
To be honest, I do not fully recall the rationale for this. One important case is that of the system clock being set back due to ntp synchronization. Fiddling with the nanoseconds number to make it appear as if the OS had reported an increase in time (when in fact it did not) seems questionable to me, but I know that it was done for some good reason. I do remember the discussions, so I should look back through the squeak-dev archives and find out the reason this was done.
Levente
Thanks very much for looking at this. I added you and Chris Muller as developers on the UTCDateAndTime repository on squeaksource.com in case you want to make any changes.
Much appreciated,
Dave
Hi Dave,
I finally had some time to dig into the code and the tests.
On Sun, 13 Mar 2016, David T. Lewis wrote:
On Sat, Mar 12, 2016 at 08:48:21PM +0100, Levente Uzonyi wrote:
Hi Dave,
I ran the tests and found that there are three types of failures.
- Some tests assume that the default offset is #localOffset. I don't
think it's correct, but that's how is it in Trunk.
There are 10 failing tests in my image. These are cases in which either I was uncertain how to handle the issue, or where I thought that the current behaviour in trunk may be wrong.
- Hashes have changed. This implies that HashedCollections containing
DateAndTime instances as key will have to be rehashed. In the base Trunk image there are appear to be no such HashedCollections, but not rehashing such collections will break images with custom packages in them after update.
I am not expert in this area at all. But part of the update process (in the MC postscripts) finds all instances of the old style DateAndTime, and becomes them into the new ones. Would the HashedCollections contianing DateAndTime instances as key still require rehash in that case?
Yes, it is. When their hash changes, these objects will not be found in such collections.
Related to DateAndTime>>hash, I would also like to ask for guidance as to how DateAndTime>>= should be defined. Maybe this is an ANSI Smalltalk question, but I was not sure if we should be thinking of DateAndTime as a magnitude, such that two instances are equal if their utcMicroseconds are the same? Or are two instances equal if they have the same magnitude and also the same localOffsetSeconds?
I implemented the first approach (two instances are #= if they represent the same UTC time, regardless of timezone). There may be use cases where the other approach makes sense. But my thinking was that when comparing two instances of DateAndTime, they should not be considered the same unless they both represent the same point in time, hence UTC time regardless of the time zone in which the instance was created.
As we discussed this at the last board meeting, the right thing is to use UTC time only both for #hash and #=, so this is correct.
- Loss of resolution and strict monotonicity. In Trunk [DateAndTime now <
DateAndTime now] is always true. This is possible because DateAndTime has nanosecond resolution, but the source clock only has microsecond resolution, and our machines are so slow that it takes more than a nanosecond to execute the primitive. All these allow us to use the sub-microsecond part of the timestamp to create intermediate strictly monotonic values.
To be honest, I do not fully recall the rationale for this. One important case is that of the system clock being set back due to ntp synchronization. Fiddling with the nanoseconds number to make it appear as if the OS had reported an increase in time (when in fact it did not) seems questionable to me, but I know that it was done for some good reason. I do remember the discussions, so I should look back through the squeak-dev archives and find out the reason this was done.
It comes handy in many situations where uniqueness is a must. E.g. creating file names, storing them in a database. I don't know why it was added originally.
The loss of the nanosecond part has another side effect. utcMicroseconds will be a Fraction when the resolution of the parsed input is too high. This is somewhat compatible, but it makes things slower. E.g.:
'2002-05-16T17:20:45.000000009+01:01' asDateAndTime utcMicroseconds "==> (1021565985000000009/1000)"
I found two other issues:
DateAndTime class >> #date:time: ignores the nanoseconds from the time argument. This is present in the Trunk as well, but no test fails, because in Trunk TimeStamps have their nanoseconds part cleared (in a very inefficient way).
The other issue is that DateAndTime >> #getSeconds returns a fraction, which contains the nanosecond part as well. This makes DateAndTime >> #asTime return a Time instance which has its nanoseconds part doubled. I simply changed #/ to #// in #getSeconds to work that around. This also satisfied the expectations of all other senders of #getSeconds, but then it turned out to be the same as #getWholeSeconds. Since #getSeconds is a replacement for the original seconds variable (if I'm not mistaken), I think it's safe to do this change and replace sends of #getWholeSeconds to #getSeconds.
I found that I'm a developer on the project, so I have uploaded a new version with the changes described above + some optimizations.
About some #FIXMEs: #offset: is plain wrong according to its comment. It should simply create a copy with the new offset and the same utcMicrosecond value. Just like how #utcOffset: does. We should keep one or the other but not both.
Levente
Levente
Thanks very much for looking at this. I added you and Chris Muller as developers on the UTCDateAndTime repository on squeaksource.com in case you want to make any changes.
Much appreciated,
Dave
Hi Levente,
Thank you for the review and for your updates. Printing dates seems to be almost 50% faster now with your updates.
Dave
On Sun, Mar 20, 2016 at 12:39:38AM +0100, Levente Uzonyi wrote:
Hi Dave,
I finally had some time to dig into the code and the tests.
On Sun, 13 Mar 2016, David T. Lewis wrote:
On Sat, Mar 12, 2016 at 08:48:21PM +0100, Levente Uzonyi wrote:
Hi Dave,
I ran the tests and found that there are three types of failures.
- Some tests assume that the default offset is #localOffset. I don't
think it's correct, but that's how is it in Trunk.
There are 10 failing tests in my image. These are cases in which either I was uncertain how to handle the issue, or where I thought that the current behaviour in trunk may be wrong.
- Hashes have changed. This implies that HashedCollections containing
DateAndTime instances as key will have to be rehashed. In the base Trunk image there are appear to be no such HashedCollections, but not rehashing such collections will break images with custom packages in them after update.
I am not expert in this area at all. But part of the update process (in the MC postscripts) finds all instances of the old style DateAndTime, and becomes them into the new ones. Would the HashedCollections contianing DateAndTime instances as key still require rehash in that case?
Yes, it is. When their hash changes, these objects will not be found in such collections.
Related to DateAndTime>>hash, I would also like to ask for guidance as to how DateAndTime>>= should be defined. Maybe this is an ANSI Smalltalk question, but I was not sure if we should be thinking of DateAndTime as a magnitude, such that two instances are equal if their utcMicroseconds are the same? Or are two instances equal if they have the same magnitude and also the same localOffsetSeconds?
I implemented the first approach (two instances are #= if they represent the same UTC time, regardless of timezone). There may be use cases where the other approach makes sense. But my thinking was that when comparing two instances of DateAndTime, they should not be considered the same unless they both represent the same point in time, hence UTC time regardless of the time zone in which the instance was created.
As we discussed this at the last board meeting, the right thing is to use UTC time only both for #hash and #=, so this is correct.
- Loss of resolution and strict monotonicity. In Trunk [DateAndTime now <
DateAndTime now] is always true. This is possible because DateAndTime has nanosecond resolution, but the source clock only has microsecond resolution, and our machines are so slow that it takes more than a nanosecond to execute the primitive. All these allow us to use the sub-microsecond part of the timestamp to create intermediate strictly monotonic values.
To be honest, I do not fully recall the rationale for this. One important case is that of the system clock being set back due to ntp synchronization. Fiddling with the nanoseconds number to make it appear as if the OS had reported an increase in time (when in fact it did not) seems questionable to me, but I know that it was done for some good reason. I do remember the discussions, so I should look back through the squeak-dev archives and find out the reason this was done.
It comes handy in many situations where uniqueness is a must. E.g. creating file names, storing them in a database. I don't know why it was added originally.
The loss of the nanosecond part has another side effect. utcMicroseconds will be a Fraction when the resolution of the parsed input is too high. This is somewhat compatible, but it makes things slower. E.g.:
'2002-05-16T17:20:45.000000009+01:01' asDateAndTime utcMicroseconds "==> (1021565985000000009/1000)"
I found two other issues:
DateAndTime class >> #date:time: ignores the nanoseconds from the time argument. This is present in the Trunk as well, but no test fails, because in Trunk TimeStamps have their nanoseconds part cleared (in a very inefficient way).
The other issue is that DateAndTime >> #getSeconds returns a fraction, which contains the nanosecond part as well. This makes DateAndTime >> #asTime return a Time instance which has its nanoseconds part doubled. I simply changed #/ to #// in #getSeconds to work that around. This also satisfied the expectations of all other senders of #getSeconds, but then it turned out to be the same as #getWholeSeconds. Since #getSeconds is a replacement for the original seconds variable (if I'm not mistaken), I think it's safe to do this change and replace sends of #getWholeSeconds to #getSeconds.
I found that I'm a developer on the project, so I have uploaded a new version with the changes described above + some optimizations.
About some #FIXMEs: #offset: is plain wrong according to its comment. It should simply create a copy with the new offset and the same utcMicrosecond value. Just like how #utcOffset: does. We should keep one or the other but not both.
Levente
Levente
Thanks very much for looking at this. I added you and Chris Muller as developers on the UTCDateAndTime repository on squeaksource.com in case you want to make any changes.
Much appreciated,
Dave
On Sun, Mar 20, 2016 at 12:39:38AM +0100, Levente Uzonyi wrote:
The loss of the nanosecond part has another side effect. utcMicroseconds will be a Fraction when the resolution of the parsed input is too high. This is somewhat compatible, but it makes things slower. E.g.:
'2002-05-16T17:20:45.000000009+01:01' asDateAndTime utcMicroseconds "==> (1021565985000000009/1000)"
This is an interesting problem.
The fractional representation of utcMicroseconds seems reasonable to me in this case, at least now that you have fixed the bugs that I introduced :-)
It might however cause issues for Magma and similar applications. I would be interested to hear from Chris Muller is that is a problem.
My expectation would be that microseconds should be the unit of measure for time magnitude, but that there should be no limit on precision. Or to say it another way, clocks may have ticks, but time itself should be thought of as continous. Thus I expect utcMicroseconds to be a Number, but not necessarily an Integer.
Microseconds is a reasonable unit of measure because it is the highest level of precision available from the clocks on the Linux, OS X, and Windows systems that we use, and because it implies clock accuracy that is well beyond the real time measurement capabilities of those platforms.
As far as I know, the practical use of nanosecond precision in DateAndTime would be in the case of adding incremental nanoseconds to the time value in order to create the illusion that repeated calls to the system clock will always result in monotonically increasing values. If so, then I suspect that the same practical result could be achieved by artificially incrementing the value in units of milliseconds rather than nanoseconds, which would ensure unique integer values.
After all, it does not seem likely that any application involving a database would be querying the system clock at a rate anywhere close to a million per second. But I have not actually tried this, so I may be misunderstanding the requirement.
Dave
On Sun, Mar 20, 2016 at 01:16:45PM -0400, David T. Lewis wrote:
On Sun, Mar 20, 2016 at 12:39:38AM +0100, Levente Uzonyi wrote:
The loss of the nanosecond part has another side effect. utcMicroseconds will be a Fraction when the resolution of the parsed input is too high. This is somewhat compatible, but it makes things slower. E.g.:
'2002-05-16T17:20:45.000000009+01:01' asDateAndTime utcMicroseconds "==> (1021565985000000009/1000)"
This is an interesting problem.
The fractional representation of utcMicroseconds seems reasonable to me in this case, at least now that you have fixed the bugs that I introduced :-)
It might however cause issues for Magma and similar applications. I would be interested to hear from Chris Muller is that is a problem.
My expectation would be that microseconds should be the unit of measure for time magnitude, but that there should be no limit on precision. Or to say it another way, clocks may have ticks, but time itself should be thought of as continous. Thus I expect utcMicroseconds to be a Number, but not necessarily an Integer.
Microseconds is a reasonable unit of measure because it is the highest level of precision available from the clocks on the Linux, OS X, and Windows systems that we use, and because it implies clock accuracy that is well beyond the real time measurement capabilities of those platforms.
As far as I know, the practical use of nanosecond precision in DateAndTime would be in the case of adding incremental nanoseconds to the time value in order to create the illusion that repeated calls to the system clock will always result in monotonically increasing values. If so, then I suspect that the same practical result could be achieved by artificially incrementing the value in units of milliseconds rather than nanoseconds, which would ensure unique integer values.
After all, it does not seem likely that any application involving a database would be querying the system clock at a rate anywhere close to a million per second. But I have not actually tried this, so I may be misunderstanding the requirement.
I updated the package in Chronology-Core-dtl.14 to provide implementations of various strategies for providing monotonically increasing DateAndTime now with a utcMicrosecond time base. I am not sure which is the best approach, but this shows how any of them can be supported.
The update comment describes the options:
Name: Chronology-Core-dtl.14 Author: dtl Time: 20 March 2016, 9:42:49.417923 pm UUID: 813fbf89-d8e0-4242-a5e5-9e665c9b8618 Ancestors: Chronology-Core-ul.13
Implement a variety of policies for incrementing the clock on repeated calls to DateAndTime class>>now. It is not clear which policy may be best, so provide four variants for experimentation and review. Presumably three of the four options can be removed at a later date.
See Time class>>clockPolicy to select a policy. The current clock policy is set to #monotonicForceNanosecondIncrement.
The four policies are:
#acceptPlatformTime - Accept the time value provided by the system platform, even in this allows time to appear to move backwards when the clock is adjusted. Simple, fast, and no hidden side effects.
#monotonicAllowDuplicates - Accept the time value provided by the system platform unless it is less that the last clock tick. This protects for system clock adjustments. Side effects unlikely. Does not ensure unique values on repeated calls.
#monotonicForceMicrosecondIncrement - If the time value is less than or equal to the value from the last call, force increment by one microsecond. This ensures integral values of UTC time, but increments the time value by a full microsecond.
#monotonicForceNanosecondIncrement - If the time value is less than or equal to the value from the last call, force increment by one nanosecond. This it functionally compatible with previous Squeak practice, but is computationally expensive and results in time values represented as fractions, which might be a problem for some database applications.
Hi Dave,
On Sun, 20 Mar 2016, David T. Lewis wrote:
I updated the package in Chronology-Core-dtl.14 to provide implementations of various strategies for providing monotonically increasing DateAndTime now with a utcMicrosecond time base. I am not sure which is the best approach, but this shows how any of them can be supported.
The update comment describes the options:
Name: Chronology-Core-dtl.14 Author: dtl Time: 20 March 2016, 9:42:49.417923 pm UUID: 813fbf89-d8e0-4242-a5e5-9e665c9b8618 Ancestors: Chronology-Core-ul.13
Implement a variety of policies for incrementing the clock on repeated calls to DateAndTime class>>now. It is not clear which policy may be best, so provide four variants for experimentation and review. Presumably three of the four options can be removed at a later date.
See Time class>>clockPolicy to select a policy. The current clock policy is set to #monotonicForceNanosecondIncrement.
The four policies are:
#acceptPlatformTime - Accept the time value provided by the system platform, even in this allows time to appear to move backwards when the clock is adjusted. Simple, fast, and no hidden side effects.
#monotonicAllowDuplicates - Accept the time value provided by the system platform unless it is less that the last clock tick. This protects for system clock adjustments. Side effects unlikely. Does not ensure unique values on repeated calls.
#monotonicForceMicrosecondIncrement - If the time value is less than or equal to the value from the last call, force increment by one microsecond. This ensures integral values of UTC time, but increments the time value by a full microsecond.
#monotonicForceNanosecondIncrement - If the time value is less than or equal to the value from the last call, force increment by one nanosecond. This it functionally compatible with previous Squeak practice, but is computationally expensive and results in time values represented as fractions, which might be a problem for some database applications.
I think this covers most possible use cases. What I was originally thinking about was the addition of another field to hold the nanosecond part, since that would have only been set by the image itself, so the primitive could still have been used to initialize the rest. That we we could have avoided the use of fractions at the cost of having another field per object even when there's no need for high accuracy.
One more thing that I noticed is that this primitive still uses the "quick but inaccurate" way to get the current time, which only updates every two milliseconds (I think once per heartbeat). Eliot has changed primitive 240 a while ago to always provide the accurate time:
| start end | start := DateAndTime now. [ (end := DateAndTime now) = start ] whileTrue. { start. end. end - start } {2016-03-23T16:53:33.637835+01:00 . 2016-03-23T16:53:33.639844+01:00 . 0:00:00:00.002009}
| start end | start := Time utcMicrosecondClock. [ (end := Time utcMicrosecondClock) = start ] whileTrue. { start. end. end - start } #(3636201206461149 3636201206461150 1)
Levente
IMHO monotonicForceMicrosecondIncrement is good rough and should be the default (or only option).
And we could easily use Elliot's utcMicrosecondClock (as my latest trunk code does).
- Bert -
On 23 Mar 2016, at 17:01, Levente Uzonyi leves@caesar.elte.hu wrote:
Hi Dave,
On Sun, 20 Mar 2016, David T. Lewis wrote:
I updated the package in Chronology-Core-dtl.14 to provide implementations of various strategies for providing monotonically increasing DateAndTime now with a utcMicrosecond time base. I am not sure which is the best approach, but this shows how any of them can be supported.
The update comment describes the options:
Name: Chronology-Core-dtl.14 Author: dtl Time: 20 March 2016, 9:42:49.417923 pm UUID: 813fbf89-d8e0-4242-a5e5-9e665c9b8618 Ancestors: Chronology-Core-ul.13
Implement a variety of policies for incrementing the clock on repeated calls to DateAndTime class>>now. It is not clear which policy may be best, so provide four variants for experimentation and review. Presumably three of the four options can be removed at a later date.
See Time class>>clockPolicy to select a policy. The current clock policy is set to #monotonicForceNanosecondIncrement.
The four policies are:
#acceptPlatformTime - Accept the time value provided by the system platform, even in this allows time to appear to move backwards when the clock is adjusted. Simple, fast, and no hidden side effects.
#monotonicAllowDuplicates - Accept the time value provided by the system platform unless it is less that the last clock tick. This protects for system clock adjustments. Side effects unlikely. Does not ensure unique values on repeated calls.
#monotonicForceMicrosecondIncrement - If the time value is less than or equal to the value from the last call, force increment by one microsecond. This ensures integral values of UTC time, but increments the time value by a full microsecond.
#monotonicForceNanosecondIncrement - If the time value is less than or equal to the value from the last call, force increment by one nanosecond. This it functionally compatible with previous Squeak practice, but is computationally expensive and results in time values represented as fractions, which might be a problem for some database applications.
I think this covers most possible use cases. What I was originally thinking about was the addition of another field to hold the nanosecond part, since that would have only been set by the image itself, so the primitive could still have been used to initialize the rest. That we we could have avoided the use of fractions at the cost of having another field per object even when there's no need for high accuracy.
One more thing that I noticed is that this primitive still uses the "quick but inaccurate" way to get the current time, which only updates every two milliseconds (I think once per heartbeat). Eliot has changed primitive 240 a while ago to always provide the accurate time:
| start end | start := DateAndTime now. [ (end := DateAndTime now) = start ] whileTrue. { start. end. end - start } {2016-03-23T16:53:33.637835+01:00 . 2016-03-23T16:53:33.639844+01:00 . 0:00:00:00.002009}
| start end | start := Time utcMicrosecondClock. [ (end := Time utcMicrosecondClock) = start ] whileTrue. { start. end. end - start } #(3636201206461149 3636201206461150 1)
Levente
On Wed, Mar 23, 2016 at 05:22:49PM +0100, Bert Freudenberg wrote:
IMHO monotonicForceMicrosecondIncrement is good rough and should be the default (or only option).
And we could easily use Elliot's utcMicrosecondClock (as my latest trunk code does).
- Bert -
I made a number of updates yesterday (but did not mention it on the list). I think that everything is now up to date and reasonably compatible with trunk, including your utcMicrosecondClock changes. The automaticTimezone preference is working now too. I also added HashedCollection rehashAll to the package postscript (thanks Levente).
I set the clock policy to monotonicAllowDuplicates, which is my own personal preference. But I expect to be outvoted on that, and I would be quite happy with your preferred choice of monotonicForceMicrosecondIncrement.
Dave
On 23.03.2016, at 23:48, David T. Lewis lewis@mail.msen.com wrote:
On Wed, Mar 23, 2016 at 05:22:49PM +0100, Bert Freudenberg wrote: IMHO monotonicForceMicrosecondIncrement is good rough and should be the default (or only option).
And we could easily use Elliot's utcMicrosecondClock (as my latest trunk code does).
- Bert -
I made a number of updates yesterday (but did not mention it on the list). I think that everything is now up to date and reasonably compatible with trunk, including your utcMicrosecondClock changes. The automaticTimezone preference is working now too. I also added HashedCollection rehashAll to the package postscript (thanks Levente).
I set the clock policy to monotonicAllowDuplicates, which is my own personal preference. But I expect to be outvoted on that, and I would be quite happy with your preferred choice of monotonicForceMicrosecondIncrement.
Oh. Well I don't need #now to be unique, dupes would be fine. But someone needed it. Speak up! ;)
- Bert -
Hi Levente,
On Wed, Mar 23, 2016 at 05:01:35PM +0100, Levente Uzonyi wrote:
On Sun, 20 Mar 2016, David T. Lewis wrote:
The four policies are:
#acceptPlatformTime - Accept the time value provided by the system platform, even in this allows time to appear to move backwards when the clock is adjusted. Simple, fast, and no hidden side effects.
#monotonicAllowDuplicates - Accept the time value provided by the system platform unless it is less that the last clock tick. This protects for system clock adjustments. Side effects unlikely. Does not ensure unique values on repeated calls.
#monotonicForceMicrosecondIncrement - If the time value is less than or equal to the value from the last call, force increment by one microsecond. This ensures integral values of UTC time, but increments the time value by a full microsecond.
#monotonicForceNanosecondIncrement - If the time value is less than or equal to the value from the last call, force increment by one nanosecond. This it functionally compatible with previous Squeak practice, but is computationally expensive and results in time values represented as fractions, which might be a problem for some database applications.
I think this covers most possible use cases. What I was originally thinking about was the addition of another field to hold the nanosecond part, since that would have only been set by the image itself, so the primitive could still have been used to initialize the rest. That we we could have avoided the use of fractions at the cost of having another field per object even when there's no need for high accuracy.
I'm actually quite happy with the idea of the value being a Number that is an Integer for all reasonable values that could ever be supplied by the VM, but that might be a Fraction if we want to represent time values at some higher precision. Mainly I like it because it seems good conceptually to think of time as continuous, and not as discreet ticks of a clock.
It also works well computationally, because the normal case uses integer values (immediates in 64-bit Spur), and because Fractions involve two integer values, which presumably would be no worse than a design that added another field. But given that none of our computers or VMs can report time to a precision greater than microseconds, I think that we can safely ignore the issue for another 20 years or so ;-)
One more thing that I noticed is that this primitive still uses the "quick but inaccurate" way to get the current time, which only updates every two milliseconds (I think once per heartbeat). Eliot has changed primitive 240 a while ago to always provide the accurate time:
| start end | start := DateAndTime now. [ (end := DateAndTime now) = start ] whileTrue. { start. end. end - start } {2016-03-23T16:53:33.637835+01:00 . 2016-03-23T16:53:33.639844+01:00 . 0:00:00:00.002009}
| start end | start := Time utcMicrosecondClock. [ (end := Time utcMicrosecondClock) = start ] whileTrue. { start. end. end - start } #(3636201206461149 3636201206461150 1)
There is a good implementation of the primitive in the trunk SVN branch that needs to be added to the oscog branch. I think that will take care of the problem. I promised Eliot I would move the code over, but it might be a couple of weeks before I can get to it. We need to add this to the platform code to provide a true atomic primitive (from sq.h):
sqInt ioUtcWithOffset(sqLong*, int*); /* primitiveUtcWithOffset */
And then the primitive (slang) can be updated to match. I am afraid that I am responsible for some of the confusion, because when this was added to Cog a number of years ago, I did not want to touch the platform code, and I implemented a rather kludgy workaround just to get it working. Sorry.
Dave
Hi Dave,
On Wed, Mar 23, 2016 at 4:12 PM, David T. Lewis lewis@mail.msen.com wrote:
Hi Levente,
On Wed, Mar 23, 2016 at 05:01:35PM +0100, Levente Uzonyi wrote:
On Sun, 20 Mar 2016, David T. Lewis wrote:
The four policies are:
#acceptPlatformTime - Accept the time value provided by the system platform, even in this allows time to appear to move backwards when the clock is adjusted. Simple, fast, and no hidden side effects.
#monotonicAllowDuplicates - Accept the time value provided by the system platform unless it is less that the last clock tick. This protects for system clock adjustments. Side effects unlikely. Does not ensure unique values on repeated calls.
#monotonicForceMicrosecondIncrement - If the time value is less than or equal to the value from the last call, force increment by one
microsecond.
This ensures integral values of UTC time, but increments the time value
by
a full microsecond.
#monotonicForceNanosecondIncrement - If the time value is less than or equal to the value from the last call, force increment by one
nanosecond.
This it functionally compatible with previous Squeak practice, but is computationally expensive and results in time values represented as fractions, which might be a problem for some database applications.
I think this covers most possible use cases. What I was originally thinking about was the addition of another field to hold the nanosecond part, since that would have only been set by the image itself, so the primitive could still have been used to initialize the rest. That we we could have avoided the use of fractions at the cost of having another field per object even when there's no need for high accuracy.
I'm actually quite happy with the idea of the value being a Number that is an Integer for all reasonable values that could ever be supplied by the VM, but that might be a Fraction if we want to represent time values at some higher precision. Mainly I like it because it seems good conceptually to think of time as continuous, and not as discreet ticks of a clock.
It also works well computationally, because the normal case uses integer values (immediates in 64-bit Spur), and because Fractions involve two integer values, which presumably would be no worse than a design that added another field. But given that none of our computers or VMs can report time to a precision greater than microseconds, I think that we can safely ignore the issue for another 20 years or so ;-)
One more thing that I noticed is that this primitive still uses the
"quick
but inaccurate" way to get the current time, which only updates every two milliseconds (I think once per heartbeat). Eliot has changed primitive
240
a while ago to always provide the accurate time:
| start end | start := DateAndTime now. [ (end := DateAndTime now) = start ] whileTrue. { start. end. end - start } {2016-03-23T16:53:33.637835+01:00 . 2016-03-23T16:53:33.639844+01:00 . 0:00:00:00.002009}
| start end | start := Time utcMicrosecondClock. [ (end := Time utcMicrosecondClock) = start ] whileTrue. { start. end. end - start } #(3636201206461149 3636201206461150 1)
There is a good implementation of the primitive in the trunk SVN branch that needs to be added to the oscog branch. I think that will take care of the problem. I promised Eliot I would move the code over, but it might be a couple of weeks before I can get to it. We need to add this to the platform code to provide a true atomic primitive (from sq.h):
sqInt ioUtcWithOffset(sqLong*, int*); /* primitiveUtcWithOffset */
And then the primitive (slang) can be updated to match. I am afraid that I am responsible for some of the confusion, because when this was added to Cog a number of years ago, I did not want to touch the platform code, and I implemented a rather kludgy workaround just to get it working. Sorry.
Turns out this isn't needed for Cog. I have ioLocalSecondsOffset which answers a value determined at start-up and only changed via ioUpdateVMTimezone, which itself is controlled by primitiveUpdateTimezone, #243. So ioUTCMicroseconds is all that's needed to get at the clock and timezone atomically.
If I had had half a brain when I implemented the 64-bit microsecond clock I would have done it as a primitive to answer UTC and a primitive to answer timezone offset, but instead I chose to hide timezone in local microseconds. Live and learn. But the existence of primitiveUpdateTimezone, #243, means I could make it answer the timezone offset if invoked with zero arguments. And that way we'll have every possible combination of 64-bit clock access we could wish for :-) (not)
VMMaker.oscog-eem.1739 Author: eem Time: 23 March 2016, 12:41:48.73939 pm UUID: e9e980a3-1fc0-4425-acb8-f1f02f1977b0 Ancestors: VMMaker.oscog-eem.1738
Fix a slip in my correction of primitiveUtcWithOffset (wrong arg count check), and use ioLocalSecondsOffset to get the timezone, hence avoiding the need for the atomic accessor for both clock and timezone offset (the offset can only be changed from the system, and hence won't change while this primitive is executing).
Add a Smalltalk epoch version primitiveUtcAndTimezoneOffset and give it primitive #244.
Dave
_,,,^..^,,,_ best, Eliot
On Wed, Mar 23, 2016 at 04:22:21PM -0700, Eliot Miranda wrote:
Turns out this isn't needed for Cog. I have ioLocalSecondsOffset which answers a value determined at start-up and only changed via ioUpdateVMTimezone, which itself is controlled by primitiveUpdateTimezone, #243. So ioUTCMicroseconds is all that's needed to get at the clock and timezone atomically.
If it is updated at start-up, then it's wrong. Think of daylight savings time transitions.
Dave
On Wed, Mar 23, 2016 at 4:51 PM, David T. Lewis lewis@mail.msen.com wrote:
On Wed, Mar 23, 2016 at 04:22:21PM -0700, Eliot Miranda wrote:
Turns out this isn't needed for Cog. I have ioLocalSecondsOffset which answers a value determined at start-up and only changed via ioUpdateVMTimezone, which itself is controlled by primitiveUpdateTimezone, #243. So ioUTCMicroseconds is all that's needed to get at the clock and timezone atomically.
If it is updated at start-up, then it's wrong. Think of daylight savings time transitions.
So update it automatically once a second or some such?
_,,,^..^,,,_ best, Eliot
On Wed, Mar 23, 2016 at 05:50:19PM -0700, Eliot Miranda wrote:
On Wed, Mar 23, 2016 at 4:51 PM, David T. Lewis lewis@mail.msen.com wrote:
On Wed, Mar 23, 2016 at 04:22:21PM -0700, Eliot Miranda wrote:
Turns out this isn't needed for Cog. I have ioLocalSecondsOffset which answers a value determined at start-up and only changed via ioUpdateVMTimezone, which itself is controlled by primitiveUpdateTimezone, #243. So ioUTCMicroseconds is all that's needed to get at the clock and timezone atomically.
If it is updated at start-up, then it's wrong. Think of daylight savings time transitions.
So update it automatically once a second or some such?
Are you joking, or is that a serious question?
Confused, Dave
/* implementation of ioUtcWithOffset(), defined in config.h to /* override default definition in src/vm/interp.h */ sqInt sqUnixUtcWithOffset(sqLong *microSeconds, int *offset) { struct timeval timeval; if (gettimeofday(&timeval, NULL) == -1) return -1; time_t seconds= timeval.tv_sec; suseconds_t usec= timeval.tv_usec; *microSeconds= seconds * 1000000 + usec; #if defined(HAVE_TM_GMTOFF) *offset= localtime(&seconds)->tm_gmtoff; #else { struct tm *local= localtime(&seconds); struct tm *gmt= gmtime(&seconds); int d= local->tm_yday - gmt->tm_yday; int h= ((d < -1 ? 24 : 1 < d ? -24 : d * 24) + local->tm_hour - gmt->tm_hour); int m= h * 60 + local->tm_min - gmt->tm_min; *offset= m * 60; } #endif return 0; }
On Mar 23, 2016, at 6:55 PM, David T. Lewis lewis@mail.msen.com wrote:
On Wed, Mar 23, 2016 at 05:50:19PM -0700, Eliot Miranda wrote:
On Wed, Mar 23, 2016 at 4:51 PM, David T. Lewis lewis@mail.msen.com wrote:
On Wed, Mar 23, 2016 at 04:22:21PM -0700, Eliot Miranda wrote:
Turns out this isn't needed for Cog. I have ioLocalSecondsOffset which answers a value determined at start-up and only changed via ioUpdateVMTimezone, which itself is controlled by primitiveUpdateTimezone, #243. So ioUTCMicroseconds is all that's needed to get at the clock and timezone atomically.
If it is updated at start-up, then it's wrong. Think of daylight savings time transitions.
So update it automatically once a second or some such?
Are you joking, or is that a serious question?
Yes. I see two or three system calls in the code below. gettimeofday, one inside localtime and one inside gmtime. That's expensive.
Confused, Dave
/* implementation of ioUtcWithOffset(), defined in config.h to /* override default definition in src/vm/interp.h */ sqInt sqUnixUtcWithOffset(sqLong *microSeconds, int *offset) { struct timeval timeval; if (gettimeofday(&timeval, NULL) == -1) return -1; time_t seconds= timeval.tv_sec; suseconds_t usec= timeval.tv_usec; *microSeconds= seconds * 1000000 + usec; #if defined(HAVE_TM_GMTOFF) *offset= localtime(&seconds)->tm_gmtoff; #else { struct tm *local= localtime(&seconds); struct tm *gmt= gmtime(&seconds); int d= local->tm_yday - gmt->tm_yday; int h= ((d < -1 ? 24 : 1 < d ? -24 : d * 24) + local->tm_hour - gmt->tm_hour); int m= h * 60 + local->tm_min - gmt->tm_min; *offset= m * 60; } #endif return 0; }
On Thu, Mar 24, 2016 at 10:05:17PM -0700, Eliot Miranda wrote:
On Mar 23, 2016, at 6:55 PM, David T. Lewis lewis@mail.msen.com wrote:
On Wed, Mar 23, 2016 at 05:50:19PM -0700, Eliot Miranda wrote:
On Wed, Mar 23, 2016 at 4:51 PM, David T. Lewis lewis@mail.msen.com wrote:
On Wed, Mar 23, 2016 at 04:22:21PM -0700, Eliot Miranda wrote:
Turns out this isn't needed for Cog. I have ioLocalSecondsOffset which answers a value determined at start-up and only changed via ioUpdateVMTimezone, which itself is controlled by primitiveUpdateTimezone, #243. So ioUTCMicroseconds is all that's needed to get at the clock and timezone atomically.
If it is updated at start-up, then it's wrong. Think of daylight savings time transitions.
So update it automatically once a second or some such?
Are you joking, or is that a serious question?
Yes. I see two or three system calls in the code below. gettimeofday, one inside localtime and one inside gmtime. That's expensive.
It's gettimeofday() and localtime(). The #else is fallback for older unix platforms.
In any case, caching the value and updating it periodically does not sound like a good idea to me.
Dave
Confused, Dave
/* implementation of ioUtcWithOffset(), defined in config.h to /* override default definition in src/vm/interp.h */ sqInt sqUnixUtcWithOffset(sqLong *microSeconds, int *offset) { struct timeval timeval; if (gettimeofday(&timeval, NULL) == -1) return -1; time_t seconds= timeval.tv_sec; suseconds_t usec= timeval.tv_usec; *microSeconds= seconds * 1000000 + usec; #if defined(HAVE_TM_GMTOFF) *offset= localtime(&seconds)->tm_gmtoff; #else { struct tm *local= localtime(&seconds); struct tm *gmt= gmtime(&seconds); int d= local->tm_yday - gmt->tm_yday; int h= ((d < -1 ? 24 : 1 < d ? -24 : d * 24) + local->tm_hour - gmt->tm_hour); int m= h * 60 + local->tm_min - gmt->tm_min; *offset= m * 60; } #endif return 0; }
On Fri, Mar 25, 2016 at 8:51 AM, David T. Lewis lewis@mail.msen.com wrote:
On Thu, Mar 24, 2016 at 10:05:17PM -0700, Eliot Miranda wrote:
On Mar 23, 2016, at 6:55 PM, David T. Lewis lewis@mail.msen.com
wrote:
On Wed, Mar 23, 2016 at 05:50:19PM -0700, Eliot Miranda wrote:
On Wed, Mar 23, 2016 at 4:51 PM, David T. Lewis lewis@mail.msen.com
wrote:
On Wed, Mar 23, 2016 at 04:22:21PM -0700, Eliot Miranda wrote:
Turns out this isn't needed for Cog. I have ioLocalSecondsOffset
which
answers a value determined at start-up and only changed via ioUpdateVMTimezone, which itself is controlled by primitiveUpdateTimezone, #243. So ioUTCMicroseconds is all that's
needed
to get at the clock and timezone atomically.
If it is updated at start-up, then it's wrong. Think of daylight
savings
time transitions.
So update it automatically once a second or some such?
Are you joking, or is that a serious question?
Yes. I see two or three system calls in the code below. gettimeofday,
one inside localtime and one inside gmtime. That's expensive.
It's gettimeofday() and localtime(). The #else is fallback for older unix platforms.
As I said, two or three.
In any case, caching the value and updating it periodically does not sound
like a good idea to me.
Why not? Why does the time zone need to be determined on every time call even though it only has a resolution of seconds? If including the timezone in every time call slows down accessing the time by, say, 33%, is it a good idea, when the VM can easily eliminate this overhead?
| c | c := LargePositiveInteger. [1 to: 10000000 do: [:i| c basicNew: 8. c basicNew: 8. c basicNew: 8. c basicNew: 8. c basicNew: 8. c basicNew: 8. c basicNew: 8. c basicNew: 8. c basicNew: 8. c basicNew: 8]] timeToRun 884
[1 to: 10000000 do: [:i| Time utcMicrosecondClock. Time utcMicrosecondClock. Time utcMicrosecondClock. Time utcMicrosecondClock. Time utcMicrosecondClock. Time utcMicrosecondClock. Time utcMicrosecondClock. Time utcMicrosecondClock. Time utcMicrosecondClock. Time utcMicrosecondClock]] timeToRun 6412
6412 / 884.0 7.253393665158371
So the overhead of the system calls involved in accessing time are much greater than the costs of allocating and garbage collecting 64-bit large integer results; much larger.
Dave
Confused, Dave
/* implementation of ioUtcWithOffset(), defined in config.h to /* override default definition in src/vm/interp.h */ sqInt sqUnixUtcWithOffset(sqLong *microSeconds, int *offset) { struct timeval timeval;
if (gettimeofday(&timeval, NULL) == -1) return -1; time_t seconds= timeval.tv_sec; suseconds_t usec= timeval.tv_usec; *microSeconds= seconds * 1000000 + usec; #if defined(HAVE_TM_GMTOFF) *offset= localtime(&seconds)->tm_gmtoff; #else { struct tm *local= localtime(&seconds); struct tm *gmt= gmtime(&seconds); int d= local->tm_yday - gmt->tm_yday; int h= ((d < -1 ? 24 : 1 < d ? -24 : d * 24) + local->tm_hour -
gmt->tm_hour);
int m= h * 60 + local->tm_min - gmt->tm_min; *offset= m * 60; } #endif return 0; }
On Fri, Mar 25, 2016 at 09:22:09AM -0700, Eliot Miranda wrote:
On Fri, Mar 25, 2016 at 8:51 AM, David T. Lewis lewis@mail.msen.com wrote:
On Thu, Mar 24, 2016 at 10:05:17PM -0700, Eliot Miranda wrote:
On Mar 23, 2016, at 6:55 PM, David T. Lewis lewis@mail.msen.com
wrote:
On Wed, Mar 23, 2016 at 05:50:19PM -0700, Eliot Miranda wrote:
On Wed, Mar 23, 2016 at 4:51 PM, David T. Lewis lewis@mail.msen.com
wrote:
> On Wed, Mar 23, 2016 at 04:22:21PM -0700, Eliot Miranda wrote: > > Turns out this isn't needed for Cog. I have ioLocalSecondsOffset
which
> answers a value determined at start-up and only changed > via ioUpdateVMTimezone, which itself is controlled by > primitiveUpdateTimezone, #243. So ioUTCMicroseconds is all that's
needed
> to get at the clock and timezone atomically.
If it is updated at start-up, then it's wrong. Think of daylight
savings
time transitions.
So update it automatically once a second or some such?
Are you joking, or is that a serious question?
Yes. I see two or three system calls in the code below. gettimeofday,
one inside localtime and one inside gmtime. That's expensive.
It's gettimeofday() and localtime(). The #else is fallback for older unix platforms.
As I said, two or three.
In any case, caching the value and updating it periodically does not sound
like a good idea to me.
Why not? Why does the time zone need to be determined on every time call even though it only has a resolution of seconds? If including the timezone in every time call slows down accessing the time by, say, 33%, is it a good idea, when the VM can easily eliminate this overhead?
| c | c := LargePositiveInteger. [1 to: 10000000 do: [:i| c basicNew: 8. c basicNew: 8. c basicNew: 8. c basicNew: 8. c basicNew: 8. c basicNew: 8. c basicNew: 8. c basicNew: 8. c basicNew: 8. c basicNew: 8]] timeToRun 884
[1 to: 10000000 do: [:i| Time utcMicrosecondClock. Time utcMicrosecondClock. Time utcMicrosecondClock. Time utcMicrosecondClock. Time utcMicrosecondClock. Time utcMicrosecondClock. Time utcMicrosecondClock. Time utcMicrosecondClock. Time utcMicrosecondClock. Time utcMicrosecondClock]] timeToRun 6412
6412 / 884.0 7.253393665158371
So the overhead of the system calls involved in accessing time are much greater than the costs of allocating and garbage collecting 64-bit large integer results; much larger.
I tested with the trunk ioUtcWithOffset(), interpreter VM, and calling the primitive with pre-allocated array to avoid garbage collection. I compared the primitive versus a hacked version with the offset value hard coded (equivalant to you suggestion of caching it).
You're right, the "cached" version is almost 4 times faster.
I still think that it is needless complexity. But yes it's faster.
Dave
On 25.03.2016, at 16:51, David T. Lewis lewis@mail.msen.com wrote:
On Thu, Mar 24, 2016 at 10:05:17PM -0700, Eliot Miranda wrote:
I see two or three system calls in the code below. gettimeofday, one inside localtime and one inside gmtime. That's expensive.
It's gettimeofday() and localtime(). The #else is fallback for older unix platforms.
In any case, caching the value and updating it periodically does not sound like a good idea to me.
Well, it’s okay to cheat as long as you won’t get caught (says DI).
Simply “once a second” is not good enough if we check the time 0.5 seconds after DST switch.
If “once a second” was implemented as “once every wall-clock second”, IMHO that would be fine. So the test would have to be something like
(prevUsecs // 1000000) ~= (nowUsecs // 1000000) ifTrue: [self updateOffsetFromUTC]
Right?
- Bert -
On Fri, Mar 25, 2016 at 9:23 AM, Bert Freudenberg bert@freudenbergs.de wrote:
On 25.03.2016, at 16:51, David T. Lewis lewis@mail.msen.com wrote:
On Thu, Mar 24, 2016 at 10:05:17PM -0700, Eliot Miranda wrote:
I see two or three system calls in the code below. gettimeofday, one
inside localtime and one inside gmtime. That's expensive.
It's gettimeofday() and localtime(). The #else is fallback for older
unix platforms.
In any case, caching the value and updating it periodically does not
sound like a good idea to me.
Well, it’s okay to cheat as long as you won’t get caught (says DI).
Simply “once a second” is not good enough if we check the time 0.5 seconds after DST switch.
If “once a second” was implemented as “once every wall-clock second”, IMHO that would be fine. So the test would have to be something like
(prevUsecs // 1000000) ~= (nowUsecs // 1000000) ifTrue: [self
updateOffsetFromUTC]
Right?
Excellent point. So the drift algorithm to provide an accurate clock can be extended to check the time zone whenever the new time is at a different second to the previous value.
- Bert -
_,,,^..^,,,_ best, Eliot
On 25.03.2016, at 17:47, Eliot Miranda eliot.miranda@gmail.com wrote:
On Fri, Mar 25, 2016 at 9:23 AM, Bert Freudenberg <bert@freudenbergs.de mailto:bert@freudenbergs.de> wrote: Well, it’s okay to cheat as long as you won’t get caught (says DI).
Simply “once a second” is not good enough if we check the time 0.5 seconds after DST switch.
If “once a second” was implemented as “once every wall-clock second”, IMHO that would be fine. So the test would have to be something like
(prevUsecs // 1000000) ~= (nowUsecs // 1000000) ifTrue: [self updateOffsetFromUTC]
Right?
Excellent point. So the drift algorithm to provide an accurate clock can be extended to check the time zone whenever the new time is at a different second to the previous value.
Drifting makes this way more complicated I’d think … unless there is an OS function to convert the drifted UTC time into local? IF the VM time and system time differ, you can’t just ask the OS for the “now” local time.
- Bert -
On Fri, Mar 25, 2016 at 10:08 AM, Bert Freudenberg bert@freudenbergs.de wrote:
On 25.03.2016, at 17:47, Eliot Miranda eliot.miranda@gmail.com wrote:
On Fri, Mar 25, 2016 at 9:23 AM, Bert Freudenberg bert@freudenbergs.de wrote:
Well, it’s okay to cheat as long as you won’t get caught (says DI).
Simply “once a second” is not good enough if we check the time 0.5 seconds after DST switch.
If “once a second” was implemented as “once every wall-clock second”, IMHO that would be fine. So the test would have to be something like
(prevUsecs // 1000000) ~= (nowUsecs // 1000000) ifTrue: [self
updateOffsetFromUTC]
Right?
Excellent point. So the drift algorithm to provide an accurate clock can be extended to check the time zone whenever the new time is at a different second to the previous value.
Drifting makes this way more complicated I’d think … unless there is an OS function to convert the drifted UTC time into local? IF the VM time and system time differ, you can’t just ask the OS for the “now” local time.
I wrote up the algorithm I propose; see http://forum.world.st/Time-millisecondClockValue-was-The-Trunk-Morphic-mt-10...
It's not that complicated and extending it is straight-forward, given that the algorithm already maintains the last time computed. When I've time I'll post a revision.
_,,,^..^,,,_ best, Eliot
On 25 Mar 2016, at 18:49, Eliot Miranda eliot.miranda@gmail.com wrote:
On Fri, Mar 25, 2016 at 10:08 AM, Bert Freudenberg bert@freudenbergs.de wrote:
On 25.03.2016, at 17:47, Eliot Miranda eliot.miranda@gmail.com wrote:
On Fri, Mar 25, 2016 at 9:23 AM, Bert Freudenberg bert@freudenbergs.de wrote: Well, it’s okay to cheat as long as you won’t get caught (says DI).
Simply “once a second” is not good enough if we check the time 0.5 seconds after DST switch.
If “once a second” was implemented as “once every wall-clock second”, IMHO that would be fine. So the test would have to be something like
(prevUsecs // 1000000) ~= (nowUsecs // 1000000) ifTrue: [self updateOffsetFromUTC]
Right?
Excellent point. So the drift algorithm to provide an accurate clock can be extended to check the time zone whenever the new time is at a different second to the previous value.
Drifting makes this way more complicated I’d think … unless there is an OS function to convert the drifted UTC time into local? IF the VM time and system time differ, you can’t just ask the OS for the “now” local time.
I wrote up the algorithm I propose; see http://forum.world.st/Time-millisecondClockValue-was-The-Trunk-Morphic-mt-10...
It's not that complicated and extending it is straight-forward, given that the algorithm already maintains the last time computed. When I've time I'll post a revision.
_,,,^..^,,,_ best, Eliot
Terminology confusion. In your post "local time" means "wall clock utc". I meant "time in local time zone".
But I see that there is indeed an OS function to convert a given UTC time to one in the local time zone. So yes, that sounds like a plan.
- Bert -
On Sat, Mar 26, 2016 at 4:30 AM, Bert Freudenberg bert@freudenbergs.de wrote:
On 25 Mar 2016, at 18:49, Eliot Miranda eliot.miranda@gmail.com wrote:
On Fri, Mar 25, 2016 at 10:08 AM, Bert Freudenberg bert@freudenbergs.de wrote:
On 25.03.2016, at 17:47, Eliot Miranda eliot.miranda@gmail.com wrote:
On Fri, Mar 25, 2016 at 9:23 AM, Bert Freudenberg bert@freudenbergs.de wrote:
Well, it’s okay to cheat as long as you won’t get caught (says DI).
Simply “once a second” is not good enough if we check the time 0.5 seconds after DST switch.
If “once a second” was implemented as “once every wall-clock second”, IMHO that would be fine. So the test would have to be something like
(prevUsecs // 1000000) ~= (nowUsecs // 1000000) ifTrue: [self
updateOffsetFromUTC]
Right?
Excellent point. So the drift algorithm to provide an accurate clock can be extended to check the time zone whenever the new time is at a different second to the previous value.
Drifting makes this way more complicated I’d think … unless there is an OS function to convert the drifted UTC time into local? IF the VM time and system time differ, you can’t just ask the OS for the “now” local time.
I wrote up the algorithm I propose; see http://forum.world.st/Time-millisecondClockValue-was-The-Trunk-Morphic-mt-10...
It would be useful if the 'now' instance variable in VMClock explicitly indicated in its name whether it was utcNow or localNow. Even reading the man pages for gettimeofday() and clock_gettime() its not clear to me which it is. I can only guess that in the face of changing timezones, its not a good idea to drift localNow, and better to drift utcNow and add a constant timeZoneOffset.
It's not that complicated and extending it is straight-forward, given that the algorithm already maintains the last time computed. When I've time I'll post a revision.
_,,,^..^,,,_ best, Eliot
Terminology confusion. In your post "local time" means "wall clock utc". I meant "time in local time zone".
But I see that there is indeed an OS function to convert a given UTC time to one in the local time zone. So yes, that sounds like a plan.
Microsoft, Linux & OSX all seem to agree that "Local-Time" is timezoned-wall-clock, and "System-Time" is utc-wall-clock. So maybe this is a worthwhile convention to continue?
"The localtime() function converts the calendar time to broken-down time representation, expressed relative to the user's specified timezone." [1]
"The system time is always kept in Coordinated Universal Time (UTC) and converted in applications to local time as needed. Local time is the actual time in your current time zone, taking into account daylight saving time (DST). [2]
"GetLocalTime - This function retrieves the current local date and time." [3]
"GetSystemTime - This function retrieves the current system date and time. The system time is expressed in UTC." [4]
cheers -ben
P.S. I also found [5] interesting
[1] https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPa... [2] https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/htm... [3] https://msdn.microsoft.com/en-us/library/ee487966.aspx [4] https://msdn.microsoft.com/en-us/library/ee488017.aspx [5] https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).a...
On Thu, Mar 24, 2016 at 7:12 AM, David T. Lewis lewis@mail.msen.com wrote:
Hi Levente,
On Wed, Mar 23, 2016 at 05:01:35PM +0100, Levente Uzonyi wrote:
On Sun, 20 Mar 2016, David T. Lewis wrote:
The four policies are:
#acceptPlatformTime - Accept the time value provided by the system platform, even in this allows time to appear to move backwards when the clock is adjusted. Simple, fast, and no hidden side effects.
#monotonicAllowDuplicates - Accept the time value provided by the system platform unless it is less that the last clock tick. This protects for system clock adjustments. Side effects unlikely. Does not ensure unique values on repeated calls.
#monotonicForceMicrosecondIncrement - If the time value is less than or equal to the value from the last call, force increment by one microsecond. This ensures integral values of UTC time, but increments the time value by a full microsecond.
#monotonicForceNanosecondIncrement - If the time value is less than or equal to the value from the last call, force increment by one nanosecond. This it functionally compatible with previous Squeak practice, but is computationally expensive and results in time values represented as fractions, which might be a problem for some database applications.
I think this covers most possible use cases. What I was originally thinking about was the addition of another field to hold the nanosecond part, since that would have only been set by the image itself, so the primitive could still have been used to initialize the rest. That we we could have avoided the use of fractions at the cost of having another field per object even when there's no need for high accuracy.
I'm actually quite happy with the idea of the value being a Number that is an Integer for all reasonable values that could ever be supplied by the VM, but that might be a Fraction if we want to represent time values at some higher precision. Mainly I like it because it seems good conceptually to think of time as continuous, and not as discreet ticks of a clock.
It also works well computationally, because the normal case uses integer values (immediates in 64-bit Spur), and because Fractions involve two integer values, which presumably would be no worse than a design that added another field. But given that none of our computers or VMs can report time to a precision greater than microseconds, I think that we can safely ignore the issue for another 20 years or so ;-)
Its not so far away. Three contemporary examples...
* Systems that synchronise time from GPS do so "typically well within 40 nanoseconds" [1]
* The distributed clock of EtherCAT networks synchronises nodes to better than 100ns. See slide 23 [2] and figure 7 [3].
* IEEE 1588 provides synchronised network time "in the range of +/-200ns between some nodes and even +/-50ns and less between the better ones." [4]
This matters for applications like financial trading, motion control and sequence-of-event logging on industrial plants. Maybe not Smalltalk's bread and butter, but the last two are areas I'd like to use it at a co-ordinator level.
cheers -ben
[1] http://gpsinformation.net/main/gpstime.htm [2] https://ece.uwaterloo.ca/~sfischme/rate/Joey-Stubbs-Ethercat.pdf [3] http://www.iestcfa.org/bestpaper/wfcs10/wfcs10_bpa.pdf [4] https://home.zhaw.ch/~wei/IEEE1588/embedded_World_05_Contribution_final.pdf
On Fri, Mar 25, 2016 at 12:48:17AM +0800, Ben Coman wrote:
On Thu, Mar 24, 2016 at 7:12 AM, David T. Lewis lewis@mail.msen.com wrote:
I'm actually quite happy with the idea of the value being a Number that is an Integer for all reasonable values that could ever be supplied by the VM, but that might be a Fraction if we want to represent time values at some higher precision. Mainly I like it because it seems good conceptually to think of time as continuous, and not as discreet ticks of a clock.
It also works well computationally, because the normal case uses integer values (immediates in 64-bit Spur), and because Fractions involve two integer values, which presumably would be no worse than a design that added another field. But given that none of our computers or VMs can report time to a precision greater than microseconds, I think that we can safely ignore the issue for another 20 years or so ;-)
Its not so far away. Three contemporary examples...
- Systems that synchronise time from GPS do so "typically well within
40 nanoseconds" [1]
- The distributed clock of EtherCAT networks synchronises nodes to
better than 100ns. See slide 23 [2] and figure 7 [3].
- IEEE 1588 provides synchronised network time "in the range of
+/-200ns between some nodes and even +/-50ns and less between the better ones." [4]
This matters for applications like financial trading, motion control and sequence-of-event logging on industrial plants. Maybe not Smalltalk's bread and butter, but the last two are areas I'd like to use it at a co-ordinator level.
cheers -ben
[1] http://gpsinformation.net/main/gpstime.htm [2] https://ece.uwaterloo.ca/~sfischme/rate/Joey-Stubbs-Ethercat.pdf [3] http://www.iestcfa.org/bestpaper/wfcs10/wfcs10_bpa.pdf [4] https://home.zhaw.ch/~wei/IEEE1588/embedded_World_05_Contribution_final.pdf
Indeed you are quite right. And thank you for those links.
Our current Squeak platforms are certainly not real time systems, but our representation of DateAndTime should not be limited by that.
I guess that all I can add at this point is my basic premise that a simple representation of a time scale is better than a complicated one. For now, the idea of microseconds as the unit of measure seems to work quite well. Maybe in the future some different representation will be better.
At higher levels of precision, I suspect that Fraction (or ScaledDecimal, which is more readable) will be a very efficient representation. And since DateAndTime instances are likely to be important for databases, forcing all of the values to be Fraction (i.e. two integers) might be a good policy. But for now, microseconds since the epoch works well, yielding Integer representations in all practical cases, and overflowing into Fraction if nanosecond precision is needed.
Dave
I always forget to mention, even though I have had this idea since you had introduced primitiveUtcWithOffset, that it would be better if the primitive could take an optional argument to store the values in the first two slots of it instead of creating a new Array. If it's too much burden to accept any object, then the argument type can be limited to Array. This change would make it possible to decrease the GC pressure when many timestamps are created in a row.
Levente
On Sat, 12 Mar 2016, David T. Lewis wrote:
On Mon, Mar 07, 2016 at 12:21:38AM -0500, David T. Lewis wrote:
On Sun, May 24, 2015 at 12:36:02PM -0400, David T. Lewis wrote:
UTCDateAndTime is a UTC based implementation of class DateAndTime with one instance variable representing the magnitude of the point in time, and another representing local time zone offset.
I have updated the UTCDateAndTime package to make it loadable in the latest Squeak trunk and Spur.
Has anyone looked at this yet? Any interest?
Dave
A new Monticello repository is at http://www.squeaksource.com/UTCDateAndTime. The home page (with a new SAR) is at http://wiki.squeak.org/squeak/6197.
Starting with an updated trunk image, you can load UTCDateAndTime in two ways:
- Open the http://www.squeaksource.com/UTCDateAndTime repository, and load
the MCZ files in sequence beginning with Chronology-Core-dtl.3.
- In a preferences browser, in category 'updates' set the 'Update URL'
preference to 'http://www.squeaksource.com/UTCDateAndTime', and do world -> help... -> update code from server.
The main objective of UTCDateAndTime is to make DateAndTime conceptually simpler, but a happy side effect is that it is also significantly faster than the old implementation.
Dave
I had the same idea, and I already implemented it in trunk interpreter VMMaker, but it is probably not in oscog yet. I did not add it on the image side, although we could do so if we update the VMs.
Dave
I always forget to mention, even though I have had this idea since you had introduced primitiveUtcWithOffset, that it would be better if the primitive could take an optional argument to store the values in the first two slots of it instead of creating a new Array. If it's too much burden to accept any object, then the argument type can be limited to Array. This change would make it possible to decrease the GC pressure when many timestamps are created in a row.
Levente
On Sat, 12 Mar 2016, David T. Lewis wrote:
On Mon, Mar 07, 2016 at 12:21:38AM -0500, David T. Lewis wrote:
On Sun, May 24, 2015 at 12:36:02PM -0400, David T. Lewis wrote:
UTCDateAndTime is a UTC based implementation of class DateAndTime with one instance variable representing the magnitude of the point in time, and another representing local time zone offset.
I have updated the UTCDateAndTime package to make it loadable in the latest Squeak trunk and Spur.
Has anyone looked at this yet? Any interest?
Dave
A new Monticello repository is at http://www.squeaksource.com/UTCDateAndTime. The home page (with a new SAR) is at http://wiki.squeak.org/squeak/6197.
Starting with an updated trunk image, you can load UTCDateAndTime in two ways:
- Open the http://www.squeaksource.com/UTCDateAndTime repository, and
load the MCZ files in sequence beginning with Chronology-Core-dtl.3.
- In a preferences browser, in category 'updates' set the 'Update URL'
preference to 'http://www.squeaksource.com/UTCDateAndTime', and do world -> help... -> update code from server.
The main objective of UTCDateAndTime is to make DateAndTime conceptually simpler, but a happy side effect is that it is also significantly faster than the old implementation.
Dave
Apologies, this is not right. I was replying from a cell phone and my recollection was wrong.
I did at one point implement a #primitiveUtcWithOffset that could receive an array of size two as an argument into which the result values are stored, instead if allocating the array in the primitive. However, I did *not* commit it to VMMaker, and it is not in any currently available VMs.
I think I decided at the time that this approach was dangerous because it would invite problems in cases involving multiple processes, where some other process might call the primitive using the same array. In that case the time value in the array would magically change without the first process being aware.
I still think that it is a good idea, but maybe not worth the risk unless there is a noticable affect of performance or GC activity. Of course, adding the capability to the primitive would not force anyone to actually use it that way.
Sorry for the misinformation.
Dave
On Sat, Mar 12, 2016 at 11:37:55PM -0500, David T. Lewis wrote:
I had the same idea, and I already implemented it in trunk interpreter VMMaker, but it is probably not in oscog yet. I did not add it on the image side, although we could do so if we update the VMs.
Dave
I always forget to mention, even though I have had this idea since you had introduced primitiveUtcWithOffset, that it would be better if the primitive could take an optional argument to store the values in the first two slots of it instead of creating a new Array. If it's too much burden to accept any object, then the argument type can be limited to Array. This change would make it possible to decrease the GC pressure when many timestamps are created in a row.
Levente
On Sat, 12 Mar 2016, David T. Lewis wrote:
On Mon, Mar 07, 2016 at 12:21:38AM -0500, David T. Lewis wrote:
On Sun, May 24, 2015 at 12:36:02PM -0400, David T. Lewis wrote:
UTCDateAndTime is a UTC based implementation of class DateAndTime with one instance variable representing the magnitude of the point in time, and another representing local time zone offset.
I have updated the UTCDateAndTime package to make it loadable in the latest Squeak trunk and Spur.
Has anyone looked at this yet? Any interest?
Dave
A new Monticello repository is at http://www.squeaksource.com/UTCDateAndTime. The home page (with a new SAR) is at http://wiki.squeak.org/squeak/6197.
Starting with an updated trunk image, you can load UTCDateAndTime in two ways:
- Open the http://www.squeaksource.com/UTCDateAndTime repository, and
load the MCZ files in sequence beginning with Chronology-Core-dtl.3.
- In a preferences browser, in category 'updates' set the 'Update URL'
preference to 'http://www.squeaksource.com/UTCDateAndTime', and do world -> help... -> update code from server.
The main objective of UTCDateAndTime is to make DateAndTime conceptually simpler, but a happy side effect is that it is also significantly faster than the old implementation.
Dave
On Sun, 13 Mar 2016, David T. Lewis wrote:
Apologies, this is not right. I was replying from a cell phone and my recollection was wrong.
I did at one point implement a #primitiveUtcWithOffset that could receive an array of size two as an argument into which the result values are stored, instead if allocating the array in the primitive. However, I did *not* commit it to VMMaker, and it is not in any currently available VMs.
I think I decided at the time that this approach was dangerous because it would invite problems in cases involving multiple processes, where some other process might call the primitive using the same array. In that case the time value in the array would magically change without the first process being aware.
That could only happen if the Array would be shared by multiple processes. For example if there were a dedicated class variable to retrieve the values from the VM, but that would be nothing but bad design.
Why I thought that the argument should be of any Object with two slots is that this would allow us to use the DateAndTime instance itself to fetch the values into. Or anyone could come up with their own class to store timestamps and still be able to use this primitive.
I still think that it is a good idea, but maybe not worth the risk unless there is a noticable affect of performance or GC activity. Of course, adding the capability to the primitive would not force anyone to actually use it that way.
We have a long running application, which most of the time generates a few hundred timestamps per second, but sometimes is goes up to the thousands range. That would definitely benefit from such feature.
Levente
Sorry for the misinformation.
Dave
On Sat, Mar 12, 2016 at 11:37:55PM -0500, David T. Lewis wrote:
I had the same idea, and I already implemented it in trunk interpreter VMMaker, but it is probably not in oscog yet. I did not add it on the image side, although we could do so if we update the VMs.
Dave
I always forget to mention, even though I have had this idea since you had introduced primitiveUtcWithOffset, that it would be better if the primitive could take an optional argument to store the values in the first two slots of it instead of creating a new Array. If it's too much burden to accept any object, then the argument type can be limited to Array. This change would make it possible to decrease the GC pressure when many timestamps are created in a row.
Levente
On Sat, 12 Mar 2016, David T. Lewis wrote:
On Mon, Mar 07, 2016 at 12:21:38AM -0500, David T. Lewis wrote:
On Sun, May 24, 2015 at 12:36:02PM -0400, David T. Lewis wrote:
UTCDateAndTime is a UTC based implementation of class DateAndTime with one instance variable representing the magnitude of the point in time, and another representing local time zone offset.
I have updated the UTCDateAndTime package to make it loadable in the latest Squeak trunk and Spur.
Has anyone looked at this yet? Any interest?
Dave
A new Monticello repository is at http://www.squeaksource.com/UTCDateAndTime. The home page (with a new SAR) is at http://wiki.squeak.org/squeak/6197.
Starting with an updated trunk image, you can load UTCDateAndTime in two ways:
- Open the http://www.squeaksource.com/UTCDateAndTime repository, and
load the MCZ files in sequence beginning with Chronology-Core-dtl.3.
- In a preferences browser, in category 'updates' set the 'Update URL'
preference to 'http://www.squeaksource.com/UTCDateAndTime', and do world -> help... -> update code from server.
The main objective of UTCDateAndTime is to make DateAndTime conceptually simpler, but a happy side effect is that it is also significantly faster than the old implementation.
Dave
On Sun, Mar 13, 2016 at 10:28:19PM +0100, Levente Uzonyi wrote:
On Sun, 13 Mar 2016, David T. Lewis wrote:
Apologies, this is not right. I was replying from a cell phone and my recollection was wrong.
I did at one point implement a #primitiveUtcWithOffset that could receive an array of size two as an argument into which the result values are stored, instead if allocating the array in the primitive. However, I did *not* commit it to VMMaker, and it is not in any currently available VMs.
I think I decided at the time that this approach was dangerous because it would invite problems in cases involving multiple processes, where some other process might call the primitive using the same array. In that case the time value in the array would magically change without the first process being aware.
That could only happen if the Array would be shared by multiple processes. For example if there were a dedicated class variable to retrieve the values from the VM, but that would be nothing but bad design.
Well yes, but bad design is a very common failure mode ;-)
Why I thought that the argument should be of any Object with two slots is that this would allow us to use the DateAndTime instance itself to fetch the values into. Or anyone could come up with their own class to store timestamps and still be able to use this primitive.
That is absolutely brilliant! What a great idea.
DateAndTime class>>now ^self basicNew initializeFromPrimitive
Dave
Urk. Sorry for the confusion, but I was looking at the wrong image and I see now that my original statement was correct:
"I had the same idea, and I already implemented it in trunk interpreter VMMaker, but it is probably not in oscog yet. I did not add it on the image side, although we could do so if we update the VMs."
This is in the trunk VMM (interpreter VM), though not in Cog/Spur yet. Better yet, it already works with Levente's idea (see below) of passing the DateAndTime instance to the primitive. No further changes to the primitive are needed to do this.
Therefore the following works in a Squeak 4.6 image with UTCDateAndTime loaded, and running on an interpreter VM:
DateAndTime>>initializeFromPrimitive ^Time primPosixMicrosecondClockWithOffset: self
DateAndTime basicNew initializeFromPrimitive ==> 2016-03-14T21:38:49.81355-04:00
So I think this is a very good idea that just needs a couple of minor VM updates to make it available.
Dave
On Sun, Mar 13, 2016 at 03:03:55PM -0400, David T. Lewis wrote:
Apologies, this is not right. I was replying from a cell phone and my recollection was wrong.
I did at one point implement a #primitiveUtcWithOffset that could receive an array of size two as an argument into which the result values are stored, instead if allocating the array in the primitive. However, I did *not* commit it to VMMaker, and it is not in any currently available VMs.
I think I decided at the time that this approach was dangerous because it would invite problems in cases involving multiple processes, where some other process might call the primitive using the same array. In that case the time value in the array would magically change without the first process being aware.
I still think that it is a good idea, but maybe not worth the risk unless there is a noticable affect of performance or GC activity. Of course, adding the capability to the primitive would not force anyone to actually use it that way.
Sorry for the misinformation.
Dave
On Sat, Mar 12, 2016 at 11:37:55PM -0500, David T. Lewis wrote:
I had the same idea, and I already implemented it in trunk interpreter VMMaker, but it is probably not in oscog yet. I did not add it on the image side, although we could do so if we update the VMs.
Dave
I always forget to mention, even though I have had this idea since you had introduced primitiveUtcWithOffset, that it would be better if the primitive could take an optional argument to store the values in the first two slots of it instead of creating a new Array. If it's too much burden to accept any object, then the argument type can be limited to Array. This change would make it possible to decrease the GC pressure when many timestamps are created in a row.
Levente
On Sat, 12 Mar 2016, David T. Lewis wrote:
On Mon, Mar 07, 2016 at 12:21:38AM -0500, David T. Lewis wrote:
On Sun, May 24, 2015 at 12:36:02PM -0400, David T. Lewis wrote:
UTCDateAndTime is a UTC based implementation of class DateAndTime with one instance variable representing the magnitude of the point in time, and another representing local time zone offset.
I have updated the UTCDateAndTime package to make it loadable in the latest Squeak trunk and Spur.
Has anyone looked at this yet? Any interest?
Dave
A new Monticello repository is at http://www.squeaksource.com/UTCDateAndTime. The home page (with a new SAR) is at http://wiki.squeak.org/squeak/6197.
Starting with an updated trunk image, you can load UTCDateAndTime in two ways:
- Open the http://www.squeaksource.com/UTCDateAndTime repository, and
load the MCZ files in sequence beginning with Chronology-Core-dtl.3.
- In a preferences browser, in category 'updates' set the 'Update URL'
preference to 'http://www.squeaksource.com/UTCDateAndTime', and do world -> help... -> update code from server.
The main objective of UTCDateAndTime is to make DateAndTime conceptually simpler, but a happy side effect is that it is also significantly faster than the old implementation.
Dave
If we have to touch the VM for this anyway, is there any reason not to use the Smalltalk epoch for this primitive, as Eliot suggested? This would put it in line with the other primitives (and make it slightly cheaper to use the skewed VM time).
- Bert -
On 15.03.2016, at 02:50, David T. Lewis lewis@mail.msen.com wrote:
Urk. Sorry for the confusion, but I was looking at the wrong image and I see now that my original statement was correct:
"I had the same idea, and I already implemented it in trunk interpreter VMMaker, but it is probably not in oscog yet. I did not add it on the image side, although we could do so if we update the VMs."
This is in the trunk VMM (interpreter VM), though not in Cog/Spur yet. Better yet, it already works with Levente's idea (see below) of passing the DateAndTime instance to the primitive. No further changes to the primitive are needed to do this.
Therefore the following works in a Squeak 4.6 image with UTCDateAndTime loaded, and running on an interpreter VM:
DateAndTime>>initializeFromPrimitive ^Time primPosixMicrosecondClockWithOffset: self
DateAndTime basicNew initializeFromPrimitive ==> 2016-03-14T21:38:49.81355-04:00
So I think this is a very good idea that just needs a couple of minor VM updates to make it available.
Dave
On Sun, Mar 13, 2016 at 03:03:55PM -0400, David T. Lewis wrote:
Apologies, this is not right. I was replying from a cell phone and my recollection was wrong.
I did at one point implement a #primitiveUtcWithOffset that could receive an array of size two as an argument into which the result values are stored, instead if allocating the array in the primitive. However, I did *not* commit it to VMMaker, and it is not in any currently available VMs.
I think I decided at the time that this approach was dangerous because it would invite problems in cases involving multiple processes, where some other process might call the primitive using the same array. In that case the time value in the array would magically change without the first process being aware.
I still think that it is a good idea, but maybe not worth the risk unless there is a noticable affect of performance or GC activity. Of course, adding the capability to the primitive would not force anyone to actually use it that way.
Sorry for the misinformation.
Dave
On Sat, Mar 12, 2016 at 11:37:55PM -0500, David T. Lewis wrote:
I had the same idea, and I already implemented it in trunk interpreter VMMaker, but it is probably not in oscog yet. I did not add it on the image side, although we could do so if we update the VMs.
Dave
I always forget to mention, even though I have had this idea since you had introduced primitiveUtcWithOffset, that it would be better if the primitive could take an optional argument to store the values in the first two slots of it instead of creating a new Array. If it's too much burden to accept any object, then the argument type can be limited to Array. This change would make it possible to decrease the GC pressure when many timestamps are created in a row.
Levente
On Sat, 12 Mar 2016, David T. Lewis wrote:
On Mon, Mar 07, 2016 at 12:21:38AM -0500, David T. Lewis wrote:
On Sun, May 24, 2015 at 12:36:02PM -0400, David T. Lewis wrote: > UTCDateAndTime is a UTC based implementation of class DateAndTime with > one instance variable representing the magnitude of the point in time, > and another representing local time zone offset.
I have updated the UTCDateAndTime package to make it loadable in the latest Squeak trunk and Spur.
Has anyone looked at this yet? Any interest?
Dave
A new Monticello repository is at http://www.squeaksource.com/UTCDateAndTime. The home page (with a new SAR) is at http://wiki.squeak.org/squeak/6197.
Starting with an updated trunk image, you can load UTCDateAndTime in two ways:
- Open the http://www.squeaksource.com/UTCDateAndTime repository, and
load the MCZ files in sequence beginning with Chronology-Core-dtl.3.
- In a preferences browser, in category 'updates' set the 'Update URL'
preference to 'http://www.squeaksource.com/UTCDateAndTime', and do world -> help... -> update code from server.
The main objective of UTCDateAndTime is to make DateAndTime conceptually simpler, but a happy side effect is that it is also significantly faster than the old implementation.
Dave
On Tue, Mar 15, 2016 at 10:02:20AM +0100, Bert Freudenberg wrote:
If we have to touch the VM for this anyway, is there any reason not to use the Smalltalk epoch for this primitive, as Eliot suggested? This would put it in line with the other primitives (and make it slightly cheaper to use the skewed VM time).
- Bert -
There is no requirement to touch the VM, the current implementation in Cog/Spur is sufficient. Levente's suggestion is a nice enhancement but not a requirement. I have already added this to the UTCDateAndTime package in such a way that Levente's approach is used if the VM supports it, otherwise my original implementation is used at the cost of one extra Array instantiation when calling DateAndTime now.
I would not want to change the current primitive, but it would be easy to add an additional one with a different name such that a transition could be done at a later time if someone wanted to do so. This is not a numbered primitive, so it is not a problem to add a different implementation with a slightly different name.
From the point of view of UTCDateAndTime, using the Smalltalk epoch would be
a disadvantage because Olson time zone tables are based on Posix epoch. This means that you would be converting Posix -> Smalltalk in the VM, then converting it back to the Posix time base in the image.
The background on this is that I would like to be able to do a clean integration of TimeZoneDatabase (the Olson tz tables) with DateAndTime, and get rid of the historical baggage associated with Squeak's original reliance on local time in the VM. The overall result should be much easier to understand and test, and will use concepts that are well documented on wikipedia.
Dave
On 15.03.2016, at 02:50, David T. Lewis lewis@mail.msen.com wrote:
Urk. Sorry for the confusion, but I was looking at the wrong image and I see now that my original statement was correct:
"I had the same idea, and I already implemented it in trunk interpreter VMMaker, but it is probably not in oscog yet. I did not add it on the image side, although we could do so if we update the VMs."
This is in the trunk VMM (interpreter VM), though not in Cog/Spur yet. Better yet, it already works with Levente's idea (see below) of passing the DateAndTime instance to the primitive. No further changes to the primitive are needed to do this.
Therefore the following works in a Squeak 4.6 image with UTCDateAndTime loaded, and running on an interpreter VM:
DateAndTime>>initializeFromPrimitive ^Time primPosixMicrosecondClockWithOffset: self
DateAndTime basicNew initializeFromPrimitive ==> 2016-03-14T21:38:49.81355-04:00
So I think this is a very good idea that just needs a couple of minor VM updates to make it available.
Dave
On Sun, Mar 13, 2016 at 03:03:55PM -0400, David T. Lewis wrote:
Apologies, this is not right. I was replying from a cell phone and my recollection was wrong.
I did at one point implement a #primitiveUtcWithOffset that could receive an array of size two as an argument into which the result values are stored, instead if allocating the array in the primitive. However, I did *not* commit it to VMMaker, and it is not in any currently available VMs.
I think I decided at the time that this approach was dangerous because it would invite problems in cases involving multiple processes, where some other process might call the primitive using the same array. In that case the time value in the array would magically change without the first process being aware.
I still think that it is a good idea, but maybe not worth the risk unless there is a noticable affect of performance or GC activity. Of course, adding the capability to the primitive would not force anyone to actually use it that way.
Sorry for the misinformation.
Dave
On Sat, Mar 12, 2016 at 11:37:55PM -0500, David T. Lewis wrote:
I had the same idea, and I already implemented it in trunk interpreter VMMaker, but it is probably not in oscog yet. I did not add it on the image side, although we could do so if we update the VMs.
Dave
I always forget to mention, even though I have had this idea since you had introduced primitiveUtcWithOffset, that it would be better if the primitive could take an optional argument to store the values in the first two slots of it instead of creating a new Array. If it's too much burden to accept any object, then the argument type can be limited to Array. This change would make it possible to decrease the GC pressure when many timestamps are created in a row.
Levente
On Sat, 12 Mar 2016, David T. Lewis wrote:
On Mon, Mar 07, 2016 at 12:21:38AM -0500, David T. Lewis wrote: > On Sun, May 24, 2015 at 12:36:02PM -0400, David T. Lewis wrote: >> UTCDateAndTime is a UTC based implementation of class DateAndTime with >> one instance variable representing the magnitude of the point in time, >> and another representing local time zone offset. > > I have updated the UTCDateAndTime package to make it loadable in the > latest > Squeak trunk and Spur.
Has anyone looked at this yet? Any interest?
Dave
> > A new Monticello repository is at > http://www.squeaksource.com/UTCDateAndTime. > The home page (with a new SAR) is at > http://wiki.squeak.org/squeak/6197. > > Starting with an updated trunk image, you can load UTCDateAndTime in > two ways: > > 1) Open the http://www.squeaksource.com/UTCDateAndTime repository, and > load > the MCZ files in sequence beginning with Chronology-Core-dtl.3. > > 2) In a preferences browser, in category 'updates' set the 'Update URL' > preference to 'http://www.squeaksource.com/UTCDateAndTime', and do > world -> help... -> update code from server. > > The main objective of UTCDateAndTime is to make DateAndTime > conceptually > simpler, but a happy side effect is that it is also significantly > faster > than the old implementation. > > Dave
I would like to consider offering UTCDateAndTime for inclusion in trunk.
On 64-bit Spur, overall performance is almost twice that of the base Chronology package. In addition, the representation of DateAndTime as Posix time plus time zone offset is simpler and easier to test and understand.
I cannot easily put this into the inbox, but loading the package into a trunk image is done as follows:
(MCMcmUpdater updateMapNamed: 'update' repository: 'http://www.squeaksource.com/UTCDateAndTime') doUpdate: false.
I have not modified any of the Chronology tests. After loading UTCDateAndTime into a trunk image, here are the tests that will fail, along with my explanation for the failures:
DateAndTimeEpochTest>>testHash - DateAndTime>>hash works differently now. Test should be either updated or eliminated.
DateAndTimeLeapTest>>testAsSeconds - Discussion required. I claim that #asSeconds can only make sense if it means elapsed seconds since the epoch. The prior implemention and the test are both wrong.
DateAndTimeLeapTest>>testHash - DateAndTime>>hash works differently now. Test should be either updated or eliminated.
DateAndTimeTest>>testPrecision - Discussion required. It is simply wrong to assume that two calls to DateAndTime class>>now will always answer different values, and it is even more wrong to fudge the clock accessors to make it appear to be doing this when it is not. Yes I know that certain database applications require distinct time stamps, but hacking the actual system clock is not the right thing to do.
TimespanDoTest>>testDatesDo - Need to change the test setUp method. The original intent is to test date iteration using a time span begining with a UTC midnight. Test will pass if the start time is constructed accordingly. Note however that date iteration is suspect for durations starting at times other than midnight in the local time zone, so additional tests may be needed.
TimespanDoTest>>testNext - Same issue as testDatesDo, fix the setUp method and the test will pass, but additional tests may be needed.
The necessary #primitiveUtcWithOffset is present in all Cog/Spur/interpreter VMs. It is an optional named primitive (not numbered). If not present, the fallback code uses the Posix epoch for all new time values, resulting in a runnable image but with incorrect time stamps for new DateAndTime instances. Falling back to the original millisecond clock logic and primitives is possible, but it seemed to me to be an unnecessary complication so I got rid of it.
Does anyone think that adding UTCDateAndTime to trunk is /not/ a good thing to do?
Dave
Hi David, thanks for proceeding with caution, clearly, this is a core framework upon which everyone's Squeak everything depends. Some questions:
DateAndTimeLeapTest>>testAsSeconds - Discussion required. I claim that #asSeconds can only make sense if it means elapsed seconds since the epoch. The prior implemention and the test are both wrong.
Is there a context where the number of seconds since the epoch would ever "make sense" except to the software which needs to compare it to another result of #asSeconds? Why does it matter what number we start at?
DateAndTimeLeapTest>>testHash - DateAndTime>>hash works differently now. Test should be either updated or eliminated.
DateAndTimeTest>>testPrecision - Discussion required. It is simply wrong to assume that two calls to DateAndTime class>>now will always answer different values, and it is even more wrong to fudge the clock accessors to make it appear to be doing this when it is not. Yes I know that certain database applications require distinct time stamps, but hacking the actual system clock is not the right thing to do.
TimespanDoTest>>testDatesDo - Need to change the test setUp method. The original intent is to test date iteration using a time span begining with a UTC midnight. Test will pass if the start time is constructed accordingly. Note however that date iteration is suspect for durations starting at times other than midnight in the local time zone, so additional tests may be needed.
TimespanDoTest>>testNext - Same issue as testDatesDo, fix the setUp method and the test will pass, but additional tests may be needed.
Can you clarify why the setUp method needs to be changed? What is the core difference between your framework and Chronology which makes this test not work as-is?
I want to understand whether there are any compatibility issues to worry about other than the internal format and the #hash calculation?
The necessary #primitiveUtcWithOffset is present in all Cog/Spur/interpreter VMs. It is an optional named primitive (not numbered). If not present, the fallback code uses the Posix epoch for all new time values, resulting in a runnable image but with incorrect time stamps for new DateAndTime instances. Falling back to the original millisecond clock logic and primitives is possible, but it seemed to me to be an unnecessary complication so I got rid of it.
Wrong timestamps are a big deal. It would be better to have an unrunnable image than incorrect timestamps. The former makes a visible issue, the latter, an invisible, insidious one..
Does anyone think that adding UTCDateAndTime to trunk is /not/ a good thing to do?
Until we're sure its a good idea, it's /not/ a good thing to do. I would like to encourage us all to take the due time to really understand all the differences, and would ask someone to produce documentation (on the wiki) which explains exactly what developers need to do to, 1) update their application code, 2) update any persistent instances from Chronology of DateAndTime, etc.
I think this will be a lot of work for me, but the reward will be faster dates and times, which is a good thing, thanks for pushing on this Dave.
On Wed, Jun 22, 2016 at 06:07:00PM -0500, Chris Muller wrote:
Hi David, thanks for proceeding with caution, clearly, this is a core framework upon which everyone's Squeak everything depends. Some questions:
DateAndTimeLeapTest>>testAsSeconds - Discussion required. I claim that #asSeconds can only make sense if it means elapsed seconds since the epoch. The prior implemention and the test are both wrong.
Is there a context where the number of seconds since the epoch would ever "make sense" except to the software which needs to compare it to another result of #asSeconds? Why does it matter what number we start at?
DateAndTimeLeapTest>>testHash - DateAndTime>>hash works differently now. Test should be either updated or eliminated.
DateAndTimeTest>>testPrecision - Discussion required. It is simply wrong to assume that two calls to DateAndTime class>>now will always answer different values, and it is even more wrong to fudge the clock accessors to make it appear to be doing this when it is not. Yes I know that certain database applications require distinct time stamps, but hacking the actual system clock is not the right thing to do.
TimespanDoTest>>testDatesDo - Need to change the test setUp method. The original intent is to test date iteration using a time span begining with a UTC midnight. Test will pass if the start time is constructed accordingly. Note however that date iteration is suspect for durations starting at times other than midnight in the local time zone, so additional tests may be needed.
TimespanDoTest>>testNext - Same issue as testDatesDo, fix the setUp method and the test will pass, but additional tests may be needed.
Can you clarify why the setUp method needs to be changed? What is the core difference between your framework and Chronology which makes this test not work as-is?
I believe that the following would be consistent with the intent of the test, and will permit the tests to pass. The test is trying to interate dates through a time span of 91 days, and was written such that the time span would start on a midnight, such that it would iterate over 91 (not 92) dates. The change below accomplishes that in the #setUp.
TimespanToTest>>setUp aDate := DateAndTime year: 2003 month: 01 day: 07 hour: 0 minute: 0 second: 0 offset: Duration zero. aDuration := Duration days: 91 hours: 0 minutes: 0 seconds: 0 nanoSeconds: 0. aTimespan := Timespan starting: aDate makeUTC duration: aDuration
I want to understand whether there are any compatibility issues to worry about other than the internal format and the #hash calculation?
None that I can think of, but I have been looking at this much too long and I might easily be missing something. Let me know if you can think of anything, more eyeballs on this would be helpful.
The necessary #primitiveUtcWithOffset is present in all Cog/Spur/interpreter VMs. It is an optional named primitive (not numbered). If not present, the fallback code uses the Posix epoch for all new time values, resulting in a runnable image but with incorrect time stamps for new DateAndTime instances. Falling back to the original millisecond clock logic and primitives is possible, but it seemed to me to be an unnecessary complication so I got rid of it.
Wrong timestamps are a big deal. It would be better to have an unrunnable image than incorrect timestamps. The former makes a visible issue, the latter, an invisible, insidious one..
I think the image must remain runnable, even if in a degraded mode. Otherwise you cannot fix it. I think (but am not sure) that someone would quickly notice if all new DateAndTime instances are 45 years old.
We could restore the backward compatibility for running in fallback mode on the old millisecond primitives. I initially planned to keep that, but ended up concluding that it was just to much ugly old cruft to keep in the image. On the other hand, you may have noticed that I tend to be a big fan of backward compatibility, so you probably would not have a hard time convincing me if you think it is a good thing to do ;-)
Does anyone think that adding UTCDateAndTime to trunk is /not/ a good thing to do?
Until we're sure its a good idea, it's /not/ a good thing to do. I would like to encourage us all to take the due time to really understand all the differences, and would ask someone to produce documentation (on the wiki) which explains exactly what developers need to do to, 1) update their application code, 2) update any persistent instances from Chronology of DateAndTime, etc.
Agreed.
And you have just confirmed my hypothesis that asking for positive feedback never works, while tossing out some flame bait can be tremendously effective. Maybe I'll try running for president next ;-)
I think this will be a lot of work for me, but the reward will be faster dates and times, which is a good thing, thanks for pushing on this Dave.
I think that it actually will provide a good improvement. One thing I really do not know is how much of the improvement will be perceptible to the user in everyday activities. I am expecting speedups for things related to source code lookups, but I don't know if the low level speed improvements that I measure will translate into meaningful differences in real life.
Do we have any benchmarks that might show if the DateAndTime speedups will result in improvements that would be noticed by an end user?
Dave
The class comment says:
Instances of Date are Timespans with duration of 1 day.
Their default creation assumes a start of midnight of UTC to provide the fast, globalized Dates out of the box. The legacy behavior that creates Timezone-sensitive Dates can be used by sending #localizedDates.
I no longer see #localizedDates in the image, so I think the comment needs an update.
For reference, and earlier version of the class comment said this:
Instances of Date are Timespans with duration of 1 day. Their default creation assumes a start of midnight in the local time zone.
I am not sure what the comment should say, but I would be happy if it could better convey the intended meaning of "Date" in addition to the explanation about creating instances relative to UTC versus local time zone.
My expectation would be that a Date is a Timespan with a start value set to midnight in some time zone. The start value is a DateAndTime, and the offset instance variable of that DateAndTime would reflect that time zone.
I would therefore expect that a "globalized" Date is a special case of a Date that was created with the start of the Timespan at midnight UTC, regardless of the current local time zone. A "globalized" Date is no different from any other Date, it is simply a Date that was created with time zone UTC.
Is that right?
Dave
Hi Dave, Dates created as positions by default is the definitely the correct behavior. The original Date implementation inherited the abstraction from Timespan of a custom duration starting at a particular DateAndTime. While that is a fine for abstract Timespans, it turned out to be a bad idea for Dates, since the vast majority of the use of Dates are as positions, not spans.
Check out the discussion surrounding Berts recent clarification of the implementation, where the timezone for Dates-as-positions is now set to nil, so the "localized" or "globalized" nomenclature can be removed from the comment.
- Chris
On Thu, Jun 23, 2016 at 8:05 AM, David T. Lewis lewis@mail.msen.com wrote:
The class comment says:
Instances of Date are Timespans with duration of 1 day.
Their default creation assumes a start of midnight of UTC to provide the fast, globalized Dates out of the box. The legacy behavior that creates Timezone-sensitive Dates can be used by sending #localizedDates.
I no longer see #localizedDates in the image, so I think the comment needs an update.
For reference, and earlier version of the class comment said this:
Instances of Date are Timespans with duration of 1 day. Their default creation assumes a start of midnight in the local time zone.
I am not sure what the comment should say, but I would be happy if it could better convey the intended meaning of "Date" in addition to the explanation about creating instances relative to UTC versus local time zone.
My expectation would be that a Date is a Timespan with a start value set to midnight in some time zone. The start value is a DateAndTime, and the offset instance variable of that DateAndTime would reflect that time zone.
I would therefore expect that a "globalized" Date is a special case of a Date that was created with the start of the Timespan at midnight UTC, regardless of the current local time zone. A "globalized" Date is no different from any other Date, it is simply a Date that was created with time zone UTC.
Is that right?
Dave
Hi Chris,
I was really just trying to ask for a good class comment. The current comment contains an error, and I used that as an excuse for raising the question.
I want to know the *meaning* of the Date class. And I would like the class comment to say what it means. The meaning seems to have changed considerably over the last ten or fifteen years as the implementations have changed, and I think that it would be helpful if the current definition could be stated as clearly as possible.
On Sat, Jun 25, 2016 at 07:34:02PM -0500, Chris Muller wrote:
Hi Dave, Dates created as positions by default is the definitely the correct behavior. The original Date implementation inherited the abstraction from Timespan of a custom duration starting at a particular DateAndTime. While that is a fine for abstract Timespans, it turned out to be a bad idea for Dates, since the vast majority of the use of Dates are as positions, not spans.
I am not sure what is meant by "Dates as positions". When I first read this, I was thinking of "position relative to GMT" but on reading it again I realized that it probably means "position on a continuum of date values". Or maybe I am just completely confused (hence my plea for a good class comment). Despite my confusion, my own best guess at the current intended meaning of "Date" was in my original question below.
A bit off topic, but is is worth asking: If we really want to model Date as a position on a continuum of date values, and if we think that the implementation of Date as a kind of Timespan is not right, then shouldn't we just consider going back to the earlier (Squeak 3.6 and earlier) implementation of Date as a Magnitude, rather than Date as a Timespan?
Dave
Check out the discussion surrounding Berts recent clarification of the implementation, where the timezone for Dates-as-positions is now set to nil, so the "localized" or "globalized" nomenclature can be removed from the comment.
- Chris
On Thu, Jun 23, 2016 at 8:05 AM, David T. Lewis lewis@mail.msen.com wrote:
The class comment says:
Instances of Date are Timespans with duration of 1 day.
Their default creation assumes a start of midnight of UTC to provide the fast, globalized Dates out of the box. The legacy behavior that creates Timezone-sensitive Dates can be used by sending #localizedDates.
I no longer see #localizedDates in the image, so I think the comment needs an update.
For reference, and earlier version of the class comment said this:
Instances of Date are Timespans with duration of 1 day. Their default creation assumes a start of midnight in the local time zone.
I am not sure what the comment should say, but I would be happy if it could better convey the intended meaning of "Date" in addition to the explanation about creating instances relative to UTC versus local time zone.
My expectation would be that a Date is a Timespan with a start value set to midnight in some time zone. The start value is a DateAndTime, and the offset instance variable of that DateAndTime would reflect that time zone.
I would therefore expect that a "globalized" Date is a special case of a Date that was created with the start of the Timespan at midnight UTC, regardless of the current local time zone. A "globalized" Date is no different from any other Date, it is simply a Date that was created with time zone UTC.
Is that right?
Dave
Would the following work as a class comment for Date?
Date provides methods for dealing with calendar dates in different formats.
Instances of Date are Timespans with duration of 1 day beginning at midnight. The start value of midnight, and possibly the duration of 1 day, depend on the time zone in which the Date is defined.
In the most common usage, a Date is defined relative to UTC (time zone offset zero), and thus may be treated as a location independent calendar value.
The current date, Date today, is assumed to be defined as a UTC date without consideration of local time zone.
Dave
On Sun, Jun 26, 2016 at 11:30:35PM -0400, David T. Lewis wrote:
Hi Chris,
I was really just trying to ask for a good class comment. The current comment contains an error, and I used that as an excuse for raising the question.
I want to know the *meaning* of the Date class. And I would like the class comment to say what it means. The meaning seems to have changed considerably over the last ten or fifteen years as the implementations have changed, and I think that it would be helpful if the current definition could be stated as clearly as possible.
On Sat, Jun 25, 2016 at 07:34:02PM -0500, Chris Muller wrote:
Hi Dave, Dates created as positions by default is the definitely the correct behavior. The original Date implementation inherited the abstraction from Timespan of a custom duration starting at a particular DateAndTime. While that is a fine for abstract Timespans, it turned out to be a bad idea for Dates, since the vast majority of the use of Dates are as positions, not spans.
I am not sure what is meant by "Dates as positions". When I first read this, I was thinking of "position relative to GMT" but on reading it again I realized that it probably means "position on a continuum of date values". Or maybe I am just completely confused (hence my plea for a good class comment). Despite my confusion, my own best guess at the current intended meaning of "Date" was in my original question below.
A bit off topic, but is is worth asking: If we really want to model Date as a position on a continuum of date values, and if we think that the implementation of Date as a kind of Timespan is not right, then shouldn't we just consider going back to the earlier (Squeak 3.6 and earlier) implementation of Date as a Magnitude, rather than Date as a Timespan?
Dave
Check out the discussion surrounding Berts recent clarification of the implementation, where the timezone for Dates-as-positions is now set to nil, so the "localized" or "globalized" nomenclature can be removed from the comment.
- Chris
On Thu, Jun 23, 2016 at 8:05 AM, David T. Lewis lewis@mail.msen.com wrote:
The class comment says:
Instances of Date are Timespans with duration of 1 day.
Their default creation assumes a start of midnight of UTC to provide the fast, globalized Dates out of the box. The legacy behavior that creates Timezone-sensitive Dates can be used by sending #localizedDates.
I no longer see #localizedDates in the image, so I think the comment needs an update.
For reference, and earlier version of the class comment said this:
Instances of Date are Timespans with duration of 1 day. Their default creation assumes a start of midnight in the local time zone.
I am not sure what the comment should say, but I would be happy if it could better convey the intended meaning of "Date" in addition to the explanation about creating instances relative to UTC versus local time zone.
My expectation would be that a Date is a Timespan with a start value set to midnight in some time zone. The start value is a DateAndTime, and the offset instance variable of that DateAndTime would reflect that time zone.
I would therefore expect that a "globalized" Date is a special case of a Date that was created with the start of the Timespan at midnight UTC, regardless of the current local time zone. A "globalized" Date is no different from any other Date, it is simply a Date that was created with time zone UTC.
Is that right?
Dave
Hi Dave, all of the Timespans are instantiated as positions by default (e.g., ignoring timezone), which is the common case. If/when someone might need a Date, Month, Week, etc. which begins at a timezone-specific time, they will be glad to see that it is handled automatically. For example, when adding a Timespan to a DateAndTime with the #+ message, the result gets the same offset as the receiver.
But this uncommon case is revealed at method-level code and comments, so I would just simplify the class comment to:
Instances of Date are Timespans with duration of 1 day.
Oh, i like that. It reflects the simplicity and elegance of Chronology's implementation which is able to interoperate with itself.
Best, Chris
Would the following work as a class comment for Date?
Date provides methods for dealing with calendar dates in different formats.
Instances of Date are Timespans with duration of 1 day beginning at midnight. The start value of midnight, and possibly the duration of 1 day, depend on the time zone in which the Date is defined.
In the most common usage, a Date is defined relative to UTC (time zone offset zero), and thus may be treated as a location independent calendar value.
The current date, Date today, is assumed to be defined as a UTC date without consideration of local time zone.
Dave
On Sun, Jun 26, 2016 at 11:30:35PM -0400, David T. Lewis wrote:
Hi Chris,
I was really just trying to ask for a good class comment. The current comment contains an error, and I used that as an excuse for raising the question.
I want to know the *meaning* of the Date class. And I would like the class comment to say what it means. The meaning seems to have changed considerably over the last ten or fifteen years as the implementations have changed, and I think that it would be helpful if the current definition could be stated as clearly as possible.
On Sat, Jun 25, 2016 at 07:34:02PM -0500, Chris Muller wrote:
Hi Dave, Dates created as positions by default is the definitely the correct behavior. The original Date implementation inherited the abstraction from Timespan of a custom duration starting at a particular DateAndTime. While that is a fine for abstract Timespans, it turned out to be a bad idea for Dates, since the vast majority of the use of Dates are as positions, not spans.
I am not sure what is meant by "Dates as positions". When I first read this, I was thinking of "position relative to GMT" but on reading it again I realized that it probably means "position on a continuum of date values". Or maybe I am just completely confused (hence my plea for a good class comment). Despite my confusion, my own best guess at the current intended meaning of "Date" was in my original question below.
A bit off topic, but is is worth asking: If we really want to model Date as a position on a continuum of date values, and if we think that the implementation of Date as a kind of Timespan is not right, then shouldn't we just consider going back to the earlier (Squeak 3.6 and earlier) implementation of Date as a Magnitude, rather than Date as a Timespan?
Dave
Check out the discussion surrounding Berts recent clarification of the implementation, where the timezone for Dates-as-positions is now set to nil, so the "localized" or "globalized" nomenclature can be removed from the comment.
- Chris
On Thu, Jun 23, 2016 at 8:05 AM, David T. Lewis lewis@mail.msen.com wrote:
The class comment says:
Instances of Date are Timespans with duration of 1 day.
Their default creation assumes a start of midnight of UTC to provide the fast, globalized Dates out of the box. The legacy behavior that creates Timezone-sensitive Dates can be used by sending #localizedDates.
I no longer see #localizedDates in the image, so I think the comment needs an update.
For reference, and earlier version of the class comment said this:
Instances of Date are Timespans with duration of 1 day. Their default creation assumes a start of midnight in the local time zone.
I am not sure what the comment should say, but I would be happy if it could better convey the intended meaning of "Date" in addition to the explanation about creating instances relative to UTC versus local time zone.
My expectation would be that a Date is a Timespan with a start value set to midnight in some time zone. The start value is a DateAndTime, and the offset instance variable of that DateAndTime would reflect that time zone.
I would therefore expect that a "globalized" Date is a special case of a Date that was created with the start of the Timespan at midnight UTC, regardless of the current local time zone. A "globalized" Date is no different from any other Date, it is simply a Date that was created with time zone UTC.
Is that right?
Dave
On Mon, Jun 27, 2016 at 5:30 AM, David T. Lewis lewis@mail.msen.com wrote:
A bit off topic, but is is worth asking: If we really want to model Date as a position on a continuum of date values, and if we think that the implementation of Date as a kind of Timespan is not right, then shouldn't we just consider going back to the earlier (Squeak 3.6 and earlier) implementation of Date as a Magnitude, rather than Date as a Timespan?
I think this is a very relevant question. We may have to distinguish a Day from a Date.
IMHO a birthday is a perfect example. It's defined by a day+month+year. If I was traveling I would celebrate the birthday in local time, so the generic "birthday" needs to compare equal to all the local dates independent of time zone.
This is how Dates worked before we made them Timespans (because they had no time, and hence no time zone). And this is also how they worked after I added the "nil" offset hack (which ignores the timezone). But it's a hack, not a good design. I'm not entirely sure what a good design would look like that also does not break old code.
- Bert -
So, Time and Dates are hard. When Date was a magnitude, it was easy. Now that it is a duration, it is occassionally wrong. Think about daylight savings time - at least one a year the day length is 25 hours, and once it is 23 hours (although in some places there are no Daylight Savings, so this isn't true, and in others, there are 2 switches, so it happens twice). Our current implementation doesn't take this into account - which is reasonable because it is hard to take this into account without a lot of work.
If we want to keep Date as a timespan (with rough correctness), maybe we could also add in Day (as a magnitude) to work like the old Date?
For what it is worth, I spend >80% of my time working with dates/timestamps, trying to turn them into Magnitudes for manipulations. The other 20%, I really enjoy them as timespans with locales since I deal with times from around the world. But the two uses are not quite easy to deal with - doable, just not quite intuitive.
-cbc
On Mon, Jun 27, 2016 at 3:41 AM, Bert Freudenberg bert@freudenbergs.de wrote:
On Mon, Jun 27, 2016 at 5:30 AM, David T. Lewis lewis@mail.msen.com wrote:
A bit off topic, but is is worth asking: If we really want to model Date as a position on a continuum of date values, and if we think that the implementation of Date as a kind of Timespan is not right, then shouldn't we just consider going back to the earlier (Squeak 3.6 and earlier) implementation of Date as a Magnitude, rather than Date as a Timespan?
I think this is a very relevant question. We may have to distinguish a Day from a Date.
IMHO a birthday is a perfect example. It's defined by a day+month+year. If I was traveling I would celebrate the birthday in local time, so the generic "birthday" needs to compare equal to all the local dates independent of time zone.
This is how Dates worked before we made them Timespans (because they had no time, and hence no time zone). And this is also how they worked after I added the "nil" offset hack (which ignores the timezone). But it's a hack, not a good design. I'm not entirely sure what a good design would look like that also does not break old code.
- Bert -
Hi Chris,
On Mon, Jun 27, 2016 at 8:31 AM, Chris Cunningham cunningham.cb@gmail.com wrote:
So, Time and Dates are hard. When Date was a magnitude, it was easy. Now that it is a duration, it is occassionally wrong. Think about daylight savings time - at least one a year the day length is 25 hours, and once it is 23 hours (although in some places there are no Daylight Savings, so this isn't true, and in others, there are 2 switches, so it happens twice). Our current implementation doesn't take this into account - which is reasonable because it is hard to take this into account without a lot of work.
If we want to keep Date as a timespan (with rough correctness), maybe we could also add in Day (as a magnitude) to work like the old Date?
That's what I wonder. Can't we simply store the start time (ideally UTC microseconds or local microseconds) internally and then compute the duration programmatically, depending on the timezone in effect?
For what it is worth, I spend >80% of my time working with dates/timestamps, trying to turn them into Magnitudes for manipulations. The other 20%, I really enjoy them as timespans with locales since I deal with times from around the world. But the two uses are not quite easy to deal with - doable, just not quite intuitive.
So if we store the start time isn't the conversion to a magnitude simply an inst var access?
-cbc
On Mon, Jun 27, 2016 at 3:41 AM, Bert Freudenberg bert@freudenbergs.de wrote:
On Mon, Jun 27, 2016 at 5:30 AM, David T. Lewis lewis@mail.msen.com wrote:
A bit off topic, but is is worth asking: If we really want to model Date as a position on a continuum of date values, and if we think that the implementation of Date as a kind of Timespan is not right, then shouldn't we just consider going back to the earlier (Squeak 3.6 and earlier) implementation of Date as a Magnitude, rather than Date as a Timespan?
I think this is a very relevant question. We may have to distinguish a Day from a Date.
IMHO a birthday is a perfect example. It's defined by a day+month+year. If I was traveling I would celebrate the birthday in local time, so the generic "birthday" needs to compare equal to all the local dates independent of time zone.
This is how Dates worked before we made them Timespans (because they had no time, and hence no time zone). And this is also how they worked after I added the "nil" offset hack (which ignores the timezone). But it's a hack, not a good design. I'm not entirely sure what a good design would look like that also does not break old code.
- Bert -
For what it is worth, I spend >80% of my time working with dates/timestamps, trying to turn them into Magnitudes for manipulations. The other 20%, I really enjoy them as timespans with locales since I deal with times from around the world. But the two uses are not quite easy to deal with - doable, just not quite intuitive.
So if we store the start time isn't the conversion to a magnitude simply an inst var access?
That's mostly what I do. But it depends on how the Date is created. For instance, unless you live in the UTC time zone, the following is true:
Date today = DateAndTime now asDate "==>true" Date today start = DateAndTime now asDate start "==>false" Date today start asSeconds = DateAndTime now asDate start asSeconds "==>true"
And, of course, it isn't a DAY that we are talking about - it is a DateAndTime (a specific point in time).
It's just remembering which corner cases are true, and which aren't, at any given time.
(as an aside, I find it interesting that Timespan current gives you a day. It is what Date today is based off of - so don't ever change that Timespan #current method!)
-cbc
On Mon, Jun 27, 2016 at 08:31:28AM -0700, Chris Cunningham wrote:
So, Time and Dates are hard. When Date was a magnitude, it was easy. Now that it is a duration, it is occassionally wrong. Think about daylight savings time - at least one a year the day length is 25 hours, and once it is 23 hours (although in some places there are no Daylight Savings, so this isn't true, and in others, there are 2 switches, so it happens twice). Our current implementation doesn't take this into account - which is reasonable because it is hard to take this into account without a lot of work.
Quite right. The concept of "one day" is ambiguous unless we know the local time zone in which it if defined. DST transitions, and possibly also handling of leap seconds, make it impossible to know the duration of one day without also knowing the time zone in which that day is defined.
If we want to keep Date as a timespan (with rough correctness), maybe we could also add in Day (as a magnitude) to work like the old Date?
If we have Day and Date, then IMHO the Day class should represent duration, and the Date class should represent magnitude.
For what it is worth, I spend >80% of my time working with dates/timestamps, trying to turn them into Magnitudes for manipulations. The other 20%, I really enjoy them as timespans with locales since I deal with times from around the world. But the two uses are not quite easy to deal with - doable, just not quite intuitive.
-cbc
Based on your experience, do you think that it would make sense to have two classes for Day and Date, where one represents date as duration, and the other represents date as magnitude?
Dave
On Mon, Jun 27, 2016 at 3:41 AM, Bert Freudenberg bert@freudenbergs.de wrote:
On Mon, Jun 27, 2016 at 5:30 AM, David T. Lewis lewis@mail.msen.com wrote:
A bit off topic, but is is worth asking: If we really want to model Date as a position on a continuum of date values, and if we think that the implementation of Date as a kind of Timespan is not right, then shouldn't we just consider going back to the earlier (Squeak 3.6 and earlier) implementation of Date as a Magnitude, rather than Date as a Timespan?
I think this is a very relevant question. We may have to distinguish a Day from a Date.
IMHO a birthday is a perfect example. It's defined by a day+month+year. If I was traveling I would celebrate the birthday in local time, so the generic "birthday" needs to compare equal to all the local dates independent of time zone.
This is how Dates worked before we made them Timespans (because they had no time, and hence no time zone). And this is also how they worked after I added the "nil" offset hack (which ignores the timezone). But it's a hack, not a good design. I'm not entirely sure what a good design would look like that also does not break old code.
- Bert -
Hi David
On Mon, Jun 27, 2016 at 9:40 PM, David T. Lewis lewis@mail.msen.com wrote:
<snip>
For what it is worth, I spend >80% of my time working with dates/timestamps, trying to turn them into Magnitudes for manipulations. The other 20%, I really enjoy them as timespans with locales since I deal with times from around the world. But the two uses are not quite easy to deal with - doable, just not quite intuitive.
-cbc
Based on your experience, do you think that it would make sense to have two classes for Day and Date, where one represents date as duration, and the other represents date as magnitude?
Dave
Sorry for the long delay.
Having Date (or Day) as a duration has positive benefits. For instance, I want to know if a particular timestamp (when something happened, what we call DateAndTime) happened on a particular Date. The DateAndTime might be in a different timezone than the Date we are checking. Being able to just ask 'is this timestamp from this date' is nice:
theDate := ('2016-07-06' asDate start offset: 4 hours) asDate. theTime := '2016-07-06 20:34:02' asDateAndTime offset: 8 hours. theDate includes: theTime " => false" theTime := '2016-07-06 20:34:02' asDateAndTime offset: -8 hours. theDate includes: theTime " => true"
Although it is hard to get a date in a certain timezone - is there a better way than what I wrote above? Rarely do I need it in my timezone - instead I need to specify it directly or not have it present at all.
Most of the time, though, I just as a number, not a duration. I just want to show it, sometimes work from its beginning to some other time, and ignore that it is a duration.
Looking at how you are interpreting my statement that I want it as a magnitude, I think I was using the wrong words. What I really meant was that I wanted it ignore the duration (and most especially the timezone) - but not use it as a raw number of some kind.
Thanks, -cbc
Hi David
On Mon, Jun 27, 2016 at 9:40 PM, David T. Lewis lewis@mail.msen.com wrote:
<snip>
For what it is worth, I spend >80% of my time working with dates/timestamps, trying to turn them into Magnitudes for
manipulations.
The other 20%, I really enjoy them as timespans with locales since I
deal
with times from around the world. But the two uses are not quite easy
to
deal with - doable, just not quite intuitive.
-cbc
Based on your experience, do you think that it would make sense to have two classes for Day and Date, where one represents date as duration, and the other represents date as magnitude?
Dave
Sorry for the long delay.
Having Date (or Day) as a duration has positive benefits. For instance, I want to know if a particular timestamp (when something happened, what we call DateAndTime) happened on a particular Date. The DateAndTime might be in a different timezone than the Date we are checking. Being able to just ask 'is this timestamp from this date' is nice:
theDate := ('2016-07-06' asDate start offset: 4 hours) asDate. theTime := '2016-07-06 20:34:02' asDateAndTime offset: 8 hours. theDate includes: theTime " => false" theTime := '2016-07-06 20:34:02' asDateAndTime offset: -8 hours. theDate includes: theTime " => true"
Although it is hard to get a date in a certain timezone - is there a better way than what I wrote above? Rarely do I need it in my timezone - instead I need to specify it directly or not have it present at all.
Most of the time, though, I just as a number, not a duration. I just want to show it, sometimes work from its beginning to some other time, and ignore that it is a duration.
Looking at how you are interpreting my statement that I want it as a magnitude, I think I was using the wrong words. What I really meant was that I wanted it ignore the duration (and most especially the timezone) - but not use it as a raw number of some kind.
Thanks, -cbc
Thank you Chris, that is a very good explanation :-)
Dave
On Mon, Jun 27, 2016 at 12:41:28PM +0200, Bert Freudenberg wrote:
On Mon, Jun 27, 2016 at 5:30 AM, David T. Lewis lewis@mail.msen.com wrote:
A bit off topic, but is is worth asking: If we really want to model Date as a position on a continuum of date values, and if we think that the implementation of Date as a kind of Timespan is not right, then shouldn't we just consider going back to the earlier (Squeak 3.6 and earlier) implementation of Date as a Magnitude, rather than Date as a Timespan?
I think this is a very relevant question. We may have to distinguish a Day from a Date.
This seems like a useful distinction to me. The concepts are different, and they deserve different representations.
To me as a native American English speaker, I would say that "Day" implies duration, and "Date" implies magnitude. I would expect that the current implementation of date as duration might map most directly to a Smalltalk class named "Day". And the earlier Squeak implementation of date as a magnitude would map directly to a Smalltalk class named "Date".
IMHO a birthday is a perfect example. It's defined by a day+month+year. If I was traveling I would celebrate the birthday in local time, so the generic "birthday" needs to compare equal to all the local dates independent of time zone.
This is how Dates worked before we made them Timespans (because they had no time, and hence no time zone). And this is also how they worked after I added the "nil" offset hack (which ignores the timezone). But it's a hack, not a good design. I'm not entirely sure what a good design would look like that also does not break old code.
- Bert -
If we can assume that the current Squeak implementation of Date as a duration makes sense for a class named "Day" and that the prior implementation of Date as a magnitude makes sense for a class named "Date", then a possible way forward would be (in someone's local image, not yet in trunk):
- Rename class Date as Day - Copy the Date tests to a new class for the Day tests. - Make sure that the tests for Day are working. - Load an old version of Date from the most recent Squeak version that had Date as a magnitude. - Make the unit tests work for Date.
Dave
If we can assume that the current Squeak implementation of Date as a duration makes sense for a class named "Day" and that the prior implementation of Date as a magnitude makes sense for a class named "Date", then a possible way forward would be (in someone's local image, not yet in trunk):
- Rename class Date as Day
- Copy the Date tests to a new class for the Day tests.
- Make sure that the tests for Day are working.
- Load an old version of Date from the most recent Squeak version that had Date as a magnitude.
- Make the unit tests work for Date.
Hi Dave,
I appreciate your point about the semantics of the word "Date" vs. "Day" but since DateAndTime is also part of Chronology, I hope you don't intend to rename it to "DayAndTime" and make it work with Days.. :)
DateAndTime has #asHour, #asDate, #asMonth, #asYear -- each one returning an instance of the appropriate Timespan subclass. This proposal would interject a totally orthogonal "exception" into the API of Chronology. Your Magnitude version of Date would have a different API like #isTimespan, for example. So, it would break many applications not just from the format change, but their application logic too. That's too big a cost.
I worked a lot with Brent for several years, I know his style is to make terse and elegant API's. Chronology provides us with a robust interoperation of inputs with its outputs. I happen to know the compactness of the API was a deliberate part of his legacy creation. We should respect that.
I was really just trying to ask for a good class comment.
I really do think this is the best way to do this clarification. Did you notice that Bert already updated the class comment of Timespan to mention the dual capability? So, I think simply removing that old stuff from Date's comment is simple and effective solution without breaking legacy apps.
On Tue, Jun 28, 2016 at 01:41:28PM -0500, Chris Muller wrote:
I was really just trying to ask for a good class comment.
I really do think this is the best way to do this clarification. Did you notice that Bert already updated the class comment of Timespan to mention the dual capability? So, I think simply removing that old stuff from Date's comment is simple and effective solution without breaking legacy apps.
This was my attempt at a class comment for Date:
Date provides methods for dealing with calendar dates in different formats.
Instances of Date are Timespans with duration of 1 day beginning at midnight. The start value of midnight, and possibly the duration of 1 day, depend on the time zone in which the Date is defined.
In the most common usage, a Date is defined relative to UTC (time zone offset zero), and thus may be treated as a location independent calendar value.
The current date, Date today, is assumed to be defined as a UTC date without consideration of local time zone.
Alternative attempts welcome :-)
Dave
On Tue, Jun 28, 2016 at 08:18:53PM -0400, David T. Lewis wrote:
On Tue, Jun 28, 2016 at 01:41:28PM -0500, Chris Muller wrote:
I was really just trying to ask for a good class comment.
I really do think this is the best way to do this clarification. Did you notice that Bert already updated the class comment of Timespan to mention the dual capability? So, I think simply removing that old stuff from Date's comment is simple and effective solution without breaking legacy apps.
This was my attempt at a class comment for Date:
Date provides methods for dealing with calendar dates in different formats.
Instances of Date are Timespans with duration of 1 day beginning at midnight. The start value of midnight, and possibly the duration of 1 day, depend on the time zone in which the Date is defined.
In the most common usage, a Date is defined relative to UTC (time zone offset zero), and thus may be treated as a location independent calendar value.
The current date, Date today, is assumed to be defined as a UTC date without consideration of local time zone.
Alternative attempts welcome :-)
Dave
Chris, thanks for updating the class comment for Date. Summarizing where we are now:
Brent's original class comment is:
Instances of Date are Timespans with duration of 1 day. Their default creation assumes a start of midnight in the local time zone.
And our class comment (Chronology-Core-cmm.6.mcz) is:
Instances of Date are Timespans with duration of 1 day. As with all Chronology Timespan sub-instances, Dates can be instantiated as position values which compare equally to any other instance of the same Date, irregardless of the timezone in which either is created.
However, like the other Timespan subInstances, there are rare cases where it may be desirable to use instances of Date to represent a particular 1-day span of time at a particular locality on the globe. All Timespans, including Dates, may specify a particular timezone offset for this purpose.
It seems that Brent's intent was to represent a date starting at midnight in the local time zone. For various reasons, we now treat it more like a magnitude, representing it as a one day duration beginning at midnight UTC. That works better for most actual usage of class Date, but it does leave me thinking that we are mashing up two different concepts.
To be clear, I am not planning to actually /do/ anything about this, I am just trying to clarify the documentation and my own understanding. It might well be a good idea to have two different classes to represent date as duration versus date as magnitude, but I certainly have no intention of taking that on until we decide to use or discard the UTCDateAndTime updates that I previously proposed.
My primary motiviation is to make sure that the changes in UTCDateAndTime pass the unit tests while also respecting the design intent. So I am not trying to be a pain in the ass, I am really trying to understand the intended meaning of the class, and I am trying to reconcile Brent's original intent with the various changes that we have made since its introduction.
Thanks :-)
Dave
Hi Dave,
Not that it matters too much to the Squeak world but a Date in VA Smalltalk is a Magnitude.
I'm very glad you are trying to think all this data/time stuff through. A while ago (like ten years) VA Smalltalk went from keeping time as an integer number of seconds to keeping them as milliseconds. In and of itself that was fine but they changed #asSeconds from answering that number of seconds to answering a rounded number of milliseconds. This broke some of my code as it made some time values (when represented as seconds) look like a time in the future. IMHO rounding shouldn't be used unless it is needed just before a value is being displayed for humans. That wasn't the case here and although many if not most people agreed with me, I didn't discover the change until it had been in place for a long time and Instantiations was reluctant to fix it.
Lou
On Sun, 26 Jun 2016 23:30:35 -0400, "David T. Lewis" lewis@mail.msen.com wrote:
Hi Chris,
I was really just trying to ask for a good class comment. The current comment contains an error, and I used that as an excuse for raising the question.
I want to know the *meaning* of the Date class. And I would like the class comment to say what it means. The meaning seems to have changed considerably over the last ten or fifteen years as the implementations have changed, and I think that it would be helpful if the current definition could be stated as clearly as possible.
On Sat, Jun 25, 2016 at 07:34:02PM -0500, Chris Muller wrote:
Hi Dave, Dates created as positions by default is the definitely the correct behavior. The original Date implementation inherited the abstraction from Timespan of a custom duration starting at a particular DateAndTime. While that is a fine for abstract Timespans, it turned out to be a bad idea for Dates, since the vast majority of the use of Dates are as positions, not spans.
I am not sure what is meant by "Dates as positions". When I first read this, I was thinking of "position relative to GMT" but on reading it again I realized that it probably means "position on a continuum of date values". Or maybe I am just completely confused (hence my plea for a good class comment). Despite my confusion, my own best guess at the current intended meaning of "Date" was in my original question below.
A bit off topic, but is is worth asking: If we really want to model Date as a position on a continuum of date values, and if we think that the implementation of Date as a kind of Timespan is not right, then shouldn't we just consider going back to the earlier (Squeak 3.6 and earlier) implementation of Date as a Magnitude, rather than Date as a Timespan?
Dave
Check out the discussion surrounding Berts recent clarification of the implementation, where the timezone for Dates-as-positions is now set to nil, so the "localized" or "globalized" nomenclature can be removed from the comment.
- Chris
On Thu, Jun 23, 2016 at 8:05 AM, David T. Lewis lewis@mail.msen.com wrote:
The class comment says:
Instances of Date are Timespans with duration of 1 day.
Their default creation assumes a start of midnight of UTC to provide the fast, globalized Dates out of the box. The legacy behavior that creates Timezone-sensitive Dates can be used by sending #localizedDates.
I no longer see #localizedDates in the image, so I think the comment needs an update.
For reference, and earlier version of the class comment said this:
Instances of Date are Timespans with duration of 1 day. Their default creation assumes a start of midnight in the local time zone.
I am not sure what the comment should say, but I would be happy if it could better convey the intended meaning of "Date" in addition to the explanation about creating instances relative to UTC versus local time zone.
My expectation would be that a Date is a Timespan with a start value set to midnight in some time zone. The start value is a DateAndTime, and the offset instance variable of that DateAndTime would reflect that time zone.
I would therefore expect that a "globalized" Date is a special case of a Date that was created with the start of the Timespan at midnight UTC, regardless of the current local time zone. A "globalized" Date is no different from any other Date, it is simply a Date that was created with time zone UTC.
Is that right?
Dave
On Mon, Jun 27, 2016 at 5:47 AM, Louis LaBrunda Lou@keystone-software.com wrote:
Hi Dave,
Not that it matters too much to the Squeak world but a Date in VA Smalltalk is a Magnitude.
I'm very glad you are trying to think all this data/time stuff through. A while ago (like ten years) VA Smalltalk went from keeping time as an integer number of seconds to keeping them as milliseconds. In and of itself that was fine but they changed #asSeconds from answering that number of seconds to answering a rounded number of milliseconds. This broke some of my code as it made some time values (when represented as seconds) look like a time in the future. IMHO rounding shouldn't be used unless it is needed just before a value is being displayed for humans. That wasn't the case here and although many if not most people agreed with me, I didn't discover the change until it had been in place for a long time and Instantiations was reluctant to fix it.
I hope we can settle on representing them as microseconds. Using nanoseconds (the Microsoft granularity) shrinks their usable time span to 36 years if using 61-bit SmallIntegers, which is too short even if we use the posix epoch, and horrible if we want to rebase things, e.g. at 2000 or 2001. Keeping microseconds, which is the VM representation gives us ~36,000 years within the 61-bit SmallInteger range (- 2^60 - 2^60 - 1) in 64-bit Spur. Using milliseconds throws away precision and introduces a divide. Multiplying, or worse still dividing, by 1000 n every instantiation seems like a bad idea to me.
Lou
On Sun, 26 Jun 2016 23:30:35 -0400, "David T. Lewis" lewis@mail.msen.com wrote:
Hi Chris,
I was really just trying to ask for a good class comment. The current comment contains an error, and I used that as an excuse for raising the question.
I want to know the *meaning* of the Date class. And I would like the class comment to say what it means. The meaning seems to have changed considerably over the last ten or fifteen years as the implementations have changed, and I think that it would be helpful if the current definition could be stated as clearly as possible.
On Sat, Jun 25, 2016 at 07:34:02PM -0500, Chris Muller wrote:
Hi Dave, Dates created as positions by default is the definitely the correct behavior. The original Date implementation inherited the abstraction from Timespan of a custom duration starting at a particular DateAndTime. While that is a fine for abstract Timespans, it turned out to be a bad idea for Dates, since the vast majority of the use of Dates are as positions, not spans.
I am not sure what is meant by "Dates as positions". When I first read this, I was thinking of "position relative to GMT" but on reading it again I realized that it probably means "position on a continuum of date values". Or maybe I am just completely confused (hence my plea for a good class comment). Despite my confusion, my own best guess at the current intended meaning of "Date" was in my original question below.
A bit off topic, but is is worth asking: If we really want to model Date as a position on a continuum of date values, and if we think that the implementation of Date as a kind of Timespan is not right, then shouldn't we just consider going back to the earlier (Squeak 3.6 and earlier) implementation of Date as a
Magnitude,
rather than Date as a Timespan?
Dave
Check out the discussion surrounding Berts recent clarification of the implementation, where the timezone for Dates-as-positions is now set to nil, so the "localized" or "globalized" nomenclature can be removed from the comment.
- Chris
On Thu, Jun 23, 2016 at 8:05 AM, David T. Lewis lewis@mail.msen.com
wrote:
The class comment says:
Instances of Date are Timespans with duration of 1 day.
Their default creation assumes a start of midnight of UTC to
provide the fast, globalized Dates out of the box. The legacy behavior that creates Timezone-sensitive Dates can be used by sending #localizedDates.
I no longer see #localizedDates in the image, so I think the comment
needs an update.
For reference, and earlier version of the class comment said this:
Instances of Date are Timespans with duration of 1 day. Their default creation assumes a start of midnight in the local
time zone.
I am not sure what the comment should say, but I would be happy if it
could
better convey the intended meaning of "Date" in addition to the
explanation
about creating instances relative to UTC versus local time zone.
My expectation would be that a Date is a Timespan with a start value
set to
midnight in some time zone. The start value is a DateAndTime, and the
offset
instance variable of that DateAndTime would reflect that time zone.
I would therefore expect that a "globalized" Date is a special case
of a Date
that was created with the start of the Timespan at midnight UTC,
regardless
of the current local time zone. A "globalized" Date is no different
from any
other Date, it is simply a Date that was created with time zone UTC.
Is that right?
Dave
-- Louis LaBrunda Keystone Software Corp. SkypeMe callto://PhotonDemon
squeak-dev@lists.squeakfoundation.org