void CalendarLimitTest::TestCalendarExtremeLimit() { UErrorCode status = U_ZERO_ERROR; Calendar *cal = Calendar::createInstance(status); if (failure(status, "Calendar::createInstance", TRUE)) return; cal->adoptTimeZone(TimeZone::createTimeZone("GMT")); DateFormat *fmt = DateFormat::createDateTimeInstance(); if(!fmt || !cal) { dataerrln("can't open cal and/or fmt"); return; } fmt->adoptCalendar(cal); ((SimpleDateFormat*) fmt)->applyPattern("HH:mm:ss.SSS Z, EEEE, MMMM d, yyyy G"); // This test used to test the algorithmic limits of the dates that // GregorianCalendar could handle. However, the algorithm has // been rewritten completely since then and the prior limits no // longer apply. Instead, we now do basic round-trip testing of // some extreme (but still manageable) dates. UDate m; logln("checking 1e16..1e17"); for ( m = 1e16; m < 1e17; m *= 1.1) { test(m, cal, fmt); } logln("checking -1e14..-1e15"); for ( m = -1e14; m > -1e15; m *= 1.1) { test(m, cal, fmt); } // This is 2^52 - 1, the largest allowable mantissa with a 0 // exponent in a 64-bit double UDate VERY_EARLY_MILLIS = - 4503599627370495.0; UDate VERY_LATE_MILLIS = 4503599627370495.0; // I am removing the previousDouble and nextDouble calls below for // two reasons: 1. As part of jitterbug 986, I am deprecating // these methods and removing calls to them. 2. This test is a // non-critical boundary behavior test. test(VERY_EARLY_MILLIS, cal, fmt); //test(previousDouble(VERY_EARLY_MILLIS), cal, fmt); test(VERY_LATE_MILLIS, cal, fmt); //test(nextDouble(VERY_LATE_MILLIS), cal, fmt); delete fmt; }
/** * This test checks various generic API methods in DateFormat to achieve 100% * API coverage. */ void IntlTestDateFormatAPI::testAPI(/* char* par */) { UErrorCode status = U_ZERO_ERROR; // ======= Test constructors logln("Testing DateFormat constructors"); DateFormat *def = DateFormat::createInstance(); DateFormat *fr = DateFormat::createTimeInstance(DateFormat::FULL, Locale::getFrench()); DateFormat *it = DateFormat::createDateInstance(DateFormat::MEDIUM, Locale::getItalian()); DateFormat *de = DateFormat::createDateTimeInstance(DateFormat::LONG, DateFormat::LONG, Locale::getGerman()); if (def == NULL || fr == NULL || it == NULL || de == NULL){ dataerrln("Error creating instnaces."); } // ======= Test equality if (fr != NULL && def != NULL) { logln("Testing equality operator"); if( *fr == *it ) { errln("ERROR: == failed"); } } // ======= Test various format() methods if (fr != NULL && it != NULL && de != NULL) { logln("Testing various format() methods"); UDate d = 837039928046.0; Formattable fD(d, Formattable::kIsDate); UnicodeString res1, res2, res3; FieldPosition pos1(0), pos2(0); status = U_ZERO_ERROR; res1 = fr->format(d, res1, pos1, status); if(U_FAILURE(status)) { errln("ERROR: format() failed (French)"); } logln( (UnicodeString) "" + d + " formatted to " + res1); res2 = it->format(d, res2, pos2); logln( (UnicodeString) "" + d + " formatted to " + res2); res3 = de->format(d, res3); logln( (UnicodeString) "" + d + " formatted to " + res3); } // ======= Test parse() if (def != NULL) { logln("Testing parse()"); UnicodeString text("02/03/76 2:50 AM, CST"); Formattable result1; UDate result2, result3; ParsePosition pos(0), pos01(0); def->parseObject(text, result1, pos); if(result1.getType() != Formattable::kDate) { errln("ERROR: parseObject() failed for " + text); } logln(text + " parsed into " + result1.getDate()); status = U_ZERO_ERROR; result2 = def->parse(text, status); if(U_FAILURE(status)) { errln("ERROR: parse() failed, stopping testing"); return; } logln(text + " parsed into " + result2); result3 = def->parse(text, pos01); logln(text + " parsed into " + result3); } // ======= Test getters and setters if (fr != NULL && it != NULL && de != NULL) { logln("Testing getters and setters"); int32_t count = 0; const Locale *locales = DateFormat::getAvailableLocales(count); logln((UnicodeString) "Got " + count + " locales" ); for(int32_t i = 0; i < count; i++) { UnicodeString name; name = locales[i].getName(); logln(name); } fr->setLenient(it->isLenient()); if(fr->isLenient() != it->isLenient()) { errln("ERROR: setLenient() failed"); } const Calendar *cal = def->getCalendar(); Calendar *newCal = cal->clone(); de->adoptCalendar(newCal); it->setCalendar(*newCal); if( *(de->getCalendar()) != *(it->getCalendar())) { errln("ERROR: adopt or set Calendar() failed"); } const NumberFormat *nf = def->getNumberFormat(); NumberFormat *newNf = (NumberFormat*) nf->clone(); de->adoptNumberFormat(newNf); it->setNumberFormat(*newNf); if( *(de->getNumberFormat()) != *(it->getNumberFormat())) { errln("ERROR: adopt or set NumberFormat() failed"); } const TimeZone& tz = def->getTimeZone(); TimeZone *newTz = tz.clone(); de->adoptTimeZone(newTz); it->setTimeZone(*newTz); if( de->getTimeZone() != it->getTimeZone()) { errln("ERROR: adopt or set TimeZone() failed"); } } // ======= Test getStaticClassID() logln("Testing getStaticClassID()"); status = U_ZERO_ERROR; DateFormat *test = new SimpleDateFormat(status); if(U_FAILURE(status)) { errln("ERROR: Couldn't create a DateFormat"); } if(test->getDynamicClassID() != SimpleDateFormat::getStaticClassID()) { errln("ERROR: getDynamicClassID() didn't return the expected value"); } delete test; delete def; delete fr; delete it; delete de; }
/* {{{ */ static void datefmt_ctor(INTERNAL_FUNCTION_PARAMETERS) { zval *object; const char *locale_str; size_t locale_len = 0; Locale locale; zend_long date_type = 0; zend_long time_type = 0; zval *calendar_zv = NULL; Calendar *calendar = NULL; zend_long calendar_type; bool calendar_owned; zval *timezone_zv = NULL; TimeZone *timezone = NULL; bool explicit_tz; char* pattern_str = NULL; size_t pattern_str_len = 0; UChar* svalue = NULL; /* UTF-16 pattern_str */ int32_t slength = 0; IntlDateFormatter_object* dfo; intl_error_reset(NULL); object = return_value; /* Parse parameters. */ if (zend_parse_parameters(ZEND_NUM_ARGS(), "sll|zzs", &locale_str, &locale_len, &date_type, &time_type, &timezone_zv, &calendar_zv, &pattern_str, &pattern_str_len) == FAILURE) { intl_error_set( NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_create: " "unable to parse input parameters", 0); Z_OBJ_P(return_value) = NULL; return; } INTL_CHECK_LOCALE_LEN_OBJ(locale_len, return_value); if (locale_len == 0) { locale_str = intl_locale_get_default(); } locale = Locale::createFromName(locale_str); DATE_FORMAT_METHOD_FETCH_OBJECT_NO_CHECK; if (DATE_FORMAT_OBJECT(dfo) != NULL) { intl_errors_set(INTL_DATA_ERROR_P(dfo), U_ILLEGAL_ARGUMENT_ERROR, "datefmt_create: cannot call constructor twice", 0); return; } /* process calendar */ if (datefmt_process_calendar_arg(calendar_zv, locale, "datefmt_create", INTL_DATA_ERROR_P(dfo), calendar, calendar_type, calendar_owned) == FAILURE) { goto error; } /* process timezone */ explicit_tz = timezone_zv != NULL && Z_TYPE_P(timezone_zv) != IS_NULL; if (explicit_tz || calendar_owned ) { //we have an explicit time zone or a non-object calendar timezone = timezone_process_timezone_argument(timezone_zv, INTL_DATA_ERROR_P(dfo), "datefmt_create"); if (timezone == NULL) { goto error; } } /* Convert pattern (if specified) to UTF-16. */ if (pattern_str && pattern_str_len > 0) { intl_convert_utf8_to_utf16(&svalue, &slength, pattern_str, pattern_str_len, &INTL_DATA_ERROR_CODE(dfo)); if (U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) { /* object construction -> only set global error */ intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create: " "error converting pattern to UTF-16", 0); goto error; } } if (pattern_str && pattern_str_len > 0) { DATE_FORMAT_OBJECT(dfo) = udat_open(UDAT_IGNORE, UDAT_IGNORE, locale_str, NULL, 0, svalue, slength, &INTL_DATA_ERROR_CODE(dfo)); } else { DATE_FORMAT_OBJECT(dfo) = udat_open((UDateFormatStyle)time_type, (UDateFormatStyle)date_type, locale_str, NULL, 0, svalue, slength, &INTL_DATA_ERROR_CODE(dfo)); } if (!U_FAILURE(INTL_DATA_ERROR_CODE(dfo))) { DateFormat *df = (DateFormat*)DATE_FORMAT_OBJECT(dfo); if (calendar_owned) { df->adoptCalendar(calendar); calendar_owned = false; } else { df->setCalendar(*calendar); } if (timezone != NULL) { df->adoptTimeZone(timezone); } } else { intl_error_set(NULL, INTL_DATA_ERROR_CODE(dfo), "datefmt_create: date " "formatter creation failed", 0); goto error; } /* Set the class variables */ dfo->date_type = date_type; dfo->time_type = time_type; dfo->calendar = calendar_type; dfo->requested_locale = estrdup(locale_str); error: if (svalue) { efree(svalue); } if (timezone != NULL && DATE_FORMAT_OBJECT(dfo) == NULL) { delete timezone; } if (calendar != NULL && calendar_owned) { delete calendar; } if (U_FAILURE(intl_error_get_code(NULL))) { /* free_object handles partially constructed instances fine */ Z_OBJ_P(return_value) = NULL; } }
U_CFUNC PHP_FUNCTION(datefmt_format_object) { zval *object, *format = NULL; const char *locale_str = NULL; size_t locale_len; bool pattern = false; UDate date; TimeZone *timeZone = NULL; UErrorCode status = U_ZERO_ERROR; DateFormat *df = NULL; Calendar *cal = NULL; DateFormat::EStyle dateStyle = DateFormat::kDefault, timeStyle = DateFormat::kDefault; if (zend_parse_parameters(ZEND_NUM_ARGS(), "o|zs!", &object, &format, &locale_str, &locale_len) == FAILURE) { RETURN_FALSE; } if (!locale_str) { locale_str = intl_locale_get_default(); } if (format == NULL || Z_TYPE_P(format) == IS_NULL) { //nothing } else if (Z_TYPE_P(format) == IS_ARRAY) { HashTable *ht = Z_ARRVAL_P(format); HashPosition pos = {0}; zval *z; if (zend_hash_num_elements(ht) != 2) { intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_format_object: bad format; if array, it must have " "two elements", 0); RETURN_FALSE; } zend_hash_internal_pointer_reset_ex(ht, &pos); z = zend_hash_get_current_data_ex(ht, &pos); if (!valid_format(z)) { intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_format_object: bad format; the date format (first " "element of the array) is not valid", 0); RETURN_FALSE; } dateStyle = (DateFormat::EStyle)Z_LVAL_P(z); zend_hash_move_forward_ex(ht, &pos); z = zend_hash_get_current_data_ex(ht, &pos); if (!valid_format(z)) { intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_format_object: bad format; the time format (" "second element of the array) is not valid", 0); RETURN_FALSE; } timeStyle = (DateFormat::EStyle)Z_LVAL_P(z); } else if (Z_TYPE_P(format) == IS_LONG) { if (!valid_format(format)) { intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_format_object: the date/time format type is invalid", 0); RETURN_FALSE; } dateStyle = timeStyle = (DateFormat::EStyle)Z_LVAL_P(format); } else { convert_to_string_ex(format); if (Z_STRLEN_P(format) == 0) { intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_format_object: the format is empty", 0); RETURN_FALSE; } pattern = true; } //there's no support for relative time in ICU yet timeStyle = (DateFormat::EStyle)(timeStyle & ~DateFormat::kRelative); zend_class_entry *instance_ce = Z_OBJCE_P(object); if (instanceof_function(instance_ce, Calendar_ce_ptr)) { Calendar *obj_cal = calendar_fetch_native_calendar(object); if (obj_cal == NULL) { intl_error_set(NULL, U_ILLEGAL_ARGUMENT_ERROR, "datefmt_format_object: bad IntlCalendar instance: " "not initialized properly", 0); RETURN_FALSE; } timeZone = obj_cal->getTimeZone().clone(); date = obj_cal->getTime(status); if (U_FAILURE(status)) { intl_error_set(NULL, status, "datefmt_format_object: error obtaining instant from " "IntlCalendar", 0); RETVAL_FALSE; goto cleanup; } cal = obj_cal->clone(); } else if (instanceof_function(instance_ce, php_date_get_date_ce())) { if (intl_datetime_decompose(object, &date, &timeZone, NULL, "datefmt_format_object") == FAILURE) { RETURN_FALSE; } cal = new GregorianCalendar(Locale::createFromName(locale_str), status); if (U_FAILURE(status)) { intl_error_set(NULL, status, "datefmt_format_object: could not create GregorianCalendar", 0); RETVAL_FALSE; goto cleanup; } } else { intl_error_set(NULL, status, "datefmt_format_object: the passed object " "must be an instance of either IntlCalendar or DateTime", 0); RETURN_FALSE; } if (pattern) { df = new SimpleDateFormat( UnicodeString(Z_STRVAL_P(format), Z_STRLEN_P(format), UnicodeString::kInvariant), Locale::createFromName(locale_str), status); if (U_FAILURE(status)) { intl_error_set(NULL, status, "datefmt_format_object: could not create SimpleDateFormat", 0); RETVAL_FALSE; goto cleanup; } } else { df = DateFormat::createDateTimeInstance(dateStyle, timeStyle, Locale::createFromName(locale_str)); if (df == NULL) { /* according to ICU sources, this should never happen */ intl_error_set(NULL, status, "datefmt_format_object: could not create DateFormat", 0); RETVAL_FALSE; goto cleanup; } } //must be in this order (or have the cal adopt the tz) df->adoptCalendar(cal); cal = NULL; df->adoptTimeZone(timeZone); timeZone = NULL; { char *ret_str; int ret_str_len; UnicodeString result = UnicodeString(); df->format(date, result); if (intl_charFromString(result, &ret_str, &ret_str_len, &status) == FAILURE) { intl_error_set(NULL, status, "datefmt_format_object: error converting result to UTF-8", 0); RETVAL_FALSE; goto cleanup; } RETVAL_STRINGL(ret_str, ret_str_len); //??? efree(ret_str); } cleanup: delete df; delete timeZone; delete cal; }