]> granicus.if.org Git - php/commitdiff
- MFH: Added support for selectively listing timezone identifiers by country
authorDerick Rethans <derick@php.net>
Fri, 18 Jul 2008 14:33:53 +0000 (14:33 +0000)
committerDerick Rethans <derick@php.net>
Fri, 18 Jul 2008 14:33:53 +0000 (14:33 +0000)
  code through timezone_identifiers_list() / DateTimezone::listIdentifiers().
- MFH: Added timezone_location_get() / DateTimezone::getLocation() for
  retrieving location information from timezones.

NEWS
ext/date/lib/parse_tz.c
ext/date/lib/timelib_structs.h
ext/date/php_date.c
ext/date/php_date.h

diff --git a/NEWS b/NEWS
index c9586e7d80be3080a950b174b145e51ca2db4913..8d65b3baa168d1ce66799beeeebef1644045f7ea 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -135,8 +135,11 @@ PHP                                                                        NEWS
     . date_parse_from_format()
   . support for abbreviation and offset based timezone specifiers for
     DateTime::getOffset() and DateTime::getName().
-  . support for selectively listing timezone identifiers through
-    timezone_identifiers_list() / DateTimezone::listIdentifiers().
+  . support for selectively listing timezone identifiers by continent or
+    country code through timezone_identifiers_list() /
+    DateTimezone::listIdentifiers().
+  . timezone_location_get() / DateTimezone::getLocation() for retrieving
+    location information from timezones.
   . date_timestamp_set() / DateTime::setTimestamp() to set a Unix timestamp
     without invoking the date parser. (Scott)
   . date_timestamp_get() / DateTime::getTimestamp() to retrieve the Unix
index f7999d111ec09b4572a081490376156d35187d80..81d3481a02aac290f9976216efd09af7443f9364 100644 (file)
 #define timelib_conv_int(l) ((l & 0x000000ff) << 24) + ((l & 0x0000ff00) << 8) + ((l & 0x00ff0000) >> 8) + ((l & 0xff000000) >> 24)
 #endif
 
+static void read_preamble(char **tzf, timelib_tzinfo *tz)
+{
+       /* skip ID */
+       *tzf += 4;
+       
+       /* read BC flag */
+       tz->bc = (**tzf == '\1');
+       *tzf += 1;
+
+       /* read country code */
+       memcpy(tz->location.country_code, *tzf, 2);
+       tz->location.country_code[2] = '\0';
+       *tzf += 2;
+
+       /* skip read of preamble */
+       *tzf += 13;
+}
+
 static void read_header(char **tzf, timelib_tzinfo *tz)
 {
        uint32_t buffer[6];
@@ -167,10 +185,33 @@ static void read_types(char **tzf, timelib_tzinfo *tz)
        free(buffer);
 }
 
+static void read_location(char **tzf, timelib_tzinfo *tz)
+{
+       uint32_t buffer[3];
+       uint32_t comments_len;
+
+       memcpy(&buffer, *tzf, sizeof(buffer));
+       tz->location.latitude = timelib_conv_int(buffer[0]);
+       tz->location.latitude = (tz->location.latitude / 100000) - 90;
+       tz->location.longitude = timelib_conv_int(buffer[1]);
+       tz->location.longitude = (tz->location.longitude / 100000) - 180;
+       comments_len = timelib_conv_int(buffer[2]);
+       *tzf += sizeof(buffer);
+
+       tz->location.comments = malloc(comments_len + 1);
+       memcpy(tz->location.comments, *tzf, comments_len);
+       tz->location.comments[comments_len] = '\0';
+       *tzf += comments_len;
+}
+
 void timelib_dump_tzinfo(timelib_tzinfo *tz)
 {
        uint32_t i;
 
+       printf("Country Code:      %s\n", tz->location.country_code);
+       printf("Geo Location:      %f,%f\n", tz->location.latitude, tz->location.longitude);
+       printf("Comments:\n%s\n",          tz->location.comments);
+       printf("BC:                %s\n",  tz->bc ? "" : "yes");
        printf("UTC/Local count:   %lu\n", (unsigned long) tz->ttisgmtcnt);
        printf("Std/Wall count:    %lu\n", (unsigned long) tz->ttisstdcnt);
        printf("Leap.sec. count:   %lu\n", (unsigned long) tz->leapcnt);
@@ -228,7 +269,7 @@ static int seek_to_tz_position(const unsigned char **tzf, char *timezone, const
                } else if (cmp > 0) {
                        left = mid + 1;
                } else { /* (cmp == 0) */
-                       (*tzf) = &(tzdb->data[tzdb->index[mid].pos + 20]);
+                       (*tzf) = &(tzdb->data[tzdb->index[mid].pos]);
 #ifdef HAVE_SETLOCALE
                        setlocale(LC_CTYPE, cur_locale);
                        if (cur_locale) free(cur_locale);
@@ -270,9 +311,11 @@ timelib_tzinfo *timelib_parse_tzfile(char *timezone, const timelib_tzdb *tzdb)
        if (seek_to_tz_position(&tzf, timezone, tzdb)) {
                tmp = timelib_tzinfo_ctor(timezone);
 
+               read_preamble((char**) &tzf, tmp);
                read_header((char**) &tzf, tmp);
                read_transistions((char**) &tzf, tmp);
                read_types((char**) &tzf, tmp);
+               read_location((char**) &tzf, tmp);
        } else {
                tmp = NULL;
        }
index 63b6c91b94dc222f57c8e2b48ebf828dc520a87f..89415fe31c8623427ca82bccf5c2b9cd1667de3b 100644 (file)
@@ -97,6 +97,14 @@ typedef struct tlinfo
        int32_t  offset;
 } tlinfo;
 
+typedef struct tlocinfo
+{
+       char country_code[3];
+       double latitude;
+       double longitude;
+       char *comments;
+} tlocinfo;
+
 typedef struct timelib_tzinfo
 {
        char    *name;
@@ -114,6 +122,8 @@ typedef struct timelib_tzinfo
        char    *timezone_abbr;
 
        tlinfo  *leap_times;
+       unsigned char bc;
+       tlocinfo location;
 } timelib_tzinfo;
 
 typedef struct timelib_special {
index 19cb877bb4e97dee7f22a75026212d882e8d0123..113e559232e2f86dea1f7e9b740a48430ccb7cdc 100644 (file)
@@ -370,6 +370,15 @@ ZEND_BEGIN_ARG_INFO(arginfo_timezone_method_transitions_get, 0)
        ZEND_ARG_INFO(0, timestamp_end)
 ZEND_END_ARG_INFO()
 
+static
+ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_location_get, 0, 0, 1)
+       ZEND_ARG_INFO(0, object)
+ZEND_END_ARG_INFO()
+
+static
+ZEND_BEGIN_ARG_INFO(arginfo_timezone_method_location_get, 0)
+ZEND_END_ARG_INFO()
+
 static
 ZEND_BEGIN_ARG_INFO_EX(arginfo_timezone_identifiers_list, 0, 0, 0)
        ZEND_ARG_INFO(0, what)
@@ -451,6 +460,7 @@ const zend_function_entry date_functions[] = {
        PHP_FE(timezone_name_from_abbr, arginfo_timezone_name_from_abbr)
        PHP_FE(timezone_offset_get, arginfo_timezone_offset_get)
        PHP_FE(timezone_transitions_get, arginfo_timezone_transitions_get)
+       PHP_FE(timezone_location_get, arginfo_timezone_location_get)
        PHP_FE(timezone_identifiers_list, arginfo_timezone_identifiers_list)
        PHP_FE(timezone_abbreviations_list, arginfo_timezone_abbreviations_list)
 
@@ -495,6 +505,7 @@ const zend_function_entry date_funcs_timezone[] = {
        PHP_ME_MAPPING(getName,           timezone_name_get,           arginfo_timezone_method_name_get, 0)
        PHP_ME_MAPPING(getOffset,         timezone_offset_get,         arginfo_timezone_method_offset_get, 0)
        PHP_ME_MAPPING(getTransitions,    timezone_transitions_get,    arginfo_timezone_method_transitions_get, 0)
+       PHP_ME_MAPPING(getLocation,       timezone_location_get,       arginfo_timezone_method_location_get, 0)
        PHP_ME_MAPPING(listAbbreviations, timezone_abbreviations_list, arginfo_timezone_abbreviations_list, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
        PHP_ME_MAPPING(listIdentifiers,   timezone_identifiers_list,   arginfo_timezone_identifiers_list, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
        {NULL, NULL, NULL}
@@ -1823,6 +1834,7 @@ PHP_FUNCTION(getdate)
 #define PHP_DATE_TIMEZONE_GROUP_UTC        0x0400
 #define PHP_DATE_TIMEZONE_GROUP_ALL        0x07FF
 #define PHP_DATE_TIMEZONE_GROUP_ALL_W_BC   0x0FFF
+#define PHP_DATE_TIMEZONE_PER_COUNTRY      0x1000
 
 #define PHP_DATE_PERIOD_EXCLUDE_START_DATE 0x0001
 
@@ -2025,6 +2037,7 @@ static void date_register_classes(TSRMLS_D)
        REGISTER_TIMEZONE_CLASS_CONST_STRING("UTC",         PHP_DATE_TIMEZONE_GROUP_UTC);
        REGISTER_TIMEZONE_CLASS_CONST_STRING("ALL",         PHP_DATE_TIMEZONE_GROUP_ALL);
        REGISTER_TIMEZONE_CLASS_CONST_STRING("ALL_WITH_BC", PHP_DATE_TIMEZONE_GROUP_ALL_W_BC);
+       REGISTER_TIMEZONE_CLASS_CONST_STRING("PER_COUNTRY", PHP_DATE_TIMEZONE_PER_COUNTRY);
 
        INIT_CLASS_ENTRY(ce_interval, "DateInterval", date_funcs_interval);
        ce_interval.create_object = date_object_new_interval;
@@ -3356,6 +3369,31 @@ PHP_FUNCTION(timezone_transitions_get)
 }
 /* }}} */
 
+/* {{{ proto array timezone_location_get()
+   Returns location information for a timezone, including country code, latitude/longitude and comments
+*/
+PHP_FUNCTION(timezone_location_get)
+{
+       zval                *object;
+       php_timezone_obj    *tzobj;
+
+       if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &object, date_ce_timezone) == FAILURE) {
+               RETURN_FALSE;
+       }
+       tzobj = (php_timezone_obj *) zend_object_store_get_object(object TSRMLS_CC);
+       DATE_CHECK_INITIALIZED(tzobj->initialized, DateTimeZone);
+       if (tzobj->type != TIMELIB_ZONETYPE_ID) {
+               RETURN_FALSE;
+       }
+
+       array_init(return_value);
+       add_assoc_string(return_value, "country_code", tzobj->tzi.tz->location.country_code, 1);
+       add_assoc_double(return_value, "latitude", tzobj->tzi.tz->location.latitude);
+       add_assoc_double(return_value, "longitude", tzobj->tzi.tz->location.longitude);
+       add_assoc_string(return_value, "comments", tzobj->tzi.tz->location.comments, 1);
+}
+/* }}} */
+
 static int date_interval_initialize(timelib_rel_time **rt, /*const*/ char *format, int format_length TSRMLS_DC)
 {
        timelib_time     *b = NULL, *e = NULL;
@@ -3734,8 +3772,16 @@ PHP_FUNCTION(timezone_identifiers_list)
        const timelib_tzdb_index_entry *table;
        int                             i, item_count;
        long                            what = PHP_DATE_TIMEZONE_GROUP_ALL;
+       char                           *option;
+       int                             option_len = 0;
 
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &what) == FAILURE) {
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ls", &what, &option, &option_len) == FAILURE) {
+               RETURN_FALSE;
+       }
+
+       /* Extra validation */
+       if (what == PHP_DATE_TIMEZONE_PER_COUNTRY && option_len != 2) {
+               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "A two-letter ISO 639-2 compatible country code is expected");
                RETURN_FALSE;
        }
 
@@ -3746,7 +3792,11 @@ PHP_FUNCTION(timezone_identifiers_list)
        array_init(return_value);
 
        for (i = 0; i < item_count; ++i) {
-               if (what == PHP_DATE_TIMEZONE_GROUP_ALL_W_BC || check_id_allowed(table[i].id, what)) {
+               if (what == PHP_DATE_TIMEZONE_PER_COUNTRY) {
+                       if (tzdb->data[table[i].pos + 5] == option[0] && tzdb->data[table[i].pos + 6] == option[1]) {
+                               add_next_index_string(return_value, table[i].id, 1);
+                       }
+               } else if (what == PHP_DATE_TIMEZONE_GROUP_ALL_W_BC || (check_id_allowed(table[i].id, what) && (tzdb->data[table[i].pos + 4] == '\1'))) {
                        add_next_index_string(return_value, table[i].id, 1);
                }
        };
index 30d0e4350ed466263acd2018f9002028bc21dc1e..9c063bd62a33ef89059540e70f58b2e6134b4c92 100644 (file)
@@ -76,6 +76,7 @@ PHP_FUNCTION(timezone_name_get);
 PHP_FUNCTION(timezone_name_from_abbr);
 PHP_FUNCTION(timezone_offset_get);
 PHP_FUNCTION(timezone_transitions_get);
+PHP_FUNCTION(timezone_location_get);
 PHP_FUNCTION(timezone_identifiers_list);
 PHP_FUNCTION(timezone_abbreviations_list);