The Universe of Discourse


Mark Dominus (陶敏修)
mjd@pobox.com


About me

RSS Atom

12 recent entries

My new git utility `what-changed-twice` needs a new name
Mystery of the quincunx's missing quincunx
The fivefold symmetry of the quince
A descriptive theory of seasons in the Mid-Atlantic
Claude and I write a utility program
A puzzle about balancing test tubes in a centrifuge
Proof by insufficient information
Willie Singletary will you please go now?
How our toy octopuses got revenge on a Philadelphia traffic court judge
Does someone really have to do the dirty jobs?
The mathematical past is a foreign country
Baseball on the Moon

Archive:

2025: JF M A MJ
JAS
2024: JF M A M J
J ASOND
2023: JF M A M J
J A S O N D
2022: J F M A M J
JAS O N D
2021: J F M AMJ
J A S O N D
2020: J F M A M J
J A S O N D
2019: JFM A M J
J A S O N D
2018: J F M A M J
J A S O N D
2017: J F M A M J
J A S O N D
2016: JF M A M J
JASON D
2015: JFM A M J
J A S O N D
2014: J F M AMJ
JASON D
2013: JFMAMJ
JAS OND
2012: J F MAMJ
JASOND
2011: JFMAM J
JASOND
2010: JFMAMJ
JA S O ND
2009: J F MAM J
JASOND
2008: J F M A M J
JAS O ND
2007: J F M A M J
J A S O N D
2006: J F M A M J
JAS O N D
2005: O N D


Subtopics:

Book 50
Tech 49
Oops 30
Unix 27
Law 22
Perl 17
Brain 15
Food 15

Higher-Order Perl Blosxom

Comments disabled


2013年12月23日

Two reasons I don't like DateTime's "floating" time zone

(This is a companion piece to my article about DateTime::Moonpig on the Perl Advent Calendar today. One of the ways DateTime::Moonpig differs from DateTime is by defaulting to UTC time instead of to DateTime's "floating" time zone. This article explains some of the reasons why.)

Perl's DateTime module lets you create time values in a so-called "floating" time zone. What this means really isn't clear. It would be coherent for it to mean a time with an unknown or unspecified time zone, but it isn't treated that way. If it were, you wouldn't be allowed to compare "floating" times with regular times, or convert "floating" times to epoch times. If "floating" meant "unspecified time zone", the computer would have to honestly say that it didn't know what to do in such cases. But it doesn't.

Unfortunately, this confused notion is the default.

Here are two demonstrations of why I don't like "floating" time zones.

1.

The behavior of the set_time_zone method may not be what you were expecting, but it makes sense and it is useful:

 my $a = DateTime->new( second => 0,
 minute => 0,
 hour => 5,
 day => 23,
 month => 12,
 year => 2013,
 time_zone => "America/New_York",
 );
 printf "The time in New York is %s.\n", $a->hms;
 $a->set_time_zone("Asia/Seoul");
 printf "The time in Seoul is %s.\n", $a->hms;

Here we have a time value and we change its time zone from New York to Seoul. There are at least two reasonable ways to behave here. This could simply change the time zone, leaving everything else the same, so that the time changes from 05:00 New York time to 05:00 Seoul time. Or changing the time zone could make other changes to the object so that it represents the same absolute time as it did before: If I pick up the phone at 05:00 in New York and call my mother-in-law in Seoul, she answers the call at 19:00 in Seoul, so if I change the object's time zone from New York to Seoul, it should change from 05:00 to 19:00.

DateTime chooses the second of these: setting the time zone retains the absolute time stored by the object, so this program prints:

 The time in New York is 05:00:00.
 The time in Seoul is 19:00:00.

Very good. And we can get to Seoul by any route we want:

 $a->set_time_zone("Europe/Berlin");
 $a->set_time_zone("Chile/EasterIsland");
 $a->set_time_zone("Asia/Seoul");
 printf "The time in Seoul is still %s.\n", $a->hms;

This prints:

 The time in Seoul is still 19:00:00.

We can hop all around the globe, but the object always represents 19:00 in Seoul, and when we get back to Seoul it's still 19:00.

But now let's do the same thing with floating time zones:

 my $b = DateTime->new( second => 0,
 minute => 0,
 hour => 5,
 day => 23,
 month => 12,
 year => 2013,
 time_zone => "America/New_York",
 );
 printf "The time in New York is %s.\n", $b->hms;
 $b->set_time_zone("floating");
 $b->set_time_zone("Asia/Seoul");
 printf "The time in Seoul is %s.\n", $b->hms;

Here we take a hop through the imaginary "floating" time zone. The output is now:

 The time in New York is 05:00:00.
 The time in Seoul is 05:00:00.

The time has changed! I said there were at least two reasonable ways to behave, and that set_time_zone behaves in the second reasonable way. Which it does, except that conversions to the "floating" time zone behave the first reasonable way. Put together, however, they are unreasonable.

2.

 use DateTime;
 sub dec23 {
 my ($hour, $zone) = @_;
 return DateTime->new( second => 0,
 minute => 0,
 hour => $hour,
 day => 23,
 month => 12,
 year => 2013,
 time_zone => $zone,
 );
 }
 my $a = dec23( 8, "Asia/Seoul" );
 my $b = dec23( 6, "America/New_York" );
 my $c = dec23( 7, "floating" );
 printf "A is %s B\n", $a < $b ? "less than" : "not less than";
 printf "B is %s C\n", $b < $c ? "less than" : "not less than";
 printf "C is %s A\n", $c < $a ? "less than" : "not less than";

With DateTime 1.04, this prints:

 A is less than B
 B is less than C
 C is less than A

There are non-transitive relations in the world, but comparison of times is not among them. And if your relation is not transitive, you have no business binding it to the < operator.

However...

Rik Signes points out that the manual says:

If you are planning to use any objects with a real time zone, it is strongly recommended that you do not mix these with floating datetimes.

However, while a disclaimer in the manual can document incorrect behavior, it does not annul it. A bug doesn't stop being a bug just because you document it in the manual. I think it would have been possible to implement floating times sanely, but DateTime didn't do that.

[ Addendum: Rik has now brought to my attention that while the primary ->new constructor defaults to the "floating" time zone, the ->now method always returns the current time in the UTC zone, which seems to me to be a mockery of the advice not to mix the two. ]


[Other articles in category /prog/perl] permanent link


AltStyle によって変換されたページ (->オリジナル) /