Is there an easy way to retrieve the locale from the timezone_identifier?
For example:
date_default_timezone_set('Europe/Berlin');
The Locale in that case should de_DE.
As deceze said there is no possiblity of this. But you can get location information from timezone. as php.net says
$tz = new DateTimeZone("Europe/Prague");
print_r($tz->getLocation());
print_r(timezone_location_get($tz));
will output
Array
(
[country_code] => CZ
[latitude] => 50.08333
[longitude] => 14.43333
[comments] =>
)
Array
(
[country_code] => CZ
[latitude] => 50.08333
[longitude] => 14.43333
[comments] =>
)
No, because there's no such 1:1 correlation. Take Belgium for example, where they officially speak three languages in the same timezone.
Related
I want to use date_sunset and date_sunrise php's functions but the result is not accurate .. I have the user's IP, Longitude, Latitude and i googled how to calculate Zenith value but found nothing.
And the final value in those functions is GMT Offset that i couldn't get it also.
This is available values that i can get for any client and want to use it to get Zenith and GMT Offset ..
geoiprecord Object (
[country_code] => EG
[country_code3] => EGY
[country_name] => Egypt
[region] => C
[city] => Cairo
[postal_code] =>
[latitude] => 30.0771
[longitude] => 31.2859
[area_code] =>
[dma_code] =>
[metro_code] =>
[continent_code] => AF
[region_name] => Cairo Governorate
[timezone] => Africa/Cairo
)
Just leave the $zenith and $gmt_offset parameters at their defaults. The result of these functions is an integer timestamp which is in terms of UTC. Simply convert the result to the time zone you have in your data "Africa/Cairo".
See this answer for a good example of how to convert timestamp to a specific time zone in PHP.
I have an array $dataStoreForTableImport set up in the following way.
$dataStoreForTableImport['title']
$dataStoreForTableImport['content']
$dataStoreForTableImport['date']
$dataStoreForTableImport['link']
$dataStoreForTableImport['username']
$dataStoreForTableImport['website']
It contains data as below
Array
(
[0] => Array
(
[title] => Quote from Tony Blair
[content] => ... from beating it I'm afraid." (Tony Blair, Sky News) He had every opportunity to put religion in its ...
[articledate] => 28/09/2013
[link] => http://boards.fool.co.uk/message.asp?source=isesitlnk0000001&mid=12890951
[Username] => Michael Dray
[website] => The Motley Fool
)
[1] => Array
(
[title] => Re: The Tony Blair Show
[content] => ... I am irritated that he got such an easy ride; Why? Because he is not to your political liking? He was a witness; he was not on trial and he spoke under oath. What did you expect Jay to ask him? I had dealings with a QC a few years ago. He was as ...
[articledate] => 28/05/2012
[link] => http://boards.fool.co.uk/message.asp?source=isesitlnk0000001&mid=12564154
[Username] => Michael Dray
[website] => The Motley Fool
)
[2] => Array
(
[title] => Re: The Tony Blair Show
[content] => ... If your doubts about Jay's competence/bias were shared I'm sure it would have been debated ad nauseam on Radio 4. Eh - are you serious? I'm a Radio 4 fan - but thats despite its hatred of all things right of centre, not becuase of. ...
[articledate] => 28/05/2012
[link] => http://boards.fool.co.uk/message.asp?source=isesitlnk0000001&mid=12564167
[Username] => Michael Dray
[website] => The Motley Fool
)
[3] => Array
(
[title] => Re: The Tony Blair Show
[content] => ... Maybe Tony should have brought Cherie with him - remember Rupert Murdoch and the reaction of Wendi Deng to the custard pie incident. IMHO Cherie is every bit as intimidating:-) Wendi Deng did not eject the pie flinger, she intervened when he acted. Use of an angled bat to deflect criticism from ...
[articledate] => 30/05/2012
[link] => http://boards.fool.co.uk/message.asp?source=isesitlnk0000001&mid=12565346
[Username] => Michael Dray
[website] => The Motley Fool
)
[4] => Array
(
[title] => Re: The Tony Blair Show
[content] => ... What did surprise me was the fact that he had his own personal bodyguards in the hearing with him. Although, given the level of security that allowed that protester to break into the hearing, maybe he had a point! Eh? He is clearly at risk of terror ...
[articledate] => 28/05/2012
[link] => http://boards.fool.co.uk/message.asp?source=isesitlnk0000001&mid=12564500
[Username] => Michael Dray
[website] => The Motley Fool
)
I want to be able to remove rows from this array that if the articleDate is before a given date.
I have tried everything but it does not seem to work. I am not even able to get it to sort correctly by date?
The date comes in the format - February 10, 2007
I have used
$sortDate = date('d/m/Y', strtotime($sortDate));
to format it to the format shown in the array above.
Can anyone please help?
Thanks
Mike
Do the filtering and sorting of rows in the database backend. This will improve the performance of you app. Use a WHERE clause for filtering by date and an ORDER BY clause for ordering by date in you SQL query.
I'm revisiting this as I'm working on another page that I want to use the same concept.
This page shows the output that I'm currently getting from my MSSQL server.
I have a table of venue information (name, address, etc...) that our events happen on. Separately, I have a table of the actual events that are scheduled (an event may happen multiple times in one day and/or over multiple days). I join those tables with a query (as seen below).
<?php
try {
$dbh = new PDO("sqlsrv:Server=localhost;Database=Sermons", "", "");
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$sql = "SELECT TOP (100) PERCENT dbo.TblSermon.Day, dbo.TblSermon.Date, dbo.TblSermon.Time, dbo.TblSermon.Speaker, dbo.TblSermon.Series, dbo.TblSermon.Sarasota, dbo.TblSermon.NonFlc, dbo.TblJoinSermonLocation.MeetingName, dbo.TblLocation.Location, dbo.TblLocation.Pastors, dbo.TblLocation.Address, dbo.TblLocation.City, dbo.TblLocation.State, dbo.TblLocation.Zip, dbo.TblLocation.Country, dbo.TblLocation.Phone, dbo.TblLocation.Email, dbo.TblLocation.WebAddress
FROM dbo.TblLocation RIGHT OUTER JOIN dbo.TblJoinSermonLocation ON dbo.TblLocation.ID = dbo.TblJoinSermonLocation.Location RIGHT OUTER JOIN dbo.TblSermon ON dbo.TblJoinSermonLocation.Sermon = dbo.TblSermon.ID
WHERE (dbo.TblSermon.Date >= { fn NOW() })
ORDER BY dbo.TblSermon.Date, dbo.TblSermon.Time";
$stmt = $dbh->prepare($sql);
$stmt->execute();
$stmt->setFetchMode(PDO::FETCH_ASSOC);
foreach ($stmt as $row) {
echo "<pre>";
print_r($row);
echo "</pre>";
}
unset($row);
$dbh = null;
}
catch(PDOException $e) {
echo $e->getMessage();
}
?>
So, as it loops through the query results, it creates an array for each record.
Array
(
[Day] => Tuesday
[Date] => 2012-10-30 00:00:00.000
[Time] => 07:00 PM
[Speaker] => Keith Moore
[Location] => The Ark Church
[Pastors] => Alan & Joy Clayton
[Address] => 450 Humble Tank Rd.
[City] => Conroe
[State] => TX
[Zip] => 77305.0
[Phone] => (936) 756-1988
[Email] => info#thearkchurch.com
[WebAddress] => http://www.thearkchurch.org
)
Array
(
[Day] => Wednesday
[Date] => 2012-10-31 00:00:00.000
[Time] => 07:00 PM
[Speaker] => Keith Moore
[Location] => The Ark Church
[Pastors] => Alan & Joy Clayton
[Address] => 450 Humble Tank Rd.
[City] => Conroe
[State] => TX
[Zip] => 77305.0
[Phone] => (936) 756-1988
[Email] => info#thearkchurch.com
[WebAddress] => http://www.thearkchurch.org
)
Array
(
[Day] => Tuesday
[Date] => 2012-11-06 00:00:00.000
[Time] => 07:00 PM
[Speaker] => Keith Moore
[Location] => Fellowship Of Faith Christian Center
[Pastors] => Michael & Joan Kalstrup
[Address] => 18999 Hwy. 59
[City] => Oakland
[State] => IA
[Zip] => 51560.0
[Phone] => (712) 482-3455
[Email] => ffcc#frontiernet.net
[WebAddress] => http://www.fellowshipoffaith.cc
)
Array
(
[Day] => Wednesday
[Date] => 2012-11-14 00:00:00.000
[Time] => 07:00 PM
[Speaker] => Keith Moore
[Location] => Faith Family Church
[Pastors] => Michael & Barbara Cameneti
[Address] => 8200 Freedom Ave NW
[City] => Canton
[State] => OH
[Zip] => 44720.0
[Phone] => (330) 492-0925
[Email] =>
[WebAddress] => http://www.myfaithfamily.com
)
What I'm wanting to do is combine those arrays, in some fashion, so that the venue information isn't repeated every time, but each date/time is show.
I tried typing it out in array style, but couldn't figure out the appropriate multi-dimensionality for it. I'm just pasting how I would like it to display, since that is how it will end up.
The Ark Church
Contact:
Alan & Joy Clayton
450 Humble Tank Rd.
Conroe, TX 77305
(936) 756-1988
info#thearkchurch.com
http://www.thearkchurch.org
Meetings:
Tuesday, 2012-10-30 07:00 PM
Wednesday, 2012-10-31 07:00 PM
Fellowship Of Faith Christian Center
Contact:
Michael & Joan Kalstrup
18999 Hwy. 59
Oakland, IA 51560
(712) 482-3455
ffcc#frontiernet.net
http://www.fellowshipoffaith.cc
Meetings:
Tuesday, 2012-11-06 07:00 PM
Faith Family Church
Contact:
Michael & Barbara Cameneti
8200 Freedom Ave NW
Canton, OH 44720
(330) 492-0925
http://www.myfaithfamily.com
Meetings:
Wednesday, 2012-11-14 07:00 PM
It doesn't necessarily have to end up like that, but it should give a good idea of what I'm looking for.
I don't necessarily have to create a new array. I just want to not show the same information over and over and over.
I was thinking that I could just do some form of compare, in foreach() that says something along the lines of "if Location is the same as previous Location", but I haven't figured out how to do it (is there a way to cache a previous variable with doing $location1 = [Location], $location2 = [Location], etc...?
One thing to note...
These examples don't have different speakers, but sometimes there are. I would like to be able to access the speaker, somehow. I assume that I would want it bound to the actual event.
JJ
One technique: if you have a loop like this:
while ($row = $query->fetch(PDO::FETCH_NUM) ) {
list($time,$place,$etc) = $row;
// display formatted data
}
try this instead:
$row = $query->fetch();
do {
list($time,$place,$etc) = $row;
$row = $query->fetch(PDO::FETCH_NUM);
if ($time != $row[0] && $place != $row[1] && $etc != $row[2]) {
// display formatted data
}
} while ($row);
I usually would approach a problem like this by creating a two-dimensinoal array, indexed by date then ID or in your case by ID then date.
Loop through events (the first dimension) and print out the contents of that event - while in there loop through the dates on that event and print those out as a list as in your example.
I don't know how to do this in php. I am trying to get geocode data from openstreetmap.org but I need to do this in php.
In Javascript (and I have this working), it's:
<script type="text/javascript"
src="http://nominatim.openstreetmap.org/reverse?format=xml&lat=43.642018&lon=-79.374671">
</script>
I have that url but I don't know how to execute it in php.
I have tried:
<?php
$url = "http://nominatim.openstreetmap.org/reverse?format=xml&lat=43.642018&lon=-79.374671";
$response = file_get_contents($url);
?>
But this doesn't work. I tried the same with curl. Any ideas or is this type of query not possible in php?
Use this;
$xml = simplexml_load_file("http://nominatim.openstreetmap.org/reverse?format=xml&lat=43.642018&lon=-79.374671");
print_r($xml);
which will return you with an array of the values, see below;
SimpleXMLElement Object
(
[#attributes] => Array
(
[timestamp] => Thu, 22 Mar 12 18:31:11 +0000
[attribution] => Data Copyright OpenStreetMap Contributors, Some Rights Reserved. CC-BY-SA 2.0.
[querystring] => format=xml&lat=43.642018&lon=-79.374671
)
[result] => 1, Yonge Street, Corktown, Toronto, Ontario, M5B2H1, Canada
[addressparts] => SimpleXMLElement Object
(
[house_number] => 1
[road] => Yonge Street
[suburb] => Corktown
[city] => Toronto
[county] => Toronto
[state] => Ontario
[postcode] => M5B2H1
[country] => Canada
[country_code] => ca
)
)
Then manipulate the data however you see fit.
It does return
<?xml version="1.0" encoding="UTF-8" ?>
<reversegeocode timestamp='Thu, 22 Mar 12 18:07:13 +0000' attribution='Data Copyright OpenStreetMap Contributors, Some Rights Reserved. CC-BY-SA 2.0.' querystring='format=xml&lat=100&Lon=100'>
<error>Unable to geocode</error></reversegeocode>
That just means that there is no address for that particular coordinate.. This however has
http://nominatim.openstreetmap.org/reverse?format=xml&lat=52.5487429714954&lon=100
Read API if you need more details
I'll try to explain what's the problem here.
According to list of supported timezones from PHP manual, I can see all valid TZ identifiers in PHP.
My first question is how to get that list from code but that's not what I really need.
My final goal is to write function isValidTimezoneId() that returns TRUE if timezone is valid, otherwise it should return FALSE.
function isValidTimezoneId($timezoneId) {
# ...function body...
return ?; # TRUE or FALSE
}
So, when I pass TZ identifier using $timezoneId (string) in function I need boolean result.
Well, what I have so far...
1) Solution using # operator
First solution I've got is something like this:
function isValidTimezoneId($timezoneId) {
$savedZone = date_default_timezone_get(); # save current zone
$res = $savedZone == $timezoneId; # it's TRUE if param matches current zone
if (!$res) { # 0r...
#date_default_timezone_set($timezoneId); # try to set new timezone
$res = date_default_timezone_get() == $timezoneId; # it's true if new timezone set matches param string.
}
date_default_timezone_set($savedZone); # restore back old timezone
return $res; # set result
}
That works perfectly, but I want another solution (to avoid trying to set wrong timezone)
2) Solution using timezone_identifiers_list()
Then, I was trying to get list of valid timezone identifiers and check it against parameter using in_array() function. So I've tried to use timezone_identifiers_list(), but that was not so good because a lot of timezones was missing in array returned by this function (alias of DateTimeZone::listIdentifiers()). At first sight that was exactly what I was looking for.
function isValidTimezoneId($timezoneId) {
$zoneList = timezone_identifiers_list(); # list of (all) valid timezones
return in_array($timezoneId, $zoneList); # set result
}
This code looks nice and easy but than I've found that $zoneList array contains ~400 elements. According to my calculations it should return 550+ elements. 150+ elements are missing... So that's not good enough as solution for my problem.
3) Solution based on DateTimeZone::listAbbreviations()
This is last step on my way trying to find perfect solution. Using array returned by this method I can extract all timezone identifiers supported by PHP.
function createTZlist() {
$tza = DateTimeZone::listAbbreviations();
$tzlist = array();
foreach ($tza as $zone)
foreach ($zone as $item)
if (is_string($item['timezone_id']) && $item['timezone_id'] != '')
$tzlist[] = $item['timezone_id'];
$tzlist = array_unique($tzlist);
asort($tzlist);
return array_values($tzlist);
}
This function returns 563 elements (in Example #2 I've got just 407).
I've tried to find differences between those two arrays:
$a1 = timezone_identifiers_list();
$a2 = createTZlist();
print_r(array_values(array_diff($a2, $a1)));
Result is:
Array
(
[0] => Africa/Asmera
[1] => Africa/Timbuktu
[2] => America/Argentina/ComodRivadavia
[3] => America/Atka
[4] => America/Buenos_Aires
[5] => America/Catamarca
[6] => America/Coral_Harbour
[7] => America/Cordoba
[8] => America/Ensenada
[9] => America/Fort_Wayne
[10] => America/Indianapolis
[11] => America/Jujuy
[12] => America/Knox_IN
[13] => America/Louisville
[14] => America/Mendoza
[15] => America/Porto_Acre
[16] => America/Rosario
[17] => America/Virgin
[18] => Asia/Ashkhabad
[19] => Asia/Calcutta
[20] => Asia/Chungking
[21] => Asia/Dacca
[22] => Asia/Istanbul
[23] => Asia/Katmandu
[24] => Asia/Macao
[25] => Asia/Saigon
[26] => Asia/Tel_Aviv
[27] => Asia/Thimbu
[28] => Asia/Ujung_Pandang
[29] => Asia/Ulan_Bator
[30] => Atlantic/Faeroe
[31] => Atlantic/Jan_Mayen
[32] => Australia/ACT
[33] => Australia/Canberra
[34] => Australia/LHI
[35] => Australia/NSW
[36] => Australia/North
[37] => Australia/Queensland
[38] => Australia/South
[39] => Australia/Tasmania
[40] => Australia/Victoria
[41] => Australia/West
[42] => Australia/Yancowinna
[43] => Brazil/Acre
[44] => Brazil/DeNoronha
[45] => Brazil/East
[46] => Brazil/West
[47] => CET
[48] => CST6CDT
[49] => Canada/Atlantic
[50] => Canada/Central
[51] => Canada/East-Saskatchewan
[52] => Canada/Eastern
[53] => Canada/Mountain
[54] => Canada/Newfoundland
[55] => Canada/Pacific
[56] => Canada/Saskatchewan
[57] => Canada/Yukon
[58] => Chile/Continental
[59] => Chile/EasterIsland
[60] => Cuba
[61] => EET
[62] => EST
[63] => EST5EDT
[64] => Egypt
[65] => Eire
[66] => Etc/GMT
[67] => Etc/GMT+0
[68] => Etc/GMT+1
[69] => Etc/GMT+10
[70] => Etc/GMT+11
[71] => Etc/GMT+12
[72] => Etc/GMT+2
[73] => Etc/GMT+3
[74] => Etc/GMT+4
[75] => Etc/GMT+5
[76] => Etc/GMT+6
[77] => Etc/GMT+7
[78] => Etc/GMT+8
[79] => Etc/GMT+9
[80] => Etc/GMT-0
[81] => Etc/GMT-1
[82] => Etc/GMT-10
[83] => Etc/GMT-11
[84] => Etc/GMT-12
[85] => Etc/GMT-13
[86] => Etc/GMT-14
[87] => Etc/GMT-2
[88] => Etc/GMT-3
[89] => Etc/GMT-4
[90] => Etc/GMT-5
[91] => Etc/GMT-6
[92] => Etc/GMT-7
[93] => Etc/GMT-8
[94] => Etc/GMT-9
[95] => Etc/GMT0
[96] => Etc/Greenwich
[97] => Etc/UCT
[98] => Etc/UTC
[99] => Etc/Universal
[100] => Etc/Zulu
[101] => Europe/Belfast
[102] => Europe/Nicosia
[103] => Europe/Tiraspol
[104] => Factory
[105] => GB
[106] => GB-Eire
[107] => GMT
[108] => GMT+0
[109] => GMT-0
[110] => GMT0
[111] => Greenwich
[112] => HST
[113] => Hongkong
[114] => Iceland
[115] => Iran
[116] => Israel
[117] => Jamaica
[118] => Japan
[119] => Kwajalein
[120] => Libya
[121] => MET
[122] => MST
[123] => MST7MDT
[124] => Mexico/BajaNorte
[125] => Mexico/BajaSur
[126] => Mexico/General
[127] => NZ
[128] => NZ-CHAT
[129] => Navajo
[130] => PRC
[131] => PST8PDT
[132] => Pacific/Ponape
[133] => Pacific/Samoa
[134] => Pacific/Truk
[135] => Pacific/Yap
[136] => Poland
[137] => Portugal
[138] => ROC
[139] => ROK
[140] => Singapore
[141] => Turkey
[142] => UCT
[143] => US/Alaska
[144] => US/Aleutian
[145] => US/Arizona
[146] => US/Central
[147] => US/East-Indiana
[148] => US/Eastern
[149] => US/Hawaii
[150] => US/Indiana-Starke
[151] => US/Michigan
[152] => US/Mountain
[153] => US/Pacific
[154] => US/Pacific-New
[155] => US/Samoa
[156] => Universal
[157] => W-SU
[158] => WET
[159] => Zulu
)
This list contains all valid TZ identifiers that Example #2 failed to match.
There's four TZ identifiers more (part of $a1):
print_r(array_values(array_diff($a1, $a2)));
Output
Array
(
[0] => America/Bahia_Banderas
[1] => Antarctica/Macquarie
[2] => Pacific/Chuuk
[3] => Pacific/Pohnpei
)
So now, I have almost perfect solution...
function isValidTimezoneId($timezoneId) {
$zoneList = createTZlist(); # list of all valid timezones (last 4 are not included)
return in_array($timezoneId, $zoneList); # set result
}
That's my solution and I can use it. Of course, I use this function as part of class so I don't need to generate $zoneList on every methods call.
What I really need here?
I'm wondering, is there any easier (quicker) solution to get list of all valid timezone identifiers as array (I want to avoid extracting that list from DateTimeZone::listAbbreviations() if that's possible)? Or if you know another way how to check is timezone parameter valid, please let me know (I repeat, # operator can't be part of solution).
P.S. If you need more details and examples, let me know. I guess you don't.
I'm using PHP 5.3.5 (think that's not important).
Update
Any part of code that throws exception on invalid timezone string (hidden using # or caught using try..catch block) is not solution I'm looking for.
Another update
I've put small bounty on this question!
Now I'm looking for the easiest way how to extract list of all timezone identifiers in PHP array.
Why not use # operator?
This code works pretty well, and you don't change default timezone:
function isValidTimezoneId($timezoneId) {
#$tz=timezone_open($timezoneId);
return $tz!==FALSE;
}
If you don't want #, you can do:
function isValidTimezoneId($timezoneId) {
try{
new DateTimeZone($timezoneId);
}catch(Exception $e){
return FALSE;
}
return TRUE;
}
You solution works fine, so if it's speed you're looking for I would look more closely at what you're doing with your arrays. I've timed a few thousand trials to get reasonable average times, and these are the results:
createTZlist : 20,713 microseconds per run
createTZlist2 : 13,848 microseconds per run
Here's the faster function:
function createTZList2()
{
$out = array();
$tza = timezone_abbreviations_list();
foreach ($tza as $zone)
{
foreach ($zone as $item)
{
$out[$item['timezone_id']] = 1;
}
}
unset($out['']);
ksort($out);
return array_keys($out);
}
The if test is faster if you reduce it to just if ($item['timezone_id']), but rather than running it 489 times to catch a single case, it's quicker to unset the empty key afterwards.
Setting hash keys allows us the skip the array_unique() call which is more expensive. Sorting the keys and then extracting them is a tiny bit faster than extracting them and then sorting the extracted list.
If you drop the sorting (which is not needed unless you're comparing the list), it gets down to 12,339 microseconds.
But really, you don't need to return the keys anyway. Looking at the holistic isValidTimezoneId(), you'd be better off doing this:
function isValidTimezoneId2($tzid)
{
$valid = array();
$tza = timezone_abbreviations_list();
foreach ($tza as $zone)
{
foreach ($zone as $item)
{
$valid[$item['timezone_id']] = true;
}
}
unset($valid['']);
return !!$valid[$tzid];
}
That is, assuming you only need to test once per execution, otherwise you'd want to save $valid after the first run. This approach avoids having to do a sort or converting the keys to values, key lookups are faster than in_array() searches and there's no extra function call. Setting the array values to true instead of 1 also removes a single cast when the result is true.
This brings it reliably down to under 12ms on my test machine, almost half the time of your example. A fun experiment in micro-optimizations!
When I tried this on a Linux system running 5.3.6, your Example #2 gave me 411 zones and Example #3 gave 496. The following slight modification to Example #2 gives me 591:
$zoneList = timezone_identifiers_list(DateTimeZone::ALL_WITH_BC);
There are no zones returned by Example #3 that are not returned with that modified Example #2.
On an OS X system running 5.3.3, Example #2 gives 407, Example #3 gives 564, and the modified Example #2 gives 565. Again, there are no zones returned by Example #3 that are not returned with that modified Example #2.
On a Linux system running 5.2.6 with the timezonedb PECL extension installed, Example #2 gives me 571 zones and Example #3 gives me only 488. There are no zones returned by Example #3 that are not by Example #2 on this system. The constant DateTimeZone::ALL_WITH_BC does not seem to exist in 5.2.6; it was probably added in 5.3.0.
So it seems the simplest way to get a list of all time zones in 5.3.x is
timezone_identifiers_list(DateTimeZone::ALL_WITH_BC), and in 5.2.x is timezone_identifiers_list(). The simplest (if not fastest) way to check if a particular string is a valid time zone is still probably #timezone_open($timezoneId) !== false.
If you're on Linux most if not all information on timezones there stored at /usr/share/zoneinfo/. You can walk over them using is_file() and related functions.
You can also parse the former files with zdump for codes or fetch sources for these files and grep/cut out needed info. Again, you are not obliged to use built-in functions to accomplish the task. There isn't a rationale why would someone force you to use only the built-in date functions.
See in PHP sources on php_date.c and timezonemap.h that`s why I can say this is always in 101.111111% static info (but per php build).
If you want to get it dynamically, use timezone_abbreviations_list as DateTimeZone::listAbbreviations is a map to it.
As you can see all these values are just one time filled list for current PHP version.
So much faster solution is simple -- prepare somehow static file with retrieved ids one time per server during install of your app and use it.
For example:
function isValidTZ($zone) {
static $zones = null;
if (null === $zones) {
include $YOUR_APP_STORAGE . '/tz_list.php';
}
// isset is muuuch faster than array_key_exists and also than in_array
// so you should work with structure like [key => 1]
return isset($zones[$zone]);
}
tz_list.php should be like this:
<?php
$zones = array(
'Africa/Abidjan' => 1,
'Africa/Accra' => 1,
'Africa/Addis_Ababa' => 1,
// ...
);
I would research what changes the perfect array and use a basic caching mechanism (like store the array in a file, that you include and update when needed). You're currently optimizing building an array that is static for 99.9999% of all the requests.
Edit:
Ok, static/dynamic.
if( !function_exists(timezone_version_get) )
{
function timezone_version_get() { return '2009.6'; }
}
include 'tz_list_' . PHP_VERSION . '_' . timezone_version_get() . '.php';
Now each time the php version is updated, the file should be regenerated automatically by your code.
In case of php<5.3, how about this?
public static function is_valid_timezone($timezone)
{
$now_timezone = #date_default_timezone_get();
$result = #date_default_timezone_set($timezone);
if( $now_timezone ){
// set back to current timezone
date_default_timezone_set($now_timezone);
}
return $result;
}
Just an addendum to Cal's excellent answer. I think the following might be even faster...
function isValidTimezoneID($tzid) {
if (empty($tzid)) {
return false;
}
foreach (timezone_abbreviations_list() as $zone) {
foreach ($zone as $item) {
if ($item["timezone_id"] == $tzid) {
return true;
}
}
}
return false;
}