diff options
| author | Gustavo André dos Santos Lopes <cataphract@php.net> | 2012-07-22 03:54:03 +0200 |
|---|---|---|
| committer | Gustavo André dos Santos Lopes <cataphract@php.net> | 2012-07-22 04:22:23 +0200 |
| commit | 2f0775b999e7859275c614a3d2d8edd1506e0d68 (patch) | |
| tree | 95b8682fb7fbf8229f3ce17064d14a7842efd812 /ext/intl/common/common_date.cpp | |
| parent | 46629e35ffadae77114088c59faf301328159d83 (diff) | |
| download | php-git-2f0775b999e7859275c614a3d2d8edd1506e0d68.tar.gz | |
Added IntlDateFormatter::formatObject(). Refactor
To better support IntlCalendar, added this function:
string IntlDateFormatter::formatObject(IntlCalendar|DateTime $obj [,
array|int|string $format = null [, string $locale = null).
$format is either of the constants IntlDateFormatter::FULL, etc., in
which case this format applies to both the date and the time, an array
in the form array($dateFormat, $timeFormat), or a string with the
SimpleDateFormat pattern.
This uses both the Calendar type and the timezone of the passed object
to configure the formatter (a GregorianCalendar is forced for
DateTime).
Some stuff was moved around and slighlt modified to allow for more code
reuse.
Diffstat (limited to 'ext/intl/common/common_date.cpp')
| -rw-r--r-- | ext/intl/common/common_date.cpp | 206 |
1 files changed, 184 insertions, 22 deletions
diff --git a/ext/intl/common/common_date.cpp b/ext/intl/common/common_date.cpp index 812a196ed0..ee998818d9 100644 --- a/ext/intl/common/common_date.cpp +++ b/ext/intl/common/common_date.cpp @@ -25,13 +25,162 @@ extern "C" { #include <ext/date/php_date.h> } -U_CFUNC double intl_zval_to_millis(zval *z, UErrorCode *status TSRMLS_DC) +#ifndef INFINITY +#define INFINITY (DBL_MAX+DBL_MAX) +#endif + +#ifndef NAN +#define NAN (INFINITY-INFINITY) +#endif + +/* {{{ timezone_convert_datetimezone + * The timezone in DateTime and DateTimeZone is not unified. */ +U_CFUNC TimeZone *timezone_convert_datetimezone(int type, + void *object, + int is_datetime, + intl_error *outside_error, + const char *func TSRMLS_DC) { - double rv = NAN; - long lv; - int type; + char *id = NULL, + offset_id[] = "GMT+00:00"; + int id_len = 0; + char *message; + TimeZone *timeZone; + + switch (type) { + case TIMELIB_ZONETYPE_ID: + id = is_datetime + ? ((php_date_obj*)object)->time->tz_info->name + : ((php_timezone_obj*)object)->tzi.tz->name; + id_len = strlen(id); + break; + case TIMELIB_ZONETYPE_OFFSET: { + int offset_mins = is_datetime + ? -((php_date_obj*)object)->time->z + : -(int)((php_timezone_obj*)object)->tzi.utc_offset, + hours = offset_mins / 60, + minutes = offset_mins - hours * 60; + minutes *= minutes > 0 ? 1 : -1; + + if (offset_mins <= -24 * 60 || offset_mins >= 24 * 60) { + spprintf(&message, 0, "%s: object has an time zone offset " + "that's too large", func); + intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + efree(message); + return NULL; + } - if (U_FAILURE(*status)) { + id = offset_id; + id_len = slprintf(id, sizeof(offset_id), "GMT%+03d:%02d", + hours, minutes); + break; + } + case TIMELIB_ZONETYPE_ABBR: + id = is_datetime + ? ((php_date_obj*)object)->time->tz_abbr + : ((php_timezone_obj*)object)->tzi.z.abbr; + id_len = strlen(id); + break; + } + + UnicodeString s = UnicodeString(id, id_len, US_INV); + timeZone = TimeZone::createTimeZone(s); +#if U_ICU_VERSION_MAJOR_NUM >= 49 + if (*timeZone == TimeZone::getUnknown()) { +#else + UnicodeString resultingId; + timeZone->getID(resultingId); + if (resultingId == UnicodeString("Etc/Unknown", -1, US_INV) + || resultingId == UnicodeString("GMT", -1, US_INV)) { +#endif + spprintf(&message, 0, "%s: time zone id '%s' " + "extracted from ext/date DateTimeZone not recognized", func, id); + intl_errors_set(outside_error, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + efree(message); + delete timeZone; + return NULL; + } + return timeZone; +} +/* }}} */ + +U_CFUNC int intl_datetime_decompose(zval *z, double *millis, TimeZone **tz, + intl_error *err, const char *func TSRMLS_DC) +{ + zval retval; + zval *zfuncname; + char *message; + + if (err && U_FAILURE(err->code)) { + return FAILURE; + } + + if (millis) { + *millis = NAN; + } + if (tz) { + *tz = NULL; + } + + if (millis) { + INIT_ZVAL(retval); + MAKE_STD_ZVAL(zfuncname); + ZVAL_STRING(zfuncname, "getTimestamp", 1); + if (call_user_function(NULL, &(z), zfuncname, &retval, 0, NULL TSRMLS_CC) + != SUCCESS || Z_TYPE(retval) != IS_LONG) { + spprintf(&message, 0, "%s: error calling ::getTimeStamp() on the " + "object", func); + intl_errors_set(err, U_INTERNAL_PROGRAM_ERROR, + message, 1 TSRMLS_CC); + efree(message); + zval_ptr_dtor(&zfuncname); + return FAILURE; + } + + *millis = U_MILLIS_PER_SECOND * (double)Z_LVAL(retval); + zval_ptr_dtor(&zfuncname); + } + + if (tz) { + php_date_obj *datetime; + datetime = (php_date_obj*)zend_object_store_get_object(z TSRMLS_CC); + if (!datetime->time) { + spprintf(&message, 0, "%s: the DateTime object is not properly " + "initialized", func); + intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + efree(message); + return FAILURE; + } + if (!datetime->time->is_localtime) { + *tz = TimeZone::getGMT()->clone(); + } else { + *tz = timezone_convert_datetimezone(datetime->time->zone_type, + datetime, 1, NULL, func TSRMLS_CC); + if (*tz == NULL) { + spprintf(&message, 0, "%s: could not convert DateTime's " + "time zone", func); + intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + efree(message); + return FAILURE; + } + } + } + + return SUCCESS; +} + +U_CFUNC double intl_zval_to_millis(zval *z, intl_error *err, const char *func TSRMLS_DC) +{ + double rv = NAN; + long lv; + int type; + char *message; + + if (err && U_FAILURE(err->code)) { return NAN; } @@ -43,7 +192,12 @@ U_CFUNC double intl_zval_to_millis(zval *z, UErrorCode *status TSRMLS_DC) } else if (type == IS_LONG) { rv = U_MILLIS_PER_SECOND * (double)lv; } else { - *status = U_ILLEGAL_ARGUMENT_ERROR; + spprintf(&message, 0, "%s: string '%s' is not numeric, " + "which would be required for it to be a valid date", func, + Z_STRVAL_P(z)); + intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + efree(message); } break; case IS_LONG: @@ -54,33 +208,41 @@ U_CFUNC double intl_zval_to_millis(zval *z, UErrorCode *status TSRMLS_DC) break; case IS_OBJECT: if (instanceof_function(Z_OBJCE_P(z), php_date_get_date_ce() TSRMLS_CC)) { - zval retval; - zval *zfuncname; - INIT_ZVAL(retval); - MAKE_STD_ZVAL(zfuncname); - ZVAL_STRING(zfuncname, "getTimestamp", 1); - if (call_user_function(NULL, &(z), zfuncname, &retval, 0, NULL TSRMLS_CC) - != SUCCESS || Z_TYPE(retval) != IS_LONG) { - *status = U_INTERNAL_PROGRAM_ERROR; - } else { - rv = U_MILLIS_PER_SECOND * (double)Z_LVAL(retval); - } - zval_ptr_dtor(&zfuncname); + intl_datetime_decompose(z, &rv, NULL, err, func TSRMLS_CC); } else if (instanceof_function(Z_OBJCE_P(z), Calendar_ce_ptr TSRMLS_CC)) { Calendar_object *co = (Calendar_object *) zend_object_store_get_object(z TSRMLS_CC ); if (co->ucal == NULL) { - *status = U_ILLEGAL_ARGUMENT_ERROR; + spprintf(&message, 0, "%s: IntlCalendar object is not properly " + "constructed", func); + intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + efree(message); } else { - rv = (double)co->ucal->getTime(*status); + UErrorCode status = UErrorCode(); + rv = (double)co->ucal->getTime(status); + if (U_FAILURE(status)) { + spprintf(&message, 0, "%s: call to internal " + "Calendar::getTime() has failed", func); + intl_errors_set(err, status, message, 1 TSRMLS_CC); + efree(message); + } } } else { /* TODO: try with cast(), get() to obtain a number */ - *status = U_ILLEGAL_ARGUMENT_ERROR; + spprintf(&message, 0, "%s: invalid object type for date/time " + "(only IntlCalendar and DateTime permitted)", func); + intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + efree(message); } break; default: - *status = U_ILLEGAL_ARGUMENT_ERROR; + spprintf(&message, 0, "%s: invalid PHP type for date", func); + intl_errors_set(err, U_ILLEGAL_ARGUMENT_ERROR, + message, 1 TSRMLS_CC); + efree(message); + break; } return rv; |
