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

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

index 73e293f927495917be01c98509901a94d67f294d..527c370b9014b57d161d5b0e50b9db75345fc051 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];
@@ -163,10 +181,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);
@@ -215,7 +256,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]);
                        return 1;
                }
 
@@ -249,9 +290,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 ed7ec9bc9d18e270cb7926100926d4798875177a..621ceab118c47bf325b9fba886dca209c821185f 100644 (file)
@@ -371,6 +371,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)
@@ -459,6 +468,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)
 
@@ -503,6 +513,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}
@@ -1955,6 +1966,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
 
@@ -2157,6 +2169,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;
@@ -3531,6 +3544,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;
@@ -3909,8 +3947,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;
        }
 
@@ -3921,7 +3967,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_ascii_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_ascii_string(return_value, table[i].id, 1);
                }
        };
index 5c09b50c176d0c114bb1e66d016258f6c7fb96c8..025adaaf2d1047eae448dcc2e76433b090c3e365 100644 (file)
@@ -77,6 +77,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);