diff --git a/inc/tz/list.php b/inc/tz/list.php
new file mode 100644
index 00000000..391d7ee7
--- /dev/null
+++ b/inc/tz/list.php
@@ -0,0 +1,76 @@
+
+* @copyright Morphoss Ltd
+* @license http://gnu.org/copyleft/gpl.html GNU GPL v3 or later
+*/
+
+require_once('vComponent.php');
+
+$response = new XMLDocument( array("" => "urn:ietf:params:xml:ns:timezone-service") );
+$tzlist = $response->NewXMLElement('timezone-list');
+$tzlist->NewElement('dtstamp', gmdate('Ymd\THis\Z'));
+
+$sql = 'SELECT our_tzno, tzid, active, to_char(last_modified AT TIME ZONE \'UTC\',\'YYYYMMDD\"T\"HH24MISS"Z"\') AS last_modified, olson_name, vtimezone FROM timezones';
+$params = array();
+$where = '';
+if ( $returnall !== true ) {
+ $where = 'active';
+}
+if ( !empty($changedsince) ) {
+ if ( !empty($where) ) $where .= ' AND ';
+ $where .= 'last_modified >= :changedsince';
+ $params[':changedsince'] = $changedsince;
+}
+if ( !empty($where)) $sql .= ' WHERE '.$where;
+
+/*
+2009-10-11T09:32:11Z
+
+America/New_York
+2009-09-17T01:39:34Z
+US/Eastern
+America/New_York
+
+*/
+$q2 = new AwlQuery();
+$qry = new AwlQuery($sql,$params);
+if ( $qry->Exec('tz/list',__LINE__,__FILE__) && $qry->rows() > 0 ) {
+ while( $tz = $qry->Fetch() ) {
+ $elements = array(
+ new XMLElement('tzid', $tz->tzid),
+ new XMLElement('last-modified', $tz->last_modified)
+ );
+ if ( $tz->active != 't' ) {
+ $elements[] = new XMLElement('inactive' );
+ }
+ if ( $tz->tzid != $tz->olson_name ) {
+ $elements[] = new XMLElement('alias', $tz->olson_name );
+ }
+ if ( $q2->QDo('SELECT * FROM tz_aliases WHERE our_tzno = ?', array($tz->our_tzno)) ) {
+ while( $alias = $q2->Fetch() ) {
+ $elements[] = new XMLElement('alias', $alias->tzalias );
+ }
+ }
+ if ( !empty($lang) && $q2->QDo('SELECT * FROM tz_localnames WHERE our_tzno = ? AND locale = ?', array($tz->our_tzno, $lang)) && $q2->rows() > 0 ) {
+ while( $local = $q2->Fetch() ) {
+ $attr = array( 'lang' => $local->locale );
+ if ( $local->preferred == 't' ) $attr['preferred'] = 'true';
+ $elements[] = new XMLElement('local-name', $local->localised_name, $attr );
+ }
+ }
+ else {
+ $elements[] = new XMLElement('local-name', $tz->tzid, array( 'lang' => $lang ) );
+ }
+ $tzlist->NewElement('summary', $elements);
+ }
+}
+
+header('Content-Type: application/xml; charset="utf-8"');
+
+echo $response->Render($tzlist);
+exit(0);
\ No newline at end of file
diff --git a/inc/tz/updatecheck.php b/inc/tz/updatecheck.php
new file mode 100644
index 00000000..2d0ed736
--- /dev/null
+++ b/inc/tz/updatecheck.php
@@ -0,0 +1,100 @@
+
+* @copyright Morphoss Ltd
+* @license http://gnu.org/copyleft/gpl.html GNU GPL v3 or later
+*/
+
+require_once('vCalendar.php');
+
+$new_zones = 0;
+$modified_zones = 0;
+
+if ( empty($c->tzsource) ) $c->tzsource = '../zonedb/vtimezones';
+if ( preg_match('{^http}', $c->tzsource ) ) {
+
+}
+else if ( file_exists($c->tzsource) ) {
+ /**
+ * Find all files recursively within the diectory given.
+ * @param string $dirname The directory to find files in
+ * @return array of filenames with full path
+ */
+ function recursive_files( $dirname ) {
+ $d = opendir($dirname);
+ $result = array();
+ while( $fn = readdir($d) ) {
+ if ( substr($fn,0,1) == '.' ) continue;
+ $fn = $dirname.'/'.$fn;
+ if ( is_dir($fn) ) {
+ $result = array_merge($result,recursive_files($fn));
+ }
+ else {
+ $result[] = $fn;
+ }
+ }
+ return $result;
+ }
+
+ $qry = new AwlQuery();
+ foreach( recursive_files($c->tzsource) AS $filename ) {
+ $tzid = str_replace('.ics', '', str_replace($c->tzsource.'/', '', $filename));
+ $tzrow = null;
+ if ( $qry->QDo('SELECT * FROM timezones WHERE tzid=:tzid', array(':tzid' => $tzid)) && $qry->rows() > 0 ) {
+ $tzrow = $qry->Fetch();
+ }
+ $vtimezone = file_get_contents( $filename, false );
+ if ( $vtimezone == $tzrow->vtimezone ) {
+ dbg_error_log('tz/updatecheck', 'Skipping zone "%s" - no change', $tzid );
+ continue;
+ }
+ $vtz = new vCalendar($vtimezone);
+ $last_modified = $vtz->GetProperty('LAST-MODIFIED');
+ if ( empty($last_modified) ) {
+ $last_modified = gmdate('Ymd\THis\Z');
+ // Then it was probably that way when we last updated the data, too :-(
+ if ( !empty($tzrow) ) {
+ $old_vtz = new vCalendar($tzrow->vtimezone);
+ $old_vtz->ClearProperties('LAST-MODIFIED');
+ // We need to add & remove this property so the Render is equivalent.
+ $vtz->AddProperty('LAST-MODIFIED',$last_modified);
+ $vtz->ClearProperties('LAST-MODIFIED');
+ if ( $vtz->Render() == $old_vtz->Render() ) {
+ dbg_error_log('tz/updatecheck', 'Skipping zone "%s" - no change', $tzid );
+ continue;
+ }
+ }
+ $vtz->AddProperty('LAST-MODIFIED',$last_modified);
+ }
+ dbg_error_log('tz/updatecheck', 'Writing %s zone for "%s"', (empty($tzrow)?"new":"updated"), $tzid );
+ $params = array(
+ ':tzid' => $tzid,
+ ':olson_name' => $tzid,
+ ':vtimezone' => $vtz->Render(),
+ ':last_modified' => $last_modified,
+ ':etag' => md5($vtz->Render())
+ );
+ if ( empty($tzrow) ) {
+ $new_zones++;
+ $sql = 'INSERT INTO timezones(tzid,active,olson_name,last_modified,etag,vtimezone) ';
+ $sql .= 'VALUES(:tzid,TRUE,:olson_name,:last_modified,:etag,:vtimezone)';
+ }
+ else {
+ $modified_zones++;
+ $sql = 'UPDATE timezones SET active=TRUE, olson_name=:olson_name, last_modified=:last_modified, ';
+ $sql .= 'etag=:etag, vtimezone=:vtimezone WHERE tzid=:tzid';
+ }
+ $qry->QDo($sql,$params);
+ }
+ header('Content-type: text/plain');
+ printf('Added %d new zones and updated data for %d zones', $new_zones, $modified_zones);
+}
+else {
+ dbg_error_log('ERROR', '$c->tzsource is not configured to a good source of timezone data');
+}
+
+exit(0);
\ No newline at end of file
diff --git a/testing/tests/timezone/5000-capabilities.result b/testing/tests/timezone/5000-capabilities.result
new file mode 100644
index 00000000..9f0dcbf6
--- /dev/null
+++ b/testing/tests/timezone/5000-capabilities.result
@@ -0,0 +1,115 @@
+HTTP/1.1 200 OK
+Date: Dow, 01 Jan 2000 00:00:00 GMT
+Content-Length: 2986
+Content-Type: application/xml; charset="utf-8"
+
+
+
+
+ Olson:2011m
+ mailto:tzs@example.org
+
+
+
+ list
+ List timezone identifiers and localized forms
+
+
+
+ lang
+ false
+ true
+ Specify desired localized form(s)
+
+
+
+ changedsince
+ false
+ false
+ Limit result to timezones changed since the
+ given date
+
+
+
+
+ returnall
+ false
+ false
+ If present inactive timezones will be returned.
+
+
+
+
+
+ get
+
+ Returns one or more timezones as specified by the
+ tzid parameter.
+
+
+
+ format
+ false
+ false
+ text/calendar
+ application/calendar+xml
+ Specify required format for timezone.
+
+
+
+
+ lang
+ false
+ true
+ Specify desired localized form(s)
+
+
+
+ tzid
+ true
+ true
+ Specify desired timezone identifiers
+
+
+
+
+
+ expand
+
+ Expands the specified timezone(s) into local onset and UTC
+ offsets
+
+
+
+ tzid
+ true
+ true
+ Specify desired timezone identifiers
+
+
+
+ start
+ false
+ false
+
+ Specify start of the period of interest. If omitted the
+ current year is assumed.
+
+
+
+
+ end
+ false
+ false
+
+ Specify end of the period of interest.
+ If omitted the current year + 10 is assumed.
+
+
+
+
+
+ capabilities
+ Gets the capabilities of the server
+
+
diff --git a/testing/tests/timezone/5010-list.result b/testing/tests/timezone/5010-list.result
new file mode 100644
index 00000000..b080df6a
--- /dev/null
+++ b/testing/tests/timezone/5010-list.result
@@ -0,0 +1,81 @@
+HTTP/1.1 200 OK
+Date: Dow, 01 Jan 2000 00:00:00 GMT
+Content-Length: 2677
+Content-Type: application/xml; charset="utf-8"
+
+
+
+ all good
+
+ Pacific/Auckland
+ 20110919T032240Z
+
+ Pacific/Auckland
+
+
+ America/Los_Angeles
+ 20110918T082240Z
+
+ America/Los_Angeles
+
+
+ Europe/Helsinki
+ 20110918T182240Z
+
+ Europe/Helsinki
+
+
+ New Zealand Standard Time
+ 20110919T032248Z
+
+ Pacific/Auckland
+ New Zealand Standard Time
+
+
+ /softwarestudio.org/Olson_20011030_5/Pacific/Auckland
+ 20110919T032253Z
+
+ Pacific/Auckland
+ /softwarestudio.org/Olson_20011030_5/Pacific/Auckland
+
+
+ /mozilla.org/20050126_1/Pacific/Auckland
+ 20110919T032256Z
+
+ Pacific/Auckland
+ /mozilla.org/20050126_1/Pacific/Auckland
+
+
+ /mozilla.org/20050126_1/Antarctica/McMurdo
+ 20110919T032256Z
+
+ Antarctica/McMurdo
+ /mozilla.org/20050126_1/Antarctica/McMurdo
+
+
+ /mozilla.org/20070129_1/Antarctica/McMurdo
+ 20110919T032258Z
+
+ Antarctica/McMurdo
+ /mozilla.org/20070129_1/Antarctica/McMurdo
+
+
+ Europe/Prague
+ 20110919T032319Z
+
+ Europe/Prague
+
+
+ America/New_York
+ 20110918T112328Z
+
+ America/New_York
+
+
+ (UTC-05:00) Eastern Time (US & Canada)
+ 20110918T112401Z
+
+ America/New_York
+ (UTC-05:00) Eastern Time (US & Canada)
+
+
diff --git a/testing/tests/timezone/5010-list.test b/testing/tests/timezone/5010-list.test
index 882dba7c..3018e394 100644
--- a/testing/tests/timezone/5010-list.test
+++ b/testing/tests/timezone/5010-list.test
@@ -2,6 +2,7 @@
# List timezone server timezones
#
TYPE=GET
-URL=http://regression.host/tz.php?action=list
+URL=http://regression.host/tz.php?action=list&returnall&lang=en_US
HEAD
+REPLACE=/dtstamp>[0-9TZ]{16}/dtstamp>all good/
diff --git a/testing/tests/timezone/5011-list.result b/testing/tests/timezone/5011-list.result
new file mode 100644
index 00000000..b0f47d8c
--- /dev/null
+++ b/testing/tests/timezone/5011-list.result
@@ -0,0 +1,9 @@
+HTTP/1.1 200 OK
+Date: Dow, 01 Jan 2000 00:00:00 GMT
+Content-Length: 239
+Content-Type: application/xml; charset="utf-8"
+
+
+
+ all good
+
diff --git a/testing/tests/timezone/5011-list.test b/testing/tests/timezone/5011-list.test
new file mode 100644
index 00000000..d7288120
--- /dev/null
+++ b/testing/tests/timezone/5011-list.test
@@ -0,0 +1,8 @@
+#
+# List timezone server timezones
+#
+TYPE=GET
+URL=http://regression.host/tz.php?action=list
+HEAD
+
+REPLACE=/dtstamp>[0-9TZ]{16}/dtstamp>all good/
diff --git a/testing/tests/timezone/5020-updatecheck.result b/testing/tests/timezone/5020-updatecheck.result
new file mode 100644
index 00000000..e20f3a8b
--- /dev/null
+++ b/testing/tests/timezone/5020-updatecheck.result
@@ -0,0 +1,6 @@
+HTTP/1.1 200 OK
+Date: Dow, 01 Jan 2000 00:00:00 GMT
+Content-Length: 48
+Content-Type: text/plain
+
+Added 362 new zones and updated data for 5 zones
\ No newline at end of file
diff --git a/testing/tests/timezone/5020-updatecheck.test b/testing/tests/timezone/5020-updatecheck.test
new file mode 100644
index 00000000..487a2857
--- /dev/null
+++ b/testing/tests/timezone/5020-updatecheck.test
@@ -0,0 +1,7 @@
+#
+# Request the timezone server update itself
+#
+TYPE=GET
+URL=http://regression.host/tz.php?action=updatecheck
+HEAD
+
diff --git a/testing/tests/timezone/5021-list.result b/testing/tests/timezone/5021-list.result
new file mode 100644
index 00000000..3e17bc27
--- /dev/null
+++ b/testing/tests/timezone/5021-list.result
@@ -0,0 +1,1843 @@
+HTTP/1.1 200 OK
+Date: Dow, 01 Jan 2000 00:00:00 GMT
+Content-Type: application/xml; charset="utf-8"
+
+
+
+ all good
+
+ Europe/Budapest
+ all good
+ Europe/Budapest
+
+
+ Europe/Podgorica
+ all good
+ Europe/Podgorica
+
+
+ Europe/Mariehamn
+ all good
+ Europe/Mariehamn
+
+
+ Europe/Copenhagen
+ all good
+ Europe/Copenhagen
+
+
+ Pacific/Auckland
+ all good
+ Pacific/Auckland
+
+
+ America/New_York
+ all good
+ America/New_York
+
+
+ Europe/Lisbon
+ all good
+ Europe/Lisbon
+
+
+ Europe/Moscow
+ all good
+ Europe/Moscow
+
+
+ Europe/Vienna
+ all good
+ Europe/Vienna
+
+
+ Europe/Andorra
+ all good
+ Europe/Andorra
+
+
+ Europe/Prague
+ all good
+ Europe/Prague
+
+
+ Europe/Simferopol
+ all good
+ Europe/Simferopol
+
+
+ Europe/Amsterdam
+ all good
+ Europe/Amsterdam
+
+
+ Europe/Minsk
+ all good
+ Europe/Minsk
+
+
+ Europe/Monaco
+ all good
+ Europe/Monaco
+
+
+ Europe/Zaporozhye
+ all good
+ Europe/Zaporozhye
+
+
+ Europe/Sofia
+ all good
+ Europe/Sofia
+
+
+ Europe/Tirane
+ all good
+ Europe/Tirane
+
+
+ Europe/Kiev
+ all good
+ Europe/Kiev
+
+
+ Europe/Jersey
+ all good
+ Europe/Jersey
+
+
+ Europe/Helsinki
+ all good
+ Europe/Helsinki
+
+
+ Europe/Istanbul
+ all good
+ Europe/Istanbul
+
+
+ Europe/Sarajevo
+ all good
+ Europe/Sarajevo
+
+
+ Europe/Zurich
+ all good
+ Europe/Zurich
+
+
+ Europe/Riga
+ all good
+ Europe/Riga
+
+
+ Europe/Guernsey
+ all good
+ Europe/Guernsey
+
+
+ Europe/Bucharest
+ all good
+ Europe/Bucharest
+
+
+ Europe/Tallinn
+ all good
+ Europe/Tallinn
+
+
+ Europe/Vatican
+ all good
+ Europe/Vatican
+
+
+ Europe/Berlin
+ all good
+ Europe/Berlin
+
+
+ Europe/Oslo
+ all good
+ Europe/Oslo
+
+
+ Europe/Stockholm
+ all good
+ Europe/Stockholm
+
+
+ Europe/Belgrade
+ all good
+ Europe/Belgrade
+
+
+ Europe/Ljubljana
+ all good
+ Europe/Ljubljana
+
+
+ Europe/Athens
+ all good
+ Europe/Athens
+
+
+ Europe/Madrid
+ all good
+ Europe/Madrid
+
+
+ Europe/Gibraltar
+ all good
+ Europe/Gibraltar
+
+
+ Europe/Bratislava
+ all good
+ Europe/Bratislava
+
+
+ Europe/Warsaw
+ all good
+ Europe/Warsaw
+
+
+ Europe/Brussels
+ all good
+ Europe/Brussels
+
+
+ Europe/Uzhgorod
+ all good
+ Europe/Uzhgorod
+
+
+ Europe/London
+ all good
+ Europe/London
+
+
+ Europe/Volgograd
+ all good
+ Europe/Volgograd
+
+
+ Europe/San_Marino
+ all good
+ Europe/San_Marino
+
+
+ Europe/Dublin
+ all good
+ Europe/Dublin
+
+
+ Europe/Isle_of_Man
+ all good
+ Europe/Isle_of_Man
+
+
+ Europe/Rome
+ all good
+ Europe/Rome
+
+
+ Europe/Vilnius
+ all good
+ Europe/Vilnius
+
+
+ Europe/Skopje
+ all good
+ Europe/Skopje
+
+
+ Europe/Vaduz
+ all good
+ Europe/Vaduz
+
+
+ Europe/Zagreb
+ all good
+ Europe/Zagreb
+
+
+ Europe/Paris
+ all good
+ Europe/Paris
+
+
+ Europe/Luxembourg
+ all good
+ Europe/Luxembourg
+
+
+ Europe/Kaliningrad
+ all good
+ Europe/Kaliningrad
+
+
+ Europe/Nicosia
+ all good
+ Europe/Nicosia
+
+
+ Europe/Chisinau
+ all good
+ Europe/Chisinau
+
+
+ Europe/Malta
+ all good
+ Europe/Malta
+
+
+ Europe/Samara
+ all good
+ Europe/Samara
+
+
+ Atlantic/St_Helena
+ all good
+ Atlantic/St_Helena
+
+
+ Atlantic/Madeira
+ all good
+ Atlantic/Madeira
+
+
+ Atlantic/Cape_Verde
+ all good
+ Atlantic/Cape_Verde
+
+
+ Atlantic/Canary
+ all good
+ Atlantic/Canary
+
+
+ Atlantic/Azores
+ all good
+ Atlantic/Azores
+
+
+ Atlantic/Reykjavik
+ all good
+ Atlantic/Reykjavik
+
+
+ Atlantic/Faroe
+ all good
+ Atlantic/Faroe
+
+
+ Atlantic/Bermuda
+ all good
+ Atlantic/Bermuda
+
+
+ Pacific/Norfolk
+ all good
+ Pacific/Norfolk
+
+
+ Pacific/Funafuti
+ all good
+ Pacific/Funafuti
+
+
+ Pacific/Tahiti
+ all good
+ Pacific/Tahiti
+
+
+ Pacific/Majuro
+ all good
+ Pacific/Majuro
+
+
+ Pacific/Wake
+ all good
+ Pacific/Wake
+
+
+ Pacific/Pago_Pago
+ all good
+ Pacific/Pago_Pago
+
+
+ Pacific/Palau
+ all good
+ Pacific/Palau
+
+
+ Pacific/Marquesas
+ all good
+ Pacific/Marquesas
+
+
+ Pacific/Fakaofo
+ all good
+ Pacific/Fakaofo
+
+
+ Pacific/Efate
+ all good
+ Pacific/Efate
+
+
+ Pacific/Noumea
+ all good
+ Pacific/Noumea
+
+
+ Pacific/Guadalcanal
+ all good
+ Pacific/Guadalcanal
+
+
+ Pacific/Chatham
+ all good
+ Pacific/Chatham
+
+
+ Pacific/Gambier
+ all good
+ Pacific/Gambier
+
+
+ Pacific/Tarawa
+ all good
+ Pacific/Tarawa
+
+
+ Pacific/Pitcairn
+ all good
+ Pacific/Pitcairn
+
+
+ Pacific/Nauru
+ all good
+ Pacific/Nauru
+
+
+ Pacific/Johnston
+ all good
+ Pacific/Johnston
+
+
+ Pacific/Rarotonga
+ all good
+ Pacific/Rarotonga
+
+
+ Pacific/Pohnpei
+ all good
+ Pacific/Pohnpei
+
+
+ Pacific/Tongatapu
+ all good
+ Pacific/Tongatapu
+
+
+ Pacific/Fiji
+ all good
+ Pacific/Fiji
+
+
+ Pacific/Kwajalein
+ all good
+ Pacific/Kwajalein
+
+
+ Pacific/Guam
+ all good
+ Pacific/Guam
+
+
+ Pacific/Wallis
+ all good
+ Pacific/Wallis
+
+
+ Pacific/Kosrae
+ all good
+ Pacific/Kosrae
+
+
+ Pacific/Port_Moresby
+ all good
+ Pacific/Port_Moresby
+
+
+ Pacific/Niue
+ all good
+ Pacific/Niue
+
+
+ Pacific/Enderbury
+ all good
+ Pacific/Enderbury
+
+
+ Pacific/Kiritimati
+ all good
+ Pacific/Kiritimati
+
+
+ Pacific/Honolulu
+ all good
+ Pacific/Honolulu
+
+
+ Pacific/Midway
+ all good
+ Pacific/Midway
+
+
+ Pacific/Saipan
+ all good
+ Pacific/Saipan
+
+
+ Pacific/Chuuk
+ all good
+ Pacific/Chuuk
+
+
+ Pacific/Apia
+ all good
+ Pacific/Apia
+
+
+ Australia/Sydney
+ all good
+ Australia/Sydney
+
+
+ Australia/Hobart
+ all good
+ Australia/Hobart
+
+
+ Australia/Currie
+ all good
+ Australia/Currie
+
+
+ Australia/Adelaide
+ all good
+ Australia/Adelaide
+
+
+ Australia/Broken_Hill
+ all good
+ Australia/Broken_Hill
+
+
+ Australia/Eucla
+ all good
+ Australia/Eucla
+
+
+ Australia/Darwin
+ all good
+ Australia/Darwin
+
+
+ Australia/Brisbane
+ all good
+ Australia/Brisbane
+
+
+ Australia/Melbourne
+ all good
+ Australia/Melbourne
+
+
+ Australia/Perth
+ all good
+ Australia/Perth
+
+
+ Australia/Lindeman
+ all good
+ Australia/Lindeman
+
+
+ Australia/Lord_Howe
+ all good
+ Australia/Lord_Howe
+
+
+ Africa/Casablanca
+ all good
+ Africa/Casablanca
+
+
+ Africa/Ndjamena
+ all good
+ Africa/Ndjamena
+
+
+ Africa/Addis_Ababa
+ all good
+ Africa/Addis_Ababa
+
+
+ Africa/Windhoek
+ all good
+ Africa/Windhoek
+
+
+ Africa/Nouakchott
+ all good
+ Africa/Nouakchott
+
+
+ Africa/Tunis
+ all good
+ Africa/Tunis
+
+
+ Africa/Algiers
+ all good
+ Africa/Algiers
+
+
+ Africa/Johannesburg
+ all good
+ Africa/Johannesburg
+
+
+ Africa/Cairo
+ all good
+ Africa/Cairo
+
+
+ Africa/Bamako
+ all good
+ Africa/Bamako
+
+
+ Africa/Abidjan
+ all good
+ Africa/Abidjan
+
+
+ Africa/Mbabane
+ all good
+ Africa/Mbabane
+
+
+ Africa/Maseru
+ all good
+ Africa/Maseru
+
+
+ Africa/Mogadishu
+ all good
+ Africa/Mogadishu
+
+
+ Africa/Banjul
+ all good
+ Africa/Banjul
+
+
+ Africa/Freetown
+ all good
+ Africa/Freetown
+
+
+ Africa/Luanda
+ all good
+ Africa/Luanda
+
+
+ Africa/Dakar
+ all good
+ Africa/Dakar
+
+
+ Africa/Kampala
+ all good
+ Africa/Kampala
+
+
+ Africa/Dar_es_Salaam
+ all good
+ Africa/Dar_es_Salaam
+
+
+ Africa/Malabo
+ all good
+ Africa/Malabo
+
+
+ Africa/Kinshasa
+ all good
+ Africa/Kinshasa
+
+
+ Africa/Kigali
+ all good
+ Africa/Kigali
+
+
+ Africa/Bujumbura
+ all good
+ Africa/Bujumbura
+
+
+ Africa/Conakry
+ all good
+ Africa/Conakry
+
+
+ Africa/Blantyre
+ all good
+ Africa/Blantyre
+
+
+ Africa/Niamey
+ all good
+ Africa/Niamey
+
+
+ Africa/Djibouti
+ all good
+ Africa/Djibouti
+
+
+ Africa/Lagos
+ all good
+ Africa/Lagos
+
+
+ Africa/Brazzaville
+ all good
+ Africa/Brazzaville
+
+
+ Africa/Tripoli
+ all good
+ Africa/Tripoli
+
+
+ Africa/Lusaka
+ all good
+ Africa/Lusaka
+
+
+ Africa/Ouagadougou
+ all good
+ Africa/Ouagadougou
+
+
+ Africa/Bangui
+ all good
+ Africa/Bangui
+
+
+ Africa/El_Aaiun
+ all good
+ Africa/El_Aaiun
+
+
+ Africa/Lubumbashi
+ all good
+ Africa/Lubumbashi
+
+
+ Africa/Bissau
+ all good
+ Africa/Bissau
+
+
+ Africa/Libreville
+ all good
+ Africa/Libreville
+
+
+ Africa/Harare
+ all good
+ Africa/Harare
+
+
+ Africa/Porto-Novo
+ all good
+ Africa/Porto-Novo
+
+
+ Africa/Monrovia
+ all good
+ Africa/Monrovia
+
+
+ Africa/Juba
+ all good
+ Africa/Juba
+
+
+ Africa/Ceuta
+ all good
+ Africa/Ceuta
+
+
+ Africa/Nairobi
+ all good
+ Africa/Nairobi
+
+
+ Africa/Douala
+ all good
+ Africa/Douala
+
+
+ Africa/Khartoum
+ all good
+ Africa/Khartoum
+
+
+ Africa/Maputo
+ all good
+ Africa/Maputo
+
+
+ Africa/Accra
+ all good
+ Africa/Accra
+
+
+ Africa/Lome
+ all good
+ Africa/Lome
+
+
+ Africa/Sao_Tome
+ all good
+ Africa/Sao_Tome
+
+
+ Africa/Asmara
+ all good
+ Africa/Asmara
+
+
+ Africa/Gaborone
+ all good
+ Africa/Gaborone
+
+
+ Arctic/Longyearbyen
+ all good
+ Arctic/Longyearbyen
+
+
+ Antarctica/Rothera
+ all good
+ Antarctica/Rothera
+
+
+ Antarctica/South_Pole
+ all good
+ Antarctica/South_Pole
+
+
+ Antarctica/Mawson
+ all good
+ Antarctica/Mawson
+
+
+ Antarctica/Casey
+ all good
+ Antarctica/Casey
+
+
+ Antarctica/Palmer
+ all good
+ Antarctica/Palmer
+
+
+ Antarctica/Vostok
+ all good
+ Antarctica/Vostok
+
+
+ Antarctica/Macquarie
+ all good
+ Antarctica/Macquarie
+
+
+ Antarctica/Syowa
+ all good
+ Antarctica/Syowa
+
+
+ Antarctica/McMurdo
+ all good
+ Antarctica/McMurdo
+
+
+ Antarctica/DumontDUrville
+ all good
+ Antarctica/DumontDUrville
+
+
+ Antarctica/Davis
+ all good
+ Antarctica/Davis
+
+
+ America/Chihuahua
+ all good
+ America/Chihuahua
+
+
+ America/Cambridge_Bay
+ all good
+ America/Cambridge_Bay
+
+
+ America/St_Johns
+ all good
+ America/St_Johns
+
+
+ America/Cancun
+ all good
+ America/Cancun
+
+
+ America/Toronto
+ all good
+ America/Toronto
+
+
+ America/Chicago
+ all good
+ America/Chicago
+
+
+ America/Metlakatla
+ all good
+ America/Metlakatla
+
+
+ America/Winnipeg
+ all good
+ America/Winnipeg
+
+
+ America/North_Dakota/Beulah
+ all good
+ America/North_Dakota/Beulah
+
+
+ America/North_Dakota/Center
+ all good
+ America/North_Dakota/Center
+
+
+ America/North_Dakota/New_Salem
+ all good
+ America/North_Dakota/New_Salem
+
+
+ America/Barbados
+ all good
+ America/Barbados
+
+
+ America/Moncton
+ all good
+ America/Moncton
+
+
+ America/Mazatlan
+ all good
+ America/Mazatlan
+
+
+ America/Anguilla
+ all good
+ America/Anguilla
+
+
+ America/Tortola
+ all good
+ America/Tortola
+
+
+ America/Juneau
+ all good
+ America/Juneau
+
+
+ America/St_Vincent
+ all good
+ America/St_Vincent
+
+
+ America/Inuvik
+ all good
+ America/Inuvik
+
+
+ America/Blanc-Sablon
+ all good
+ America/Blanc-Sablon
+
+
+ America/Iqaluit
+ all good
+ America/Iqaluit
+
+
+ America/Swift_Current
+ all good
+ America/Swift_Current
+
+
+ America/Rainy_River
+ all good
+ America/Rainy_River
+
+
+ America/Scoresbysund
+ all good
+ America/Scoresbysund
+
+
+ America/Costa_Rica
+ all good
+ America/Costa_Rica
+
+
+ America/Dominica
+ all good
+ America/Dominica
+
+
+ America/Tegucigalpa
+ all good
+ America/Tegucigalpa
+
+
+ America/El_Salvador
+ all good
+ America/El_Salvador
+
+
+ America/Grand_Turk
+ all good
+ America/Grand_Turk
+
+
+ America/Nome
+ all good
+ America/Nome
+
+
+ America/Hermosillo
+ all good
+ America/Hermosillo
+
+
+ America/Ojinaga
+ all good
+ America/Ojinaga
+
+
+ America/Tijuana
+ all good
+ America/Tijuana
+
+
+ America/Jamaica
+ all good
+ America/Jamaica
+
+
+ America/Mexico_City
+ all good
+ America/Mexico_City
+
+
+ America/Guatemala
+ all good
+ America/Guatemala
+
+
+ America/Santa_Isabel
+ all good
+ America/Santa_Isabel
+
+
+ America/Nassau
+ all good
+ America/Nassau
+
+
+ America/Shiprock
+ all good
+ America/Shiprock
+
+
+ America/St_Lucia
+ all good
+ America/St_Lucia
+
+
+ America/Marigot
+ all good
+ America/Marigot
+
+
+ America/Grenada
+ all good
+ America/Grenada
+
+
+ America/Port-au-Prince
+ all good
+ America/Port-au-Prince
+
+
+ America/St_Kitts
+ all good
+ America/St_Kitts
+
+
+ America/Atikokan
+ all good
+ America/Atikokan
+
+
+ America/Miquelon
+ all good
+ America/Miquelon
+
+
+ America/Anchorage
+ all good
+ America/Anchorage
+
+
+ America/Managua
+ all good
+ America/Managua
+
+
+ America/Antigua
+ all good
+ America/Antigua
+
+
+ America/Godthab
+ all good
+ America/Godthab
+
+
+ America/Phoenix
+ all good
+ America/Phoenix
+
+
+ America/Cayman
+ all good
+ America/Cayman
+
+
+ America/Sitka
+ all good
+ America/Sitka
+
+
+ America/Thule
+ all good
+ America/Thule
+
+
+ America/Montserrat
+ all good
+ America/Montserrat
+
+
+ America/Martinique
+ all good
+ America/Martinique
+
+
+ America/Puerto_Rico
+ all good
+ America/Puerto_Rico
+
+
+ America/Adak
+ all good
+ America/Adak
+
+
+ America/Dawson
+ all good
+ America/Dawson
+
+
+ America/Monterrey
+ all good
+ America/Monterrey
+
+
+ America/Whitehorse
+ all good
+ America/Whitehorse
+
+
+ America/Goose_Bay
+ all good
+ America/Goose_Bay
+
+
+ America/Guadeloupe
+ all good
+ America/Guadeloupe
+
+
+ America/Dawson_Creek
+ all good
+ America/Dawson_Creek
+
+
+ America/Resolute
+ all good
+ America/Resolute
+
+
+ America/Belize
+ all good
+ America/Belize
+
+
+ America/Denver
+ all good
+ America/Denver
+
+
+ America/Merida
+ all good
+ America/Merida
+
+
+ America/Los_Angeles
+ all good
+ America/Los_Angeles
+
+
+ America/Halifax
+ all good
+ America/Halifax
+
+
+ America/Regina
+ all good
+ America/Regina
+
+
+ America/St_Barthelemy
+ all good
+ America/St_Barthelemy
+
+
+ America/Bahia_Banderas
+ all good
+ America/Bahia_Banderas
+
+
+ America/Indiana/Winamac
+ all good
+ America/Indiana/Winamac
+
+
+ America/Indiana/Tell_City
+ all good
+ America/Indiana/Tell_City
+
+
+ America/Indiana/Vincennes
+ all good
+ America/Indiana/Vincennes
+
+
+ America/Indiana/Indianapolis
+ all good
+ America/Indiana/Indianapolis
+
+
+ Indian/Mauritius
+ all good
+ Indian/Mauritius
+
+
+ America/Indiana/Petersburg
+ all good
+ America/Indiana/Petersburg
+
+
+ America/Indiana/Knox
+ all good
+ America/Indiana/Knox
+
+
+ America/Indiana/Marengo
+ all good
+ America/Indiana/Marengo
+
+
+ America/Indiana/Vevay
+ all good
+ America/Indiana/Vevay
+
+
+ America/Kentucky/Louisville
+ all good
+ America/Kentucky/Louisville
+
+
+ America/Kentucky/Monticello
+ all good
+ America/Kentucky/Monticello
+
+
+ America/Rankin_Inlet
+ all good
+ America/Rankin_Inlet
+
+
+ America/Glace_Bay
+ all good
+ America/Glace_Bay
+
+
+ America/Yakutat
+ all good
+ America/Yakutat
+
+
+ America/Boise
+ all good
+ America/Boise
+
+
+ America/Edmonton
+ all good
+ America/Edmonton
+
+
+ America/Yellowknife
+ all good
+ America/Yellowknife
+
+
+ America/St_Thomas
+ all good
+ America/St_Thomas
+
+
+ Indian/Mahe
+ all good
+ Indian/Mahe
+
+
+ America/Montreal
+ all good
+ America/Montreal
+
+
+ America/Pangnirtung
+ all good
+ America/Pangnirtung
+
+
+ America/Detroit
+ all good
+ America/Detroit
+
+
+ America/Vancouver
+ all good
+ America/Vancouver
+
+
+ America/Matamoros
+ all good
+ America/Matamoros
+
+
+ America/Nipigon
+ all good
+ America/Nipigon
+
+
+ America/Havana
+ all good
+ America/Havana
+
+
+ America/Menominee
+ all good
+ America/Menominee
+
+
+ America/Thunder_Bay
+ all good
+ America/Thunder_Bay
+
+
+ America/Santo_Domingo
+ all good
+ America/Santo_Domingo
+
+
+ America/Danmarkshavn
+ all good
+ America/Danmarkshavn
+
+
+ America/Panama
+ all good
+ America/Panama
+
+
+ Indian/Chagos
+ all good
+ Indian/Chagos
+
+
+ Indian/Comoro
+ all good
+ Indian/Comoro
+
+
+ Indian/Mayotte
+ all good
+ Indian/Mayotte
+
+
+ Indian/Kerguelen
+ all good
+ Indian/Kerguelen
+
+
+ Indian/Antananarivo
+ all good
+ Indian/Antananarivo
+
+
+ Indian/Maldives
+ all good
+ Indian/Maldives
+
+
+ Indian/Reunion
+ all good
+ Indian/Reunion
+
+
+ Indian/Christmas
+ all good
+ Indian/Christmas
+
+
+ Indian/Cocos
+ all good
+ Indian/Cocos
+
+
+ Asia/Seoul
+ all good
+ Asia/Seoul
+
+
+ Asia/Sakhalin
+ all good
+ Asia/Sakhalin
+
+
+ Asia/Tehran
+ all good
+ Asia/Tehran
+
+
+ Asia/Aden
+ all good
+ Asia/Aden
+
+
+ Asia/Macau
+ all good
+ Asia/Macau
+
+
+ Asia/Bishkek
+ all good
+ Asia/Bishkek
+
+
+ Asia/Kabul
+ all good
+ Asia/Kabul
+
+
+ Asia/Hovd
+ all good
+ Asia/Hovd
+
+
+ Asia/Anadyr
+ all good
+ Asia/Anadyr
+
+
+ Asia/Kuwait
+ all good
+ Asia/Kuwait
+
+
+ Asia/Omsk
+ all good
+ Asia/Omsk
+
+
+ Asia/Manila
+ all good
+ Asia/Manila
+
+
+ Asia/Makassar
+ all good
+ Asia/Makassar
+
+
+ Asia/Vientiane
+ all good
+ Asia/Vientiane
+
+
+ Asia/Oral
+ all good
+ Asia/Oral
+
+
+ Asia/Kashgar
+ all good
+ Asia/Kashgar
+
+
+ Asia/Yekaterinburg
+ all good
+ Asia/Yekaterinburg
+
+
+ Asia/Kamchatka
+ all good
+ Asia/Kamchatka
+
+
+ Asia/Harbin
+ all good
+ Asia/Harbin
+
+
+ Asia/Aqtobe
+ all good
+ Asia/Aqtobe
+
+
+ Asia/Chongqing
+ all good
+ Asia/Chongqing
+
+
+ Asia/Samarkand
+ all good
+ Asia/Samarkand
+
+
+ Asia/Kuala_Lumpur
+ all good
+ Asia/Kuala_Lumpur
+
+
+ Asia/Taipei
+ all good
+ Asia/Taipei
+
+
+ Asia/Shanghai
+ all good
+ Asia/Shanghai
+
+
+ Asia/Singapore
+ all good
+ Asia/Singapore
+
+
+ Asia/Kuching
+ all good
+ Asia/Kuching
+
+
+ Asia/Tbilisi
+ all good
+ Asia/Tbilisi
+
+
+ Asia/Dhaka
+ all good
+ Asia/Dhaka
+
+
+ Asia/Krasnoyarsk
+ all good
+ Asia/Krasnoyarsk
+
+
+ Asia/Istanbul
+ all good
+ Asia/Istanbul
+
+
+ Asia/Tashkent
+ all good
+ Asia/Tashkent
+
+
+ Asia/Jerusalem
+ all good
+ Asia/Jerusalem
+
+
+ Asia/Ulaanbaatar
+ all good
+ Asia/Ulaanbaatar
+
+
+ Asia/Beirut
+ all good
+ Asia/Beirut
+
+
+ Asia/Jayapura
+ all good
+ Asia/Jayapura
+
+
+ Asia/Tokyo
+ all good
+ Asia/Tokyo
+
+
+ Asia/Bangkok
+ all good
+ Asia/Bangkok
+
+
+ Asia/Kolkata
+ all good
+ Asia/Kolkata
+
+
+ Asia/Baku
+ all good
+ Asia/Baku
+
+
+ Asia/Karachi
+ all good
+ Asia/Karachi
+
+
+ Asia/Muscat
+ all good
+ Asia/Muscat
+
+
+ Asia/Kathmandu
+ all good
+ Asia/Kathmandu
+
+
+ Asia/Gaza
+ all good
+ Asia/Gaza
+
+
+ Asia/Yerevan
+ all good
+ Asia/Yerevan
+
+
+ Asia/Colombo
+ all good
+ Asia/Colombo
+
+
+ Asia/Phnom_Penh
+ all good
+ Asia/Phnom_Penh
+
+
+ Asia/Vladivostok
+ all good
+ Asia/Vladivostok
+
+
+ Asia/Almaty
+ all good
+ Asia/Almaty
+
+
+ Asia/Riyadh
+ all good
+ Asia/Riyadh
+
+
+ Asia/Thimphu
+ all good
+ Asia/Thimphu
+
+
+ Asia/Dubai
+ all good
+ Asia/Dubai
+
+
+ Asia/Qyzylorda
+ all good
+ Asia/Qyzylorda
+
+
+ Asia/Aqtau
+ all good
+ Asia/Aqtau
+
+
+ Asia/Hong_Kong
+ all good
+ Asia/Hong_Kong
+
+
+ Asia/Novosibirsk
+ all good
+ Asia/Novosibirsk
+
+
+ Asia/Dushanbe
+ all good
+ Asia/Dushanbe
+
+
+ Asia/Ashgabat
+ all good
+ Asia/Ashgabat
+
+
+ Asia/Brunei
+ all good
+ Asia/Brunei
+
+
+ Asia/Novokuznetsk
+ all good
+ Asia/Novokuznetsk
+
+
+ Asia/Pyongyang
+ all good
+ Asia/Pyongyang
+
+
+ Asia/Magadan
+ all good
+ Asia/Magadan
+
+
+ Asia/Bahrain
+ all good
+ Asia/Bahrain
+
+
+ Asia/Damascus
+ all good
+ Asia/Damascus
+
+
+ Asia/Qatar
+ all good
+ Asia/Qatar
+
+
+ Asia/Choibalsan
+ all good
+ Asia/Choibalsan
+
+
+ Asia/Ho_Chi_Minh
+ all good
+ Asia/Ho_Chi_Minh
+
+
+ Asia/Yakutsk
+ all good
+ Asia/Yakutsk
+
+
+ Asia/Irkutsk
+ all good
+ Asia/Irkutsk
+
+
+ Asia/Dili
+ all good
+ Asia/Dili
+
+
+ Asia/Urumqi
+ all good
+ Asia/Urumqi
+
+
+ Asia/Nicosia
+ all good
+ Asia/Nicosia
+
+
+ Asia/Pontianak
+ all good
+ Asia/Pontianak
+
+
+ Asia/Amman
+ all good
+ Asia/Amman
+
+
+ Asia/Jakarta
+ all good
+ Asia/Jakarta
+
+
+ Asia/Baghdad
+ all good
+ Asia/Baghdad
+
+
+ Asia/Rangoon
+ all good
+ Asia/Rangoon
+
+
diff --git a/testing/tests/timezone/5021-list.test b/testing/tests/timezone/5021-list.test
new file mode 100644
index 00000000..8594e61c
--- /dev/null
+++ b/testing/tests/timezone/5021-list.test
@@ -0,0 +1,9 @@
+#
+# List timezone server timezones
+#
+TYPE=GET
+URL=http://regression.host/tz.php?action=list
+HEAD
+
+REPLACE=/dtstamp>[0-9TZ]{16}/dtstamp>all good/
+REPLACE=/last-modified>[0-9TZ]{16}/last-modified>all good/
diff --git a/zonedb/update-tzdata.sh b/zonedb/update-tzdata.sh
new file mode 100755
index 00000000..978f37ea
--- /dev/null
+++ b/zonedb/update-tzdata.sh
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+wget --continue 'ftp://elsie.nci.nih.gov/pub/tz*.tar.gz'
+
+TZCODEFILE="`ls -t tzcode*.tar.gz|tail -n 1`"
+TZDATAFILE="`ls -t tzdata*.tar.gz|tail -n 1`"
+
+(
+ mkdir tzcode && cd tzcode && tar -xfz ../$TZCODEFILE
+)
+
+(
+ mkdir tzdata && cd tzdata && tar -xfz ../$TZDATAFILE
+)
+
+vzic --olson-dir tzdata --output-dir vtimezones