Bug #66102 [Com]: DateTimeZone::listIdentifiers does not return linked timezone
| From: | a dot servedio at technotraffic dot com | Date: | Mon, 11 Aug 2014 14:53:58 +0000 |
| Subject: | Bug #66102 [Com]: DateTimeZone::listIdentifiers does not return linked timezone | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-187078@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=66102&edit=1
ID: 66102
Comment by: a dot servedio at technotraffic dot com
Reported by: a dot servedio at technotraffic dot com
Summary: DateTimeZone::listIdentifiers does not return linked
timezone
Status: Not a bug
Type: Bug
Package: Date/time related
Operating System: Linux, might be any
PHP Version: Irrelevant
Block user comment: N
Private report: N
New Comment:
Hi Derick, and thank you for your answers.
I understand your points.
It's great that there already is a parameter to include linked timezone in the
"backward" list.
America/Montreal and America/Toronto are both valid timezone Identifiers as of today and from
Iana's perspective. America/Montreal was changed to be a link to America/Toronto since they end
up doing the same thing to dates. It has not become deprecated, and it will not be removed from the
timezone list in a foreseeable future
<?php
// instantiate DateTimeZone
new \DateTimeZone("America/Toronto"); /* Works. No exception thrown */
new \DateTimeZone("America/Montreal"); /* Works. No exception thrown */
// get identifiers and identifiers + linked timezone (since 5.3.0)
$tz_ids = DateTimeZone::listIdentifiers();
$tz_ids_all = DateTimeZone::listIdentifiers(DateTimeZone::ALL_WITH_BC);
// test
var_dump(in_array('America/Toronto', $tz_ids))); /* true */
var_dump(in_array('America/Montreal', $tz_ids)); /* false */
var_dump(in_array('America/Montreal', $tz_ids_all)); /* true */
?>
So yes, it's not a bug. DateTimeZone::listIdentifiers CAN return linked timezones.
Would that info be a valid candidate for a comment to that function in the manual? It might help
those that got confused like me and where using for many years a timezone that became a linked
timezone.
Previous Comments:
------------------------------------------------------------------------
[2014-08-11 10:25:24] derick@php.net
Just to comment in the previous comment, which gets things quite a bit wrong:
| \DateTimeZone::listIdentifiers(); /* distinctive timezones */
It actually by default returns all timezone IDs that are not being "deprecated".
| \DateTimeZone::listAbbreviations(); /* all timezones */
Abbreviations are *not* timezones. Please do not think that abbreviations are unique, as they are
not.
| This inconsistency made me certain that this was a bug but it's more of a way
| to help those building a selection menu.
| I believe listIdentifiers() should still return all timezones by default and
| act like the other TZ functions in php and other systems around. To simplify
| tz select menu builders, perhaps the function could get upgraded with a
| parameter like \DateTimeZone::listIdentifiers($distinctive_only = false).
Actually, the choice was made the other way around just because the reason you mention: We
don't want 'duplicates' in lists.
And it is already quite possible to really list *all* identifiers:
$l2 = DateTimeZone::listIdentifiers( DateTimeZone::ALL_WITH_BC );
You can compare which identifiers are "deprecated" through:
<?php
$l1 = DateTimeZone::listIdentifiers();
$l2 = DateTimeZone::listIdentifiers( DateTimeZone::ALL_WITH_BC );
$l = array_diff($l2, $l1);
var_dump($l);
------------------------------------------------------------------------
[2014-08-09 12:33:45] a dot servedio at technotraffic dot com
I see your point..
If you are building an interface that list timezones, 417 distinctive TZ is already long enough. But
if you want to validate a user supplied value, or a database value, that list should not be used for
validation.
Basically:
\DateTimeZone::listIdentifiers(); /* distinctive timezones */
\DateTimeZone::listAbbreviations(); /* all timezones */
new \DateTimeZone($tz); /* all timezones */
ini_set('date.timezone', 'America/Montreal'); /* all timezones */
/etc/timezone content on Linux /* all timezones */
This inconsistency made me certain that this was a bug but it's more of a way to help those
building a selection menu.
I believe listIdentifiers() should still return all timezones by default and act like the other TZ
functions in php and other systems around. To simplify tz select menu builders, perhaps the function
could get upgraded with a parameter like \DateTimeZone::listIdentifiers($distinctive_only = false).
But I guess to not mess up those already using this function that doesn't want linked TZ or
that doesn't know about them, the parameter could be more like $distinctive_only = true by
default.
Either way, with or without any modification to listIdentifiers function, this info about linked tz
and distinctive tz should go into the manual for that function. It would help developers that uses
this function for other cases beside building a fully loaded tz selection list, which involves
linked timezones that are used in other systems and are in fact still valid.
------------------------------------------------------------------------
[2014-08-09 11:30:58] mal dot graty at idioplatform dot com
Yup, I agree with all of that. :)
However it's these two comments specifically that makes me think that it's not expected to
be returned from the listIdentifiers function: https://github.com/eggert/tz/commit/242980fc79ef5fb676383f91505f9cbce6ff74cb#commitcomment-5248692
and https://github.com/eggert/tz/issues/4#issuecomment-27102005
I interpret it as: for anyone already using America/Montreal they should see no change (i.e. can
still be used for time calculations) but it should be omitted from the list because America/Toronto
should be used in preference going forward.
In my view DateTimeZone::listIdentifiers is correct in listing only distinct identifiers, keeping
the list to a bare minimum to choose from (the full list is double the length). This also ensures
that everything in the list has country and lat/lon info, something backward links do not have.
For TZ validation, a try catch around the constructor seems like the best approach. However if you
do need a complete list for some purpose, it can be derived from DateTimeZone::listAbbreviations as
shown in the script below.
Test script:
---------------
// compile
$abbrs = \DateTimeZone::listAbbreviations();
$usable_tzs = array_unique(array_filter(
array_merge(array_map('strtoupper', array_keys($abbrs)), array_reduce(
$abbrs,
function ($tzs, $abbr) {
return array_merge($tzs, array_map(
function ($tz) {
return $tz['timezone_id'];
},
$abbr
));
},
array()
)),
function ($tz) {
return strlen($tz) > 1;
}
));
// validate
foreach ($usable_tzs as $tz) {
try {
new DateTimeZone($tz);
} catch (Exception $e) {
echo $tz . ' is NOT a valid timezone' . PHP_EOL;
}
}
// test
var_dump(in_array('America/Montreal', $usable_tzs));
var_dump(count(DateTimeZone::listIdentifiers()));
var_dump(count($usable_tzs));
Result:
----------------
bool(true)
int(417)
int(834)
------------------------------------------------------------------------
[2014-08-09 09:25:42] a dot servedio at technotraffic dot com
Hi, thank you for taking the time to answer.
The iana maintainer is the same person in both my bug description link and the link you provide.
Now reading both comments, it seems like the reasoning for the "backward" list isn't
only for timezones that may be deprecated, but also for timezones that provides the same end result
as another one and are being provided as "links" instead of distinctive entries.
From the url you provide, he mentions "America/Montreal is redundant", not
"deprecated".
He also says "The TZ setting 'America/Montreal' should work as it did before, for all
time stamps after 1970." in his answer on my link.
Which is probably why <?php new \DateTimeZone("America/Montreal") ?> works.
Which is probably also why the recent tzdata package in Linux will still create a fully usable
/usr/share/zoneinfo/America/Montreal entry as of today, and that /etc/timezone can hold
'America/Montreal' no problem.
------------------------------------------------------------------------
[2014-08-09 03:57:30] mal dot graty at idioplatform dot com
If I understand correctly, this is expected behaviour.
America/Montreal is, in effect, deprecated. It will still work, for anything already using it, but
going forward America/Toronto should be chosen instead.
This decision was taken by the IANA, and isn't related to PHP.
There have been discussions here
(https://github.com/eggert/tz/commit/242980fc79ef5fb676383f91505f9cbce6ff74cb#commitcomment-5248365)
and here (https://github.com/eggert/tz/issues/4) that explain the reasoning for doing so.
tl;dr: Linked timezones function, but do not appear in DateTimeZone::listIdentifiers by design,
since they are only linked for backward compatibility, and should not be used going forward where
possible.
------------------------------------------------------------------------
The remainder of the comments for this report are too long. To view
the rest of the comments, please view the bug report online at
https://bugs.php.net/bug.php?id=66102
--
Edit this bug report at https://bugs.php.net/bug.php?id=66102&edit=1