/** * @bug 4060212 */ void DateFormatRegressionTest::Test4060212(void) { UnicodeString dateString = "1995-040.05:01:29"; logln( "dateString= " + dateString ); logln("Using yyyy-DDD.hh:mm:ss"); UErrorCode status = U_ZERO_ERROR; SimpleDateFormat *formatter = new SimpleDateFormat(UnicodeString("yyyy-DDD.hh:mm:ss"), status); if (failure(status, "new SimpleDateFormat", TRUE)) return; ParsePosition pos(0); UDate myDate = formatter->parse( dateString, pos ); UnicodeString myString; DateFormat *fmt = DateFormat::createDateTimeInstance( DateFormat::FULL, DateFormat::LONG); if (fmt == NULL) { dataerrln("Error calling DateFormat::createDateTimeInstance"); delete formatter; return; } myString = fmt->format( myDate, myString); logln( myString ); Calendar *cal = new GregorianCalendar(status); failure(status, "new GregorianCalendar"); cal->setTime(myDate, status); failure(status, "cal->setTime"); if ((cal->get(UCAL_DAY_OF_YEAR, status) != 40) || failure(status, "cal->get")) errln((UnicodeString) "Fail: Got " + cal->get(UCAL_DAY_OF_YEAR, status) + " Want 40"); // this is an odd usage of "ddd" and it doesn't // work now that date values are range checked per #3579. logln("Using yyyy-ddd.hh:mm:ss"); delete formatter; formatter = NULL; formatter = new SimpleDateFormat(UnicodeString("yyyy-ddd.hh:mm:ss"), status); if(failure(status, "new SimpleDateFormat")) return; pos.setIndex(0); myDate = formatter->parse( dateString, pos ); myString = fmt->format( myDate, myString ); logln( myString ); cal->setTime(myDate, status); failure(status, "cal->setTime"); if ((cal->get(UCAL_DAY_OF_YEAR, status) != 40) || failure(status, "cal->get")) errln((UnicodeString) "Fail: Got " + cal->get(UCAL_DAY_OF_YEAR, status) + " Want 40"); delete formatter; delete fmt; delete cal; }
// Mimics Date.getYear() etc. void CalendarTimeZoneTest::dateToFields(UDate date, int32_t& y, int32_t& m, int32_t& d, int32_t& hr, int32_t& min, int32_t& sec) { Calendar* cal = getCalendar(); if (cal == 0) return; UErrorCode status = U_ZERO_ERROR; cal->setTime(date, status); y = cal->get(UCAL_YEAR, status) - 1900; m = cal->get(UCAL_MONTH, status); d = cal->get(UCAL_DATE, status); hr = cal->get(UCAL_HOUR_OF_DAY, status); min = cal->get(UCAL_MINUTE, status); sec = cal->get(UCAL_SECOND, status); releaseCalendar(cal); }
int32_t RelativeDateFormat::dayDifference(Calendar &cal, UErrorCode &status) { if(U_FAILURE(status)) { return 0; } // TODO: Cache the nowCal to avoid heap allocs? Would be difficult, don't know the calendar type Calendar *nowCal = cal.clone(); nowCal->setTime(Calendar::getNow(), status); // For the day difference, we are interested in the difference in the (modified) julian day number // which is midnight to midnight. Using fieldDifference() is NOT correct here, because // 6pm Jan 4th to 10am Jan 5th should be considered "tomorrow". int32_t dayDiff = cal.get(UCAL_JULIAN_DAY, status) - nowCal->get(UCAL_JULIAN_DAY, status); delete nowCal; return dayDiff; }
void IslamicCalendar::initializeSystemDefaultCentury() { // initialize systemDefaultCentury and systemDefaultCenturyYear based // on the current time. They'll be set to 80 years before // the current time. // No point in locking as it should be idempotent. if (fgSystemDefaultCenturyStart == fgSystemDefaultCentury) { UErrorCode status = U_ZERO_ERROR; Calendar *calendar = new IslamicCalendar(Locale("ar@calendar=islamic-civil"),status); if (calendar != NULL && U_SUCCESS(status)) { calendar->setTime(Calendar::getNow(), status); calendar->add(UCAL_YEAR, -80, status); UDate newStart = calendar->getTime(status); int32_t newYear = calendar->get(UCAL_YEAR, status); { Mutex m; fgSystemDefaultCenturyStart = newStart; fgSystemDefaultCenturyStartYear = newYear; } delete calendar; } // We have no recourse upon failure unless we want to propagate the failure // out. } }
std::string resultDateInJson(const UDate& date) { UErrorCode status = U_ZERO_ERROR; Calendar* cal = Calendar::createInstance(status); if (!cal) { slog2f(0, ID_G11N, SLOG2_ERROR, "GlobalizationNDK::resultInJson: failed to create Calendar instance: %d", status); return errorInJson(UNKNOWN_ERROR, "Failed to create Calendar instance!"); } std::auto_ptr<Calendar> deleter(cal); cal->setTime(date, status); if (status != U_ZERO_ERROR && status != U_ERROR_WARNING_START) { slog2f(0, ID_G11N, SLOG2_ERROR, "GlobalizationNDK::resultInJson: failed to setTime: %d", status); return errorInJson(UNKNOWN_ERROR, "Failed to set Calendar time!"); } Json::Value result; result["year"] = cal->get(UCAL_YEAR, status); result["month"] = cal->get(UCAL_MONTH, status); result["day"] = cal->get(UCAL_DAY_OF_MONTH, status); result["hour"] = cal->get(UCAL_HOUR, status); result["minute"] = cal->get(UCAL_MINUTE, status); result["second"] = cal->get(UCAL_SECOND, status); result["millisecond"] = cal->get(UCAL_MILLISECOND, status); Json::Value root; root["result"] = result; Json::FastWriter writer; return writer.write(root); }
/** * @bug 4126678 * CANNOT REPRODUDE * * Yet another _alleged_ bug in TimeZone::getOffset(), a method that never * should have been made public. It's simply too hard to use correctly. * * The original test code failed to do the following: * (1) Call Calendar::setTime() before getting the fields! * (2) Use the right millis (as usual) for getOffset(); they were passing * in the MILLIS field, instead of the STANDARD MILLIS IN DAY. * When you fix these two problems, the test passes, as expected. */ void TimeZoneRegressionTest:: Test4126678() { UErrorCode status = U_ZERO_ERROR; Calendar *cal = Calendar::createInstance(status); if(U_FAILURE(status)) { dataerrln("Error creating calendar %s", u_errorName(status)); delete cal; return; } failure(status, "Calendar::createInstance"); TimeZone *tz = TimeZone::createTimeZone("PST"); cal->adoptTimeZone(tz); cal->set(1998, UCAL_APRIL, 5, 10, 0); if (! tz->useDaylightTime() || U_FAILURE(status)) dataerrln("We're not in Daylight Savings Time and we should be. - %s", u_errorName(status)); //cal.setTime(dt); int32_t era = cal->get(UCAL_ERA, status); int32_t year = cal->get(UCAL_YEAR, status); int32_t month = cal->get(UCAL_MONTH, status); int32_t day = cal->get(UCAL_DATE, status); int32_t dayOfWeek = cal->get(UCAL_DAY_OF_WEEK, status); int32_t millis = cal->get(UCAL_MILLISECOND, status) + (cal->get(UCAL_SECOND, status) + (cal->get(UCAL_MINUTE, status) + (cal->get(UCAL_HOUR, status) * 60) * 60) * 1000) - cal->get(UCAL_DST_OFFSET, status); failure(status, "cal->get"); int32_t offset = tz->getOffset((uint8_t)era, year, month, day, (uint8_t)dayOfWeek, millis, status); int32_t raw_offset = tz->getRawOffset(); if (offset == raw_offset) dataerrln("Offsets should match"); delete cal; }
int32_t Calendar::getActualMaximum(UCalendarDateFields field, UErrorCode& status) const { int32_t fieldValue = getLeastMaximum(field); int32_t endValue = getMaximum(field); // if we know that the maximum value is always the same, just return it if (fieldValue == endValue) { return fieldValue; } // clone the calendar so we don't mess with the real one, and set it to // accept anything for the field values Calendar *work = (Calendar*)this->clone(); work->setLenient(TRUE); // if we're counting weeks, set the day of the week to Sunday. We know the // last week of a month or year will contain the first day of the week. if (field == UCAL_WEEK_OF_YEAR || field == UCAL_WEEK_OF_MONTH) work->set(UCAL_DAY_OF_WEEK, fFirstDayOfWeek); // now try each value from getLeastMaximum() to getMaximum() one by one until // we get a value that normalizes to another value. The last value that // normalizes to itself is the actual maximum for the current date int32_t result = fieldValue; do { work->set(field, fieldValue); if(work->get(field, status) != fieldValue) { break; } else { result = fieldValue; fieldValue++; } } while (fieldValue <= endValue); delete work; /* Test for buffer overflows */ if(U_FAILURE(status)) { return 0; } return result; }
int32_t Calendar::getActualMinimum(UCalendarDateFields field, UErrorCode& status) const { int32_t fieldValue = getGreatestMinimum(field); int32_t endValue = getMinimum(field); // if we know that the minimum value is always the same, just return it if (fieldValue == endValue) { return fieldValue; } // clone the calendar so we don't mess with the real one, and set it to // accept anything for the field values Calendar *work = (Calendar*)this->clone(); work->setLenient(TRUE); // now try each value from getLeastMaximum() to getMaximum() one by one until // we get a value that normalizes to another value. The last value that // normalizes to itself is the actual minimum for the current date int32_t result = fieldValue; do { work->set(field, fieldValue); if (work->get(field, status) != fieldValue) { break; } else { result = fieldValue; fieldValue--; } } while (fieldValue >= endValue); delete work; /* Test for buffer overflows */ if(U_FAILURE(status)) { return 0; } return result; }
/** * Verify the Persian Calendar. */ void IntlCalendarTest::TestPersian() { UDate timeA = Calendar::getNow(); Calendar *cal; UErrorCode status = U_ZERO_ERROR; cal = Calendar::createInstance("fa_IR@calendar=persian", status); CHECK(status, UnicodeString("Creating fa_IR@calendar=persian calendar")); // Sanity check the calendar UDate timeB = Calendar::getNow(); UDate timeCal = cal->getTime(status); if(!(timeA <= timeCal) || !(timeCal <= timeB)) { errln((UnicodeString)"Error: Calendar time " + timeCal + " is not within sampled times [" + timeA + " to " + timeB + "]!"); } // end sanity check // Test various dates to be sure of validity int32_t data[] = { 1925, 4, 24, 1304, 2, 4, 2011, 1, 11, 1389, 10, 21, 1986, 2, 25, 1364, 12, 6, 1934, 3, 14, 1312, 12, 23, 2090, 3, 19, 1468, 12, 29, 2007, 2, 22, 1385, 12, 3, 1969, 12, 31, 1348, 10, 10, 1945, 11, 12, 1324, 8, 21, 1925, 3, 31, 1304, 1, 11, 1996, 3, 19, 1374, 12, 29, 1996, 3, 20, 1375, 1, 1, 1997, 3, 20, 1375, 12, 30, 1997, 3, 21, 1376, 1, 1, 2008, 3, 19, 1386, 12, 29, 2008, 3, 20, 1387, 1, 1, 2004, 3, 19, 1382, 12, 29, 2004, 3, 20, 1383, 1, 1, 2006, 3, 20, 1384, 12, 29, 2006, 3, 21, 1385, 1, 1, 2005, 4, 20, 1384, 1, 31, 2005, 4, 21, 1384, 2, 1, 2005, 5, 21, 1384, 2, 31, 2005, 5, 22, 1384, 3, 1, 2005, 6, 21, 1384, 3, 31, 2005, 6, 22, 1384, 4, 1, 2005, 7, 22, 1384, 4, 31, 2005, 7, 23, 1384, 5, 1, 2005, 8, 22, 1384, 5, 31, 2005, 8, 23, 1384, 6, 1, 2005, 9, 22, 1384, 6, 31, 2005, 9, 23, 1384, 7, 1, 2005, 10, 22, 1384, 7, 30, 2005, 10, 23, 1384, 8, 1, 2005, 11, 21, 1384, 8, 30, 2005, 11, 22, 1384, 9, 1, 2005, 12, 21, 1384, 9, 30, 2005, 12, 22, 1384, 10, 1, 2006, 1, 20, 1384, 10, 30, 2006, 1, 21, 1384, 11, 1, 2006, 2, 19, 1384, 11, 30, 2006, 2, 20, 1384, 12, 1, 2006, 3, 20, 1384, 12, 29, 2006, 3, 21, 1385, 1, 1, // The 2820-year cycle arithmetical algorithm would fail this one. 2025, 3, 21, 1404, 1, 1, -1,-1,-1,-1,-1,-1,-1,-1,-1,-1 }; Calendar *grego = Calendar::createInstance("fa_IR@calendar=gregorian", status); for (int32_t i=0; data[i]!=-1; ) { int32_t gregYear = data[i++]; int32_t gregMonth = data[i++]-1; int32_t gregDay = data[i++]; int32_t persYear = data[i++]; int32_t persMonth = data[i++]-1; int32_t persDay = data[i++]; // Test conversion from Persian dates grego->clear(); grego->set(gregYear, gregMonth, gregDay); cal->clear(); cal->set(persYear, persMonth, persDay); UDate persTime = cal->getTime(status); UDate gregTime = grego->getTime(status); if (persTime != gregTime) { errln(UnicodeString("Expected ") + gregTime + " but got " + persTime); } // Test conversion to Persian dates cal->clear(); cal->setTime(gregTime, status); int32_t computedYear = cal->get(UCAL_YEAR, status); int32_t computedMonth = cal->get(UCAL_MONTH, status); int32_t computedDay = cal->get(UCAL_DATE, status); if ((persYear != computedYear) || (persMonth != computedMonth) || (persDay != computedDay)) { errln(UnicodeString("Expected ") + persYear + "/" + (persMonth+1) + "/" + persDay + " but got " + computedYear + "/" + (computedMonth+1) + "/" + computedDay); } } delete cal; delete grego; }
/** * Run a test of a quasi-Gregorian calendar. This is a calendar * that behaves like a Gregorian but has different year/era mappings. * The int[] data array should have the format: * * { era, year, gregorianYear, month, dayOfMonth, ... ... , -1 } */ void IntlCalendarTest::quasiGregorianTest(Calendar& cal, const Locale& gcl, const int32_t *data) { UErrorCode status = U_ZERO_ERROR; // As of JDK 1.4.1_01, using the Sun JDK GregorianCalendar as // a reference throws us off by one hour. This is most likely // due to the JDK 1.4 incorporation of historical time zones. //java.util.Calendar grego = java.util.Calendar.getInstance(); Calendar *grego = Calendar::createInstance(gcl, status); if (U_FAILURE(status)) { dataerrln("Error calling Calendar::createInstance"); return; } int32_t tz1 = cal.get(UCAL_ZONE_OFFSET,status); int32_t tz2 = grego -> get (UCAL_ZONE_OFFSET, status); if(tz1 != tz2) { errln((UnicodeString)"cal's tz " + tz1 + " != grego's tz " + tz2); } for (int32_t i=0; data[i]!=-1; ) { int32_t era = data[i++]; int32_t year = data[i++]; int32_t gregorianYear = data[i++]; int32_t month = data[i++]; int32_t dayOfMonth = data[i++]; grego->clear(); grego->set(gregorianYear, month, dayOfMonth); UDate D = grego->getTime(status); cal.clear(); cal.set(UCAL_ERA, era); cal.set(year, month, dayOfMonth); UDate d = cal.getTime(status); #ifdef U_DEBUG_DUMPCALS logln((UnicodeString)"cal : " + CalendarTest::calToStr(cal)); logln((UnicodeString)"grego: " + CalendarTest::calToStr(*grego)); #endif if (d == D) { logln(UnicodeString("OK: ") + era + ":" + year + "/" + (month+1) + "/" + dayOfMonth + " => " + d + " (" + UnicodeString(cal.getType()) + ")"); } else { errln(UnicodeString("Fail: (fields to millis)") + era + ":" + year + "/" + (month+1) + "/" + dayOfMonth + " => " + d + ", expected " + D + " (" + UnicodeString(cal.getType()) + "Off by: " + (d-D)); } // Now, set the gregorian millis on the other calendar cal.clear(); cal.setTime(D, status); int e = cal.get(UCAL_ERA, status); int y = cal.get(UCAL_YEAR, status); #ifdef U_DEBUG_DUMPCALS logln((UnicodeString)"cal : " + CalendarTest::calToStr(cal)); logln((UnicodeString)"grego: " + CalendarTest::calToStr(*grego)); #endif if (y == year && e == era) { logln((UnicodeString)"OK: " + D + " => " + cal.get(UCAL_ERA, status) + ":" + cal.get(UCAL_YEAR, status) + "/" + (cal.get(UCAL_MONTH, status)+1) + "/" + cal.get(UCAL_DATE, status) + " (" + UnicodeString(cal.getType()) + ")"); } else { errln((UnicodeString)"Fail: (millis to fields)" + D + " => " + cal.get(UCAL_ERA, status) + ":" + cal.get(UCAL_YEAR, status) + "/" + (cal.get(UCAL_MONTH, status)+1) + "/" + cal.get(UCAL_DATE, status) + ", expected " + era + ":" + year + "/" + (month+1) + "/" + dayOfMonth + " (" + UnicodeString(cal.getType())); } } delete grego; CHECK(status, "err during quasiGregorianTest()"); }
void CalendarLimitTest::doLimitsTest(Calendar& cal, const int32_t* fieldsToTest, UDate startDate, int32_t testDuration) { static const int32_t FIELDS[] = { UCAL_ERA, UCAL_YEAR, UCAL_MONTH, UCAL_WEEK_OF_YEAR, UCAL_WEEK_OF_MONTH, UCAL_DAY_OF_MONTH, UCAL_DAY_OF_YEAR, UCAL_DAY_OF_WEEK_IN_MONTH, UCAL_YEAR_WOY, UCAL_EXTENDED_YEAR, -1, }; static const char* FIELD_NAME[] = { "ERA", "YEAR", "MONTH", "WEEK_OF_YEAR", "WEEK_OF_MONTH", "DAY_OF_MONTH", "DAY_OF_YEAR", "DAY_OF_WEEK", "DAY_OF_WEEK_IN_MONTH", "AM_PM", "HOUR", "HOUR_OF_DAY", "MINUTE", "SECOND", "MILLISECOND", "ZONE_OFFSET", "DST_OFFSET", "YEAR_WOY", "DOW_LOCAL", "EXTENDED_YEAR", "JULIAN_DAY", "MILLISECONDS_IN_DAY", "IS_LEAP_MONTH" }; UErrorCode status = U_ZERO_ERROR; int32_t i, j; UnicodeString ymd; GregorianCalendar greg(status); if (failure(status, "new GregorianCalendar")) { return; } greg.setTime(startDate, status); if (failure(status, "GregorianCalendar::setTime")) { return; } logln((UnicodeString)"Start: " + startDate); if (fieldsToTest == NULL) { fieldsToTest = FIELDS; } // Keep a record of minima and maxima that we actually see. // These are kept in an array of arrays of hashes. int32_t limits[UCAL_FIELD_COUNT][4]; for (j = 0; j < UCAL_FIELD_COUNT; j++) { limits[j][0] = INT32_MAX; limits[j][1] = INT32_MIN; limits[j][2] = INT32_MAX; limits[j][3] = INT32_MIN; } // This test can run for a long time; show progress. UDate millis = ucal_getNow(); UDate mark = millis + 5000; // 5 sec millis -= testDuration * 1000; // stop time if testDuration<0 for (i = 0; testDuration > 0 ? i < testDuration : ucal_getNow() < millis; ++i) { if (ucal_getNow() >= mark) { logln((UnicodeString)"(" + i + " days)"); mark += 5000; // 5 sec } UDate testMillis = greg.getTime(status); cal.setTime(testMillis, status); cal.setMinimalDaysInFirstWeek(1); if (failure(status, "Calendar set/getTime")) { return; } for (j = 0; fieldsToTest[j] >= 0; ++j) { UCalendarDateFields f = (UCalendarDateFields)fieldsToTest[j]; int32_t v = cal.get(f, status); int32_t minActual = cal.getActualMinimum(f, status); int32_t maxActual = cal.getActualMaximum(f, status); int32_t minLow = cal.getMinimum(f); int32_t minHigh = cal.getGreatestMinimum(f); int32_t maxLow = cal.getLeastMaximum(f); int32_t maxHigh = cal.getMaximum(f); if (limits[j][0] > minActual) { // the minimum limits[j][0] = minActual; } if (limits[j][1] < minActual) { // the greatest minimum limits[j][1] = minActual; } if (limits[j][2] > maxActual) { // the least maximum limits[j][2] = maxActual; } if (limits[j][3] < maxActual) { // the maximum limits[j][3] = maxActual; } if (minActual < minLow || minActual > minHigh) { errln((UnicodeString)"Fail: [" + cal.getType() + "] " + ymdToString(cal, ymd) + " Range for min of " + FIELD_NAME[f] + "(" + f + ")=" + minLow + ".." + minHigh + ", actual_min=" + minActual); } if (maxActual < maxLow || maxActual > maxHigh) { if ( uprv_strcmp(cal.getType(), "chinese") == 0 && testMillis >= 2842992000000.0 && testMillis <= 2906668800000.0 && logKnownIssue("12620", "chinese calendar failures for some actualMax tests")) { logln((UnicodeString)"KnownFail: [" + cal.getType() + "] " + ymdToString(cal, ymd) + " Range for max of " + FIELD_NAME[f] + "(" + f + ")=" + maxLow + ".." + maxHigh + ", actual_max=" + maxActual); } else { errln((UnicodeString)"Fail: [" + cal.getType() + "] " + ymdToString(cal, ymd) + " Range for max of " + FIELD_NAME[f] + "(" + f + ")=" + maxLow + ".." + maxHigh + ", actual_max=" + maxActual); } } if (v < minActual || v > maxActual) { // timebomb per #9967, fix with #9972 if ( uprv_strcmp(cal.getType(), "dangi") == 0 && testMillis >= 1865635198000.0 && logKnownIssue("9972", "as per #9967")) { // Feb 2029 gregorian, end of dangi 4361 logln((UnicodeString)"KnownFail: [" + cal.getType() + "] " + ymdToString(cal, ymd) + " " + FIELD_NAME[f] + "(" + f + ")=" + v + ", actual=" + minActual + ".." + maxActual + ", allowed=(" + minLow + ".." + minHigh + ")..(" + maxLow + ".." + maxHigh + ")"); } else if ( uprv_strcmp(cal.getType(), "chinese") == 0 && testMillis >= 2842992000000.0 && testMillis <= 2906668800000.0 && logKnownIssue("12620", "chinese calendar failures for some actualMax tests")) { logln((UnicodeString)"KnownFail: [" + cal.getType() + "] " + ymdToString(cal, ymd) + " " + FIELD_NAME[f] + "(" + f + ")=" + v + ", actual=" + minActual + ".." + maxActual + ", allowed=(" + minLow + ".." + minHigh + ")..(" + maxLow + ".." + maxHigh + ")"); } else { errln((UnicodeString)"Fail: [" + cal.getType() + "] " + ymdToString(cal, ymd) + " " + FIELD_NAME[f] + "(" + f + ")=" + v + ", actual=" + minActual + ".." + maxActual + ", allowed=(" + minLow + ".." + minHigh + ")..(" + maxLow + ".." + maxHigh + ")"); } } } greg.add(UCAL_DAY_OF_YEAR, 1, status); if (failure(status, "Calendar::add")) { return; } } // Check actual maxima and minima seen against ranges returned // by API. UnicodeString buf; for (j = 0; fieldsToTest[j] >= 0; ++j) { int32_t rangeLow, rangeHigh; UBool fullRangeSeen = TRUE; UCalendarDateFields f = (UCalendarDateFields)fieldsToTest[j]; buf.remove(); buf.append((UnicodeString)"[" + cal.getType() + "] " + FIELD_NAME[f]); // Minumum rangeLow = cal.getMinimum(f); rangeHigh = cal.getGreatestMinimum(f); if (limits[j][0] != rangeLow || limits[j][1] != rangeHigh) { fullRangeSeen = FALSE; } buf.append((UnicodeString)" minima range=" + rangeLow + ".." + rangeHigh); buf.append((UnicodeString)" minima actual=" + limits[j][0] + ".." + limits[j][1]); // Maximum rangeLow = cal.getLeastMaximum(f); rangeHigh = cal.getMaximum(f); if (limits[j][2] != rangeLow || limits[j][3] != rangeHigh) { fullRangeSeen = FALSE; } buf.append((UnicodeString)" maxima range=" + rangeLow + ".." + rangeHigh); buf.append((UnicodeString)" maxima actual=" + limits[j][2] + ".." + limits[j][3]); if (fullRangeSeen) { logln((UnicodeString)"OK: " + buf); } else { // This may or may not be an error -- if the range of dates // we scan over doesn't happen to contain a minimum or // maximum, it doesn't mean some other range won't. logln((UnicodeString)"Warning: " + buf); } } logln((UnicodeString)"End: " + greg.getTime(status)); }
/** * Return the maximum value that this field could have, given the current date. * For example, with the date "Feb 3, 1997" and the DAY_OF_MONTH field, the actual * maximum would be 28; for "Feb 3, 1996" it s 29. Similarly for a Hebrew calendar, * for some years the actual maximum for MONTH is 12, and for others 13. * @stable ICU 2.0 */ int32_t GregorianCalendar::getActualMaximum(UCalendarDateFields field, UErrorCode& status) const { /* It is a known limitation that the code here (and in getActualMinimum) * won't behave properly at the extreme limits of GregorianCalendar's * representable range (except for the code that handles the YEAR * field). That's because the ends of the representable range are at * odd spots in the year. For calendars with the default Gregorian * cutover, these limits are Sun Dec 02 16:47:04 GMT 292269055 BC to Sun * Aug 17 07:12:55 GMT 292278994 AD, somewhat different for non-GMT * zones. As a result, if the calendar is set to Aug 1 292278994 AD, * the actual maximum of DAY_OF_MONTH is 17, not 30. If the date is Mar * 31 in that year, the actual maximum month might be Jul, whereas is * the date is Mar 15, the actual maximum might be Aug -- depending on * the precise semantics that are desired. Similar considerations * affect all fields. Nonetheless, this effect is sufficiently arcane * that we permit it, rather than complicating the code to handle such * intricacies. - liu 8/20/98 * UPDATE: No longer true, since we have pulled in the limit values on * the year. - Liu 11/6/00 */ switch (field) { case UCAL_YEAR: /* The year computation is no different, in principle, from the * others, however, the range of possible maxima is large. In * addition, the way we know we've exceeded the range is different. * For these reasons, we use the special case code below to handle * this field. * * The actual maxima for YEAR depend on the type of calendar: * * Gregorian = May 17, 292275056 BC - Aug 17, 292278994 AD * Julian = Dec 2, 292269055 BC - Jan 3, 292272993 AD * Hybrid = Dec 2, 292269055 BC - Aug 17, 292278994 AD * * We know we've exceeded the maximum when either the month, date, * time, or era changes in response to setting the year. We don't * check for month, date, and time here because the year and era are * sufficient to detect an invalid year setting. NOTE: If code is * added to check the month and date in the future for some reason, * Feb 29 must be allowed to shift to Mar 1 when setting the year. */ { if(U_FAILURE(status)) return 0; Calendar *cal = clone(); if(!cal) { status = U_MEMORY_ALLOCATION_ERROR; return 0; } cal->setLenient(TRUE); int32_t era = cal->get(UCAL_ERA, status); UDate d = cal->getTime(status); /* Perform a binary search, with the invariant that lowGood is a * valid year, and highBad is an out of range year. */ int32_t lowGood = kGregorianCalendarLimits[UCAL_YEAR][1]; int32_t highBad = kGregorianCalendarLimits[UCAL_YEAR][2]+1; while ((lowGood + 1) < highBad) { int32_t y = (lowGood + highBad) / 2; cal->set(UCAL_YEAR, y); if (cal->get(UCAL_YEAR, status) == y && cal->get(UCAL_ERA, status) == era) { lowGood = y; } else { highBad = y; cal->setTime(d, status); // Restore original fields } } delete cal; return lowGood; } default: return Calendar::getActualMaximum(field,status); } }
/** * Check that the given year/month/dom/hour maps to and from the * given epochHours. This verifies the functioning of the * calendar and time zone in conjunction with one another, * including the calendar time->fields and fields->time and * the time zone getOffset method. * * @param epochHours hours after Jan 1 1970 0:00 GMT. */ void TimeZoneBoundaryTest::verifyMapping(Calendar& cal, int year, int month, int dom, int hour, double epochHours) { double H = 3600000.0; UErrorCode status = U_ZERO_ERROR; cal.clear(); cal.set(year, month, dom, hour, 0, 0); UDate e = cal.getTime(status)/ H; UDate ed = (epochHours * H); if (e == epochHours) { logln(UnicodeString("Ok: ") + year + "/" + (month+1) + "/" + dom + " " + hour + ":00 => " + e + " (" + ed + ")"); } else { dataerrln(UnicodeString("FAIL: ") + year + "/" + (month+1) + "/" + dom + " " + hour + ":00 => " + e + " (" + (e * H) + ")" + ", expected " + epochHours + " (" + ed + ")"); } cal.setTime(ed, status); if (cal.get(UCAL_YEAR, status) == year && cal.get(UCAL_MONTH, status) == month && cal.get(UCAL_DATE, status) == dom && cal.get(UCAL_MILLISECONDS_IN_DAY, status) == hour * 3600000) { logln(UnicodeString("Ok: ") + epochHours + " (" + ed + ") => " + cal.get(UCAL_YEAR, status) + "/" + (cal.get(UCAL_MONTH, status)+1) + "/" + cal.get(UCAL_DATE, status) + " " + cal.get(UCAL_MILLISECOND, status)/H); } else { dataerrln(UnicodeString("FAIL: ") + epochHours + " (" + ed + ") => " + cal.get(UCAL_YEAR, status) + "/" + (cal.get(UCAL_MONTH, status)+1) + "/" + cal.get(UCAL_DATE, status) + " " + cal.get(UCAL_MILLISECOND, status)/H + ", expected " + year + "/" + (month+1) + "/" + dom + " " + hour); } }
/** * Get values of date-time fields * * @param time * @param locale * @param tz * * @return list * * @version 0.5-1 (Marek Gagolewski, 2015-01-01) * @version 0.5-1 (Marek Gagolewski, 2015-03-03) tz arg added */ SEXP stri_datetime_fields(SEXP time, SEXP tz, SEXP locale) { PROTECT(time = stri_prepare_arg_POSIXct(time, "time")); const char* locale_val = stri__prepare_arg_locale(locale, "locale", true); if (!isNull(tz)) PROTECT(tz = stri_prepare_arg_string_1(tz, "tz")); else PROTECT(tz); /* needed to set tzone attrib */ TimeZone* tz_val = stri__prepare_arg_timezone(tz, "tz", true/*allowdefault*/); Calendar* cal = NULL; STRI__ERROR_HANDLER_BEGIN(2) R_len_t vectorize_length = LENGTH(time); StriContainerDouble time_cont(time, vectorize_length); UErrorCode status = U_ZERO_ERROR; cal = Calendar::createInstance(locale_val, status); STRI__CHECKICUSTATUS_THROW(status, {/* do nothing special on err */}) cal->adoptTimeZone(tz_val); tz_val = NULL; /* The Calendar takes ownership of the TimeZone. */ SEXP ret; #define STRI__FIELDS_NUM 14 STRI__PROTECT(ret = Rf_allocVector(VECSXP, STRI__FIELDS_NUM)); for (R_len_t j=0; j<STRI__FIELDS_NUM; ++j) SET_VECTOR_ELT(ret, j, Rf_allocVector(INTSXP, vectorize_length)); for (R_len_t i=0; i<vectorize_length; ++i) { if (time_cont.isNA(i)) { for (R_len_t j=0; j<STRI__FIELDS_NUM; ++j) INTEGER(VECTOR_ELT(ret, j))[i] = NA_INTEGER; continue; } status = U_ZERO_ERROR; cal->setTime((UDate)(time_cont.get(i)*1000.0), status); STRI__CHECKICUSTATUS_THROW(status, {/* do nothing special on err */}) for (R_len_t j=0; j<STRI__FIELDS_NUM; ++j) { UCalendarDateFields units_field; switch (j) { case 0: units_field = UCAL_EXTENDED_YEAR; break; case 1: units_field = UCAL_MONTH; break; case 2: units_field = UCAL_DAY_OF_MONTH; break; case 3: units_field = UCAL_HOUR_OF_DAY; break; case 4: units_field = UCAL_MINUTE; break; case 5: units_field = UCAL_SECOND; break; case 6: units_field = UCAL_MILLISECOND; break; case 7: units_field = UCAL_WEEK_OF_YEAR; break; case 8: units_field = UCAL_WEEK_OF_MONTH; break; case 9: units_field = UCAL_DAY_OF_YEAR; break; case 10: units_field = UCAL_DAY_OF_WEEK; break; case 11: units_field = UCAL_HOUR; break; case 12: units_field = UCAL_AM_PM; break; case 13: units_field = UCAL_ERA; break; default: throw StriException(MSG__INCORRECT_MATCH_OPTION, "units"); } //UCAL_IS_LEAP_MONTH //UCAL_MILLISECONDS_IN_DAY -> SecondsInDay // UCAL_AM_PM -> "AM" or "PM" (localized? or factor?+index in stri_datetime_symbols) add arg use_symbols???? // UCAL_DAY_OF_WEEK -> (localized? or factor?) SUNDAY, MONDAY // UCAL_DAY_OF_YEAR ' // isWekend status = U_ZERO_ERROR; INTEGER(VECTOR_ELT(ret, j))[i] = cal->get(units_field, status); STRI__CHECKICUSTATUS_THROW(status, {/* do nothing special on err */}) if (units_field == UCAL_MONTH) ++INTEGER(VECTOR_ELT(ret, j))[i]; // month + 1 else if (units_field == UCAL_AM_PM) ++INTEGER(VECTOR_ELT(ret, j))[i]; // ampm + 1 else if (units_field == UCAL_ERA) ++INTEGER(VECTOR_ELT(ret, j))[i]; // era + 1 }