Dictionary and Date as keys

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

Dictionary and Date as keys

Pharo Smalltalk Users mailing list
My problem - use Dates as Dictionary keys - shortly:

d1 := Date today translateToUTC.
d2 := Date today.

d1 = d2. (true!)

d := Dictionary new.
d at: d1 put: 1.

d at: d1. (ok)
d at: d2. (bad - key not found)

---

pf

Reply | Threaded
Open this post in threaded view
|

Re: Dictionary and Date as keys

Alistair Grant
Hi Petr,

On Tue, 16 Oct 2018 at 21:25, Petr Fischer via Pharo-users
<[hidden email]> wrote:
>
> My problem - use Dates as Dictionary keys - shortly:
>
> d1 := Date today translateToUTC.
> d2 := Date today.
>
> d1 = d2. (true!)

Which timezone are you in?

CEDT (UTC+0200) gives false for this.

Date is implemented primarily as a timespan, so days in different
timezones are considered different.  If you do:

| d1 d2 |

d1 := Date today translateTo: (TimeZone abbreviated: 'UTC') offset.
d2 := Date today translateTo: (TimeZone abbreviated: 'EST') offset.

{ d1 = d2.  d1 equals: d2 }


You can see the difference.

Of course, this doesn't help with using Date as a key in a dictionary.
Probably your best option is to look at Sven's excellent ZTimezone
package (although I haven't tested it in this scenario).

I can't find the repository right now (I think Sven moved it to github).  Sven?

Cheers,
Alistair



> d := Dictionary new.
> d at: d1 put: 1.
>
> d at: d1. (ok)
> d at: d2. (bad - key not found)
>
> ---
>
> pf
>

Reply | Threaded
Open this post in threaded view
|

Re: Dictionary and Date as keys

Sven Van Caekenberghe-2
In reply to this post by Pharo Smalltalk Users mailing list


> On 16 Oct 2018, at 19:53, Petr Fischer via Pharo-users <[hidden email]> wrote:
>
>
> From: Petr Fischer <[hidden email]>
> Subject: Dictionary and Date as keys
> Date: 16 October 2018 at 19:53:40 GMT+2
> To: [hidden email]
>
>
> My problem - use Dates as Dictionary keys - shortly:
>
> d1 := Date today translateToUTC.
> d2 := Date today.
>
> d1 = d2. (true!)

Hmm, no, for me (Pharo 7)

 Date today = Date today translateToUTC

is false as it should be.

> d := Dictionary new.
> d at: d1 put: 1.
>
> d at: d1. (ok)
> d at: d2. (bad - key not found)
>
> ---
>
> pf
>
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Dictionary and Date as keys

Sven Van Caekenberghe-2
In reply to this post by Alistair Grant


> On 16 Oct 2018, at 22:27, Alistair Grant <[hidden email]> wrote:
>
> Hi Petr,
>
> On Tue, 16 Oct 2018 at 21:25, Petr Fischer via Pharo-users
> <[hidden email]> wrote:
>>
>> My problem - use Dates as Dictionary keys - shortly:
>>
>> d1 := Date today translateToUTC.
>> d2 := Date today.
>>
>> d1 = d2. (true!)
>
> Which timezone are you in?
>
> CEDT (UTC+0200) gives false for this.
>
> Date is implemented primarily as a timespan, so days in different
> timezones are considered different.  If you do:
>
> | d1 d2 |
>
> d1 := Date today translateTo: (TimeZone abbreviated: 'UTC') offset.
> d2 := Date today translateTo: (TimeZone abbreviated: 'EST') offset.
>
> { d1 = d2.  d1 equals: d2 }
>
>
> You can see the difference.
>
> Of course, this doesn't help with using Date as a key in a dictionary.
> Probably your best option is to look at Sven's excellent ZTimezone
> package (although I haven't tested it in this scenario).
>
> I can't find the repository right now (I think Sven moved it to github).  Sven?

It is called ZTimestamp and it lives in various places, for example: https://github.com/svenvc/ztimestamp

> Cheers,
> Alistair
>
>
>
>> d := Dictionary new.
>> d at: d1 put: 1.
>>
>> d at: d1. (ok)
>> d at: d2. (bad - key not found)
>>
>> ---
>>
>> pf
>>
>


Reply | Threaded
Open this post in threaded view
|

Re: Dictionary and Date as keys

Richard O'Keefe
There is an elephant in the room.  Historically and in Smalltalks such as
GNU Smalltalk, Smalltalk/X, my Smalltalk->C system, VisualAge Smalltalk,
and VisualWOrks, a Date is *not* a TimeSpan and is *not* associated with
a time zone or a zone offset.  It's generally a direct subclass of
Magnitude.  And this was originally true in Squeak as well.  I just had a
look at SqueakV2.source to verify that.

At some point subsequent to the 2.x series, Squeak made an incompatible
and to me incomprehensible change, with the result that "Date" in today's
Squeak and Pharo is incompatible with every other Smalltalk I've been able
to check: it does not mean the same thing any more and cannot be used the
same ways.

The "classic" semantics is that a Date represents a cultural item, a day
in the proleptic Gregorian calendar, without reference to any particular
locality.  For example, my most recent birthday was 2018-10-11, and it
would have been the same *date* but not the same *timespan* no matter
where I was in the world.  The USA celebrated President's day on
2018-02-19 this year, and it was the same *date* in every state, but
by no means the same *timespan*.

Now, granting the utility of a class to represent the timespan associated
with a date in a given timezone, the obvious way to introduce it would
have been to introduce a new DateInZone class.  Sadly, in Squeak the
Date class was changed incompatibly to take that role, with nothing left
to do what Date usefully did (and still does elsewhere).

So now we have the problem that the original poster wanted to do
something perfectly sensible that works in nearly every other Smalltalk
and used to work in Squeak, but it doesn't work in Pharo.

In this situation, I'd be strongly inclined to port say GNU Smalltalk's
Date class, renaming it to CompatibleDate, add a global variable
DateInZone, and add methods
  CompatibleDate>>inZone:
  DateInZone>>sansZone



On Wed, 17 Oct 2018 at 09:44, Sven Van Caekenberghe <[hidden email]> wrote:


> On 16 Oct 2018, at 22:27, Alistair Grant <[hidden email]> wrote:
>
> Hi Petr,
>
> On Tue, 16 Oct 2018 at 21:25, Petr Fischer via Pharo-users
> <[hidden email]> wrote:
>>
>> My problem - use Dates as Dictionary keys - shortly:
>>
>> d1 := Date today translateToUTC.
>> d2 := Date today.
>>
>> d1 = d2. (true!)
>
> Which timezone are you in?
>
> CEDT (UTC+0200) gives false for this.
>
> Date is implemented primarily as a timespan, so days in different
> timezones are considered different.  If you do:
>
> | d1 d2 |
>
> d1 := Date today translateTo: (TimeZone abbreviated: 'UTC') offset.
> d2 := Date today translateTo: (TimeZone abbreviated: 'EST') offset.
>
> { d1 = d2.  d1 equals: d2 }
>
>
> You can see the difference.
>
> Of course, this doesn't help with using Date as a key in a dictionary.
> Probably your best option is to look at Sven's excellent ZTimezone
> package (although I haven't tested it in this scenario).
>
> I can't find the repository right now (I think Sven moved it to github).  Sven?

It is called ZTimestamp and it lives in various places, for example: https://github.com/svenvc/ztimestamp

> Cheers,
> Alistair
>
>
>
>> d := Dictionary new.
>> d at: d1 put: 1.
>>
>> d at: d1. (ok)
>> d at: d2. (bad - key not found)
>>
>> ---
>>
>> pf
>>
>


Reply | Threaded
Open this post in threaded view
|

Re: Dictionary and Date as keys

Sven Van Caekenberghe-2


> On 17 Oct 2018, at 13:07, Richard O'Keefe <[hidden email]> wrote:
>
> There is an elephant in the room.  Historically and in Smalltalks such as
> GNU Smalltalk, Smalltalk/X, my Smalltalk->C system, VisualAge Smalltalk,
> and VisualWOrks, a Date is *not* a TimeSpan and is *not* associated with
> a time zone or a zone offset.  It's generally a direct subclass of
> Magnitude.  And this was originally true in Squeak as well.  I just had a
> look at SqueakV2.source to verify that.
>
> At some point subsequent to the 2.x series, Squeak made an incompatible
> and to me incomprehensible change, with the result that "Date" in today's
> Squeak and Pharo is incompatible with every other Smalltalk I've been able
> to check: it does not mean the same thing any more and cannot be used the
> same ways.
>
> The "classic" semantics is that a Date represents a cultural item, a day
> in the proleptic Gregorian calendar, without reference to any particular
> locality.  For example, my most recent birthday was 2018-10-11, and it
> would have been the same *date* but not the same *timespan* no matter
> where I was in the world.  The USA celebrated President's day on
> 2018-02-19 this year, and it was the same *date* in every state, but
> by no means the same *timespan*.
>
> Now, granting the utility of a class to represent the timespan associated
> with a date in a given timezone, the obvious way to introduce it would
> have been to introduce a new DateInZone class.  Sadly, in Squeak the
> Date class was changed incompatibly to take that role, with nothing left
> to do what Date usefully did (and still does elsewhere).
>
> So now we have the problem that the original poster wanted to do
> something perfectly sensible that works in nearly every other Smalltalk
> and used to work in Squeak, but it doesn't work in Pharo.
>
> In this situation, I'd be strongly inclined to port say GNU Smalltalk's
> Date class, renaming it to CompatibleDate, add a global variable
> DateInZone, and add methods
>   CompatibleDate>>inZone:
>   DateInZone>>sansZone

Date's current implementation and its implications has been the subject of many discussions before, it won't be the last.

Both the simple, abstract calendar date as well as the more complex date in a timezone with a concrete timespan are useful.

Using #translateToUTC and other techniques, you can make all your dates UTC based and be very close to the simple abstract calendar date.

IMHO, what we need is to move away from TZ offsets towards real TZ identifiers (as in the Olson DB). So not +02:00 but Europe/Brussels.

Next we need chronology objects with/without TZ info (or maybe the without case can just be UTC).

But it is also very important to acknowledge the limitations of the objects without TZ info, because this fallback on current TZ is way too brittle.

Your simple old school calendar Date cannot be asked for its start or stop or whether it includes a specific time, since all these need a TZ.

The point about Date serialisation in the STON thread is illustrative here.

The round trip of 1/1/2000 between my image, to some external representation without TZ, to your image will not be the same thing if we use different TZs. Given DST, the dates will even change by the season on the same machine. Not being aware of this complexity or hiding it will eventually lead to problems and bugs.

> On Wed, 17 Oct 2018 at 09:44, Sven Van Caekenberghe <[hidden email]> wrote:
>
>
> > On 16 Oct 2018, at 22:27, Alistair Grant <[hidden email]> wrote:
> >
> > Hi Petr,
> >
> > On Tue, 16 Oct 2018 at 21:25, Petr Fischer via Pharo-users
> > <[hidden email]> wrote:
> >>
> >> My problem - use Dates as Dictionary keys - shortly:
> >>
> >> d1 := Date today translateToUTC.
> >> d2 := Date today.
> >>
> >> d1 = d2. (true!)
> >
> > Which timezone are you in?
> >
> > CEDT (UTC+0200) gives false for this.
> >
> > Date is implemented primarily as a timespan, so days in different
> > timezones are considered different.  If you do:
> >
> > | d1 d2 |
> >
> > d1 := Date today translateTo: (TimeZone abbreviated: 'UTC') offset.
> > d2 := Date today translateTo: (TimeZone abbreviated: 'EST') offset.
> >
> > { d1 = d2.  d1 equals: d2 }
> >
> >
> > You can see the difference.
> >
> > Of course, this doesn't help with using Date as a key in a dictionary.
> > Probably your best option is to look at Sven's excellent ZTimezone
> > package (although I haven't tested it in this scenario).
> >
> > I can't find the repository right now (I think Sven moved it to github).  Sven?
>
> It is called ZTimestamp and it lives in various places, for example: https://github.com/svenvc/ztimestamp
>
> > Cheers,
> > Alistair
> >
> >
> >
> >> d := Dictionary new.
> >> d at: d1 put: 1.
> >>
> >> d at: d1. (ok)
> >> d at: d2. (bad - key not found)
> >>
> >> ---
> >>
> >> pf
> >>
> >
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Dictionary and Date as keys

Hannes Hirzel
In reply to this post by Richard O'Keefe
Maybe this happened with Squeak version 3.7?

http://wiki.squeak.org/squeak/1871

--Hannes

On 10/17/18, Richard O'Keefe <[hidden email]> wrote:

> There is an elephant in the room.  Historically and in Smalltalks such as
> GNU Smalltalk, Smalltalk/X, my Smalltalk->C system, VisualAge Smalltalk,
> and VisualWOrks, a Date is *not* a TimeSpan and is *not* associated with
> a time zone or a zone offset.  It's generally a direct subclass of
> Magnitude.  And this was originally true in Squeak as well.  I just had a
> look at SqueakV2.source to verify that.
>
> At some point subsequent to the 2.x series, Squeak made an incompatible
> and to me incomprehensible change, with the result that "Date" in today's
> Squeak and Pharo is incompatible with every other Smalltalk I've been able
> to check: it does not mean the same thing any more and cannot be used the
> same ways.
>
> The "classic" semantics is that a Date represents a cultural item, a day
> in the proleptic Gregorian calendar, without reference to any particular
> locality.  For example, my most recent birthday was 2018-10-11, and it
> would have been the same *date* but not the same *timespan* no matter
> where I was in the world.  The USA celebrated President's day on
> 2018-02-19 this year, and it was the same *date* in every state, but
> by no means the same *timespan*.
>
> Now, granting the utility of a class to represent the timespan associated
> with a date in a given timezone, the obvious way to introduce it would
> have been to introduce a new DateInZone class.  Sadly, in Squeak the
> Date class was changed incompatibly to take that role, with nothing left
> to do what Date usefully did (and still does elsewhere).
>
> So now we have the problem that the original poster wanted to do
> something perfectly sensible that works in nearly every other Smalltalk
> and used to work in Squeak, but it doesn't work in Pharo.
>
> In this situation, I'd be strongly inclined to port say GNU Smalltalk's
> Date class, renaming it to CompatibleDate, add a global variable
> DateInZone, and add methods
>   CompatibleDate>>inZone:
>   DateInZone>>sansZone
>
>
>
> On Wed, 17 Oct 2018 at 09:44, Sven Van Caekenberghe <[hidden email]> wrote:
>
>>
>>
>> > On 16 Oct 2018, at 22:27, Alistair Grant <[hidden email]> wrote:
>> >
>> > Hi Petr,
>> >
>> > On Tue, 16 Oct 2018 at 21:25, Petr Fischer via Pharo-users
>> > <[hidden email]> wrote:
>> >>
>> >> My problem - use Dates as Dictionary keys - shortly:
>> >>
>> >> d1 := Date today translateToUTC.
>> >> d2 := Date today.
>> >>
>> >> d1 = d2. (true!)
>> >
>> > Which timezone are you in?
>> >
>> > CEDT (UTC+0200) gives false for this.
>> >
>> > Date is implemented primarily as a timespan, so days in different
>> > timezones are considered different.  If you do:
>> >
>> > | d1 d2 |
>> >
>> > d1 := Date today translateTo: (TimeZone abbreviated: 'UTC') offset.
>> > d2 := Date today translateTo: (TimeZone abbreviated: 'EST') offset.
>> >
>> > { d1 = d2.  d1 equals: d2 }
>> >
>> >
>> > You can see the difference.
>> >
>> > Of course, this doesn't help with using Date as a key in a dictionary.
>> > Probably your best option is to look at Sven's excellent ZTimezone
>> > package (although I haven't tested it in this scenario).
>> >
>> > I can't find the repository right now (I think Sven moved it to
>> github).  Sven?
>>
>> It is called ZTimestamp and it lives in various places, for example:
>> https://github.com/svenvc/ztimestamp
>>
>> > Cheers,
>> > Alistair
>> >
>> >
>> >
>> >> d := Dictionary new.
>> >> d at: d1 put: 1.
>> >>
>> >> d at: d1. (ok)
>> >> d at: d2. (bad - key not found)
>> >>
>> >> ---
>> >>
>> >> pf
>> >>
>> >
>>
>>
>>
>

cbc
Reply | Threaded
Open this post in threaded view
|

Re: Dictionary and Date as keys

cbc
In reply to this post by Alistair Grant
Hi,

On Tue, Oct 16, 2018 at 1:28 PM Alistair Grant <[hidden email]> wrote:
Hi Petr,

On Tue, 16 Oct 2018 at 21:25, Petr Fischer via Pharo-users
<[hidden email]> wrote:
>
> My problem - use Dates as Dictionary keys - shortly:
>
> d1 := Date today translateToUTC.
> d2 := Date today.
>
> d1 = d2. (true!)

Of course, this doesn't help with using Date as a key in a dictionary.
Probably your best option is to look at Sven's excellent ZTimezone
package (although I haven't tested it in this scenario).

The base problem here is that the hash of the dates is not the same for dates that are equal - that should never happen.  If you try
d1 hash = d2 hash
you should see that the hash's are different (Petr for sure; you for the cases where the offsets are different).

When objects (especially fo the same class) are =, then their hash must be the same as well, or things break.

-cbc 
Reply | Threaded
Open this post in threaded view
|

Re: Dictionary and Date as keys

Sean P. DeNigris
Administrator
In reply to this post by Sven Van Caekenberghe-2
Sven Van Caekenberghe-2 wrote
>> the obvious way to introduce it would
>> have been to introduce a new DateInZone class.

Yes, that would have been nice. Especially since IMHO this is the more
common, simple case, and least surprising to new users. I would assume by
the time you're building international apps there is decent familiarization
with the system.


Sven Van Caekenberghe-2 wrote
> Both the simple, abstract calendar date as well as the more complex date
> in a timezone with a concrete timespan are useful.

Agreed. The additional problem (besides incompatible/inconsistent naming)
with the Squeak/Pharo implementation of option #2 is that they are buggy and
incomplete.



-----
Cheers,
Sean
--
Sent from: http://forum.world.st/Pharo-Smalltalk-Users-f1310670.html

Cheers,
Sean
Reply | Threaded
Open this post in threaded view
|

Re: Dictionary and Date as keys

Sven Van Caekenberghe-2
In reply to this post by cbc
Chris,

That is not what I am seeing in Pharo 7:

date1 := Date today.
date2 := Date today translateToUTC.

date1 = date2. "false"
date1 hash = date2 hash. "false"

dictionary := Dictionary new.

dictionary at: date1 put: date1.
dictionary at: date2 put: date2.

(dictionary at: date1) = date1. "true"
(dictionary at: date2) = date2. "true"

dictionary. "a Dictionary(17 October 2018->17 October 2018 17 October 2018->17 October 2018 )"

date1 offset. "0:02:00:00"
date2 offset. "0:00:00:00"

Both dates are different, but they are equal (an operation that ignores the offsets)

date1 equals: date2. "true"

Sven

> On 17 Oct 2018, at 16:33, Chris Cunningham <[hidden email]> wrote:
>
> Hi,
>
> On Tue, Oct 16, 2018 at 1:28 PM Alistair Grant <[hidden email]> wrote:
> Hi Petr,
>
> On Tue, 16 Oct 2018 at 21:25, Petr Fischer via Pharo-users
> <[hidden email]> wrote:
> >
> > My problem - use Dates as Dictionary keys - shortly:
> >
> > d1 := Date today translateToUTC.
> > d2 := Date today.
> >
> > d1 = d2. (true!)
>
> Of course, this doesn't help with using Date as a key in a dictionary.
> Probably your best option is to look at Sven's excellent ZTimezone
> package (although I haven't tested it in this scenario).
>
> The base problem here is that the hash of the dates is not the same for dates that are equal - that should never happen.  If you try
> d1 hash = d2 hash
> you should see that the hash's are different (Petr for sure; you for the cases where the offsets are different).
>
> When objects (especially fo the same class) are =, then their hash must be the same as well, or things break.
>
> -cbc