Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1952)

Unified Diff: source/i18n/calendar.cpp

Issue 845603002: Update ICU to 54.1 step 1 (Closed) Base URL: https://chromium.googlesource.com/chromium/deps/icu.git@master
Patch Set: remove unusued directories Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « source/i18n/bocsu.cpp ('k') | source/i18n/chnsecal.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: source/i18n/calendar.cpp
diff --git a/source/i18n/calendar.cpp b/source/i18n/calendar.cpp
index 27825c04a2c85ec8907ebcdd03c9e23d382d02fc..062a9e9c30ae0af4dffe7d7629b2002001e872f6 100644
--- a/source/i18n/calendar.cpp
+++ b/source/i18n/calendar.cpp
@@ -1,6 +1,6 @@
/*
*******************************************************************************
-* Copyright (C) 1997-2013, International Business Machines Corporation and *
+* Copyright (C) 1997-2014, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*
@@ -106,7 +106,7 @@ U_CDECL_END
*/
const char* fldName(UCalendarDateFields f) {
- return udbg_enumName(UDBG_UCalendarDateFields, (int32_t)f);
+ return udbg_enumName(UDBG_UCalendarDateFields, (int32_t)f);
}
#if UCAL_DEBUG_DUMP
@@ -680,11 +680,14 @@ fAreFieldsVirtuallySet(FALSE),
fNextStamp((int32_t)kMinimumUserStamp),
fTime(0),
fLenient(TRUE),
-fZone(0),
+fZone(NULL),
fRepeatedWallTime(UCAL_WALLTIME_LAST),
fSkippedWallTime(UCAL_WALLTIME_LAST)
{
clear();
+ if (U_FAILURE(success)) {
+ return;
+ }
fZone = TimeZone::createDefault();
if (fZone == NULL) {
success = U_MEMORY_ALLOCATION_ERROR;
@@ -703,10 +706,13 @@ fAreFieldsVirtuallySet(FALSE),
fNextStamp((int32_t)kMinimumUserStamp),
fTime(0),
fLenient(TRUE),
-fZone(0),
+fZone(NULL),
fRepeatedWallTime(UCAL_WALLTIME_LAST),
fSkippedWallTime(UCAL_WALLTIME_LAST)
{
+ if (U_FAILURE(success)) {
+ return;
+ }
if(zone == 0) {
#if defined (U_DEBUG_CAL)
fprintf(stderr, "%s:%d: ILLEGAL ARG because timezone cannot be 0\n",
@@ -718,7 +724,6 @@ fSkippedWallTime(UCAL_WALLTIME_LAST)
clear();
fZone = zone;
-
setWeekData(aLocale, NULL, success);
}
@@ -733,14 +738,17 @@ fAreFieldsVirtuallySet(FALSE),
fNextStamp((int32_t)kMinimumUserStamp),
fTime(0),
fLenient(TRUE),
-fZone(0),
+fZone(NULL),
fRepeatedWallTime(UCAL_WALLTIME_LAST),
fSkippedWallTime(UCAL_WALLTIME_LAST)
{
+ if (U_FAILURE(success)) {
+ return;
+ }
clear();
fZone = zone.clone();
if (fZone == NULL) {
- success = U_MEMORY_ALLOCATION_ERROR;
+ success = U_MEMORY_ALLOCATION_ERROR;
}
setWeekData(aLocale, NULL, success);
}
@@ -757,7 +765,7 @@ Calendar::~Calendar()
Calendar::Calendar(const Calendar &source)
: UObject(source)
{
- fZone = 0;
+ fZone = NULL;
*this = source;
}
@@ -778,9 +786,8 @@ Calendar::operator=(const Calendar &right)
fLenient = right.fLenient;
fRepeatedWallTime = right.fRepeatedWallTime;
fSkippedWallTime = right.fSkippedWallTime;
- if (fZone != NULL) {
- delete fZone;
- }
+ delete fZone;
+ fZone = NULL;
if (right.fZone != NULL) {
fZone = right.fZone->clone();
}
@@ -1164,6 +1171,135 @@ Calendar::set(int32_t year, int32_t month, int32_t date, int32_t hour, int32_t m
}
// -------------------------------------
+// For now the full getRelatedYear implementation is here;
+// per #10752 move the non-default implementation to subclasses
+// (default implementation will do no year adjustment)
+
+static int32_t gregoYearFromIslamicStart(int32_t year) {
+ // ad hoc conversion, improve under #10752
+ // rough est for now, ok for grego 1846-2138,
+ // otherwise occasionally wrong (for 3% of years)
+ int cycle, offset, shift = 0;
+ if (year >= 1397) {
+ cycle = (year - 1397) / 67;
+ offset = (year - 1397) % 67;
+ shift = 2*cycle + ((offset >= 33)? 1: 0);
+ } else {
+ cycle = (year - 1396) / 67 - 1;
+ offset = -(year - 1396) % 67;
+ shift = 2*cycle + ((offset <= 33)? 1: 0);
+ }
+ return year + 579 - shift;
+}
+
+int32_t Calendar::getRelatedYear(UErrorCode &status) const
+{
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+ int32_t year = get(UCAL_EXTENDED_YEAR, status);
+ if (U_FAILURE(status)) {
+ return 0;
+ }
+ // modify for calendar type
+ ECalType type = getCalendarType(getType());
+ switch (type) {
+ case CALTYPE_PERSIAN:
+ year += 622; break;
+ case CALTYPE_HEBREW:
+ year -= 3760; break;
+ case CALTYPE_CHINESE:
+ year -= 2637; break;
+ case CALTYPE_INDIAN:
+ year += 79; break;
+ case CALTYPE_COPTIC:
+ year += 284; break;
+ case CALTYPE_ETHIOPIC:
+ year += 8; break;
+ case CALTYPE_ETHIOPIC_AMETE_ALEM:
+ year -=5492; break;
+ case CALTYPE_DANGI:
+ year -= 2333; break;
+ case CALTYPE_ISLAMIC_CIVIL:
+ case CALTYPE_ISLAMIC:
+ case CALTYPE_ISLAMIC_UMALQURA:
+ case CALTYPE_ISLAMIC_TBLA:
+ case CALTYPE_ISLAMIC_RGSA:
+ year = gregoYearFromIslamicStart(year); break;
+ default:
+ // CALTYPE_GREGORIAN
+ // CALTYPE_JAPANESE
+ // CALTYPE_BUDDHIST
+ // CALTYPE_ROC
+ // CALTYPE_ISO8601
+ // do nothing, EXTENDED_YEAR same as Gregorian
+ break;
+ }
+ return year;
+}
+
+// -------------------------------------
+// For now the full setRelatedYear implementation is here;
+// per #10752 move the non-default implementation to subclasses
+// (default implementation will do no year adjustment)
+
+static int32_t firstIslamicStartYearFromGrego(int32_t year) {
+ // ad hoc conversion, improve under #10752
+ // rough est for now, ok for grego 1846-2138,
+ // otherwise occasionally wrong (for 3% of years)
+ int cycle, offset, shift = 0;
+ if (year >= 1977) {
+ cycle = (year - 1977) / 65;
+ offset = (year - 1977) % 65;
+ shift = 2*cycle + ((offset >= 32)? 1: 0);
+ } else {
+ cycle = (year - 1976) / 65 - 1;
+ offset = -(year - 1976) % 65;
+ shift = 2*cycle + ((offset <= 32)? 1: 0);
+ }
+ return year - 579 + shift;
+}
+void Calendar::setRelatedYear(int32_t year)
+{
+ // modify for calendar type
+ ECalType type = getCalendarType(getType());
+ switch (type) {
+ case CALTYPE_PERSIAN:
+ year -= 622; break;
+ case CALTYPE_HEBREW:
+ year += 3760; break;
+ case CALTYPE_CHINESE:
+ year += 2637; break;
+ case CALTYPE_INDIAN:
+ year -= 79; break;
+ case CALTYPE_COPTIC:
+ year -= 284; break;
+ case CALTYPE_ETHIOPIC:
+ year -= 8; break;
+ case CALTYPE_ETHIOPIC_AMETE_ALEM:
+ year +=5492; break;
+ case CALTYPE_DANGI:
+ year += 2333; break;
+ case CALTYPE_ISLAMIC_CIVIL:
+ case CALTYPE_ISLAMIC:
+ case CALTYPE_ISLAMIC_UMALQURA:
+ case CALTYPE_ISLAMIC_TBLA:
+ case CALTYPE_ISLAMIC_RGSA:
+ year = firstIslamicStartYearFromGrego(year); break;
+ default:
+ // CALTYPE_GREGORIAN
+ // CALTYPE_JAPANESE
+ // CALTYPE_BUDDHIST
+ // CALTYPE_ROC
+ // CALTYPE_ISO8601
+ // do nothing, EXTENDED_YEAR same as Gregorian
+ break;
+ }
+ // set extended year
+ set(UCAL_EXTENDED_YEAR, year);
+}
+
+// -------------------------------------
void
Calendar::clear()
@@ -1894,10 +2030,10 @@ void Calendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status
// a computed amount of millis to the current millis. The only
// wrinkle is with DST (and/or a change to the zone's UTC offset, which
// we'll include with DST) -- for some fields, like the DAY_OF_MONTH,
- // we don't want the HOUR to shift due to changes in DST. If the
+ // we don't want the wall time to shift due to changes in DST. If the
// result of the add operation is to move from DST to Standard, or
// vice versa, we need to adjust by an hour forward or back,
- // respectively. For such fields we set keepHourInvariant to TRUE.
+ // respectively. For such fields we set keepWallTimeInvariant to TRUE.
// We only adjust the DST for fields larger than an hour. For
// fields smaller than an hour, we cannot adjust for DST without
@@ -1912,7 +2048,7 @@ void Calendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status
// <April 30>, rather than <April 31> => <May 1>.
double delta = amount; // delta in ms
- UBool keepHourInvariant = TRUE;
+ UBool keepWallTimeInvariant = TRUE;
switch (field) {
case UCAL_ERA:
@@ -1974,22 +2110,22 @@ void Calendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status
case UCAL_HOUR_OF_DAY:
case UCAL_HOUR:
delta *= kOneHour;
- keepHourInvariant = FALSE;
+ keepWallTimeInvariant = FALSE;
break;
case UCAL_MINUTE:
delta *= kOneMinute;
- keepHourInvariant = FALSE;
+ keepWallTimeInvariant = FALSE;
break;
case UCAL_SECOND:
delta *= kOneSecond;
- keepHourInvariant = FALSE;
+ keepWallTimeInvariant = FALSE;
break;
case UCAL_MILLISECOND:
case UCAL_MILLISECONDS_IN_DAY:
- keepHourInvariant = FALSE;
+ keepWallTimeInvariant = FALSE;
break;
default:
@@ -2003,41 +2139,61 @@ void Calendar::add(UCalendarDateFields field, int32_t amount, UErrorCode& status
// ") not supported");
}
- // In order to keep the hour invariant (for fields where this is
+ // In order to keep the wall time invariant (for fields where this is
// appropriate), check the combined DST & ZONE offset before and
// after the add() operation. If it changes, then adjust the millis
// to compensate.
int32_t prevOffset = 0;
- int32_t hour = 0;
- if (keepHourInvariant) {
+ int32_t prevWallTime = 0;
+ if (keepWallTimeInvariant) {
prevOffset = get(UCAL_DST_OFFSET, status) + get(UCAL_ZONE_OFFSET, status);
- hour = internalGet(UCAL_HOUR_OF_DAY);
+ prevWallTime = get(UCAL_MILLISECONDS_IN_DAY, status);
}
setTimeInMillis(getTimeInMillis(status) + delta, status);
- if (keepHourInvariant) {
- int32_t newOffset = get(UCAL_DST_OFFSET, status) + get(UCAL_ZONE_OFFSET, status);
- if (newOffset != prevOffset) {
- // We have done an hour-invariant adjustment but the
- // combined offset has changed. We adjust millis to keep
- // the hour constant. In cases such as midnight after
- // a DST change which occurs at midnight, there is the
- // danger of adjusting into a different day. To avoid
- // this we make the adjustment only if it actually
- // maintains the hour.
-
- // When the difference of the previous UTC offset and
- // the new UTC offset exceeds 1 full day, we do not want
- // to roll over/back the date. For now, this only happens
- // in Samoa (Pacific/Apia) on Dec 30, 2011. See ticket:9452.
- int32_t adjAmount = prevOffset - newOffset;
- adjAmount = adjAmount >= 0 ? adjAmount % (int32_t)kOneDay : -(-adjAmount % (int32_t)kOneDay);
- if (adjAmount != 0) {
- double t = internalGetTime();
- setTimeInMillis(t + adjAmount, status);
- if (get(UCAL_HOUR_OF_DAY, status) != hour) {
- setTimeInMillis(t, status);
+ if (keepWallTimeInvariant) {
+ int32_t newWallTime = get(UCAL_MILLISECONDS_IN_DAY, status);
+ if (newWallTime != prevWallTime) {
+ // There is at least one zone transition between the base
+ // time and the result time. As the result, wall time has
+ // changed.
+ UDate t = internalGetTime();
+ int32_t newOffset = get(UCAL_DST_OFFSET, status) + get(UCAL_ZONE_OFFSET, status);
+ if (newOffset != prevOffset) {
+ // When the difference of the previous UTC offset and
+ // the new UTC offset exceeds 1 full day, we do not want
+ // to roll over/back the date. For now, this only happens
+ // in Samoa (Pacific/Apia) on Dec 30, 2011. See ticket:9452.
+ int32_t adjAmount = prevOffset - newOffset;
+ adjAmount = adjAmount >= 0 ? adjAmount % (int32_t)kOneDay : -(-adjAmount % (int32_t)kOneDay);
+ if (adjAmount != 0) {
+ setTimeInMillis(t + adjAmount, status);
+ newWallTime = get(UCAL_MILLISECONDS_IN_DAY, status);
+ }
+ if (newWallTime != prevWallTime) {
+ // The result wall time or adjusted wall time was shifted because
+ // the target wall time does not exist on the result date.
+ switch (fSkippedWallTime) {
+ case UCAL_WALLTIME_FIRST:
+ if (adjAmount > 0) {
+ setTimeInMillis(t, status);
+ }
+ break;
+ case UCAL_WALLTIME_LAST:
+ if (adjAmount < 0) {
+ setTimeInMillis(t, status);
+ }
+ break;
+ case UCAL_WALLTIME_NEXT_VALID:
+ UDate tmpT = adjAmount > 0 ? internalGetTime() : t;
+ UDate immediatePrevTrans;
+ UBool hasTransition = getImmediatePreviousZoneTransition(tmpT, &immediatePrevTrans, status);
+ if (U_SUCCESS(status) && hasTransition) {
+ setTimeInMillis(immediatePrevTrans, status);
+ }
+ break;
+ }
}
}
}
@@ -2158,7 +2314,7 @@ Calendar::adoptTimeZone(TimeZone* zone)
if (zone == NULL) return;
// fZone should always be non-null
- if (fZone != NULL) delete fZone;
+ delete fZone;
fZone = zone;
// if the zone changes, we need to recompute the time fields
@@ -2177,6 +2333,7 @@ Calendar::setTimeZone(const TimeZone& zone)
const TimeZone&
Calendar::getTimeZone() const
{
+ U_ASSERT(fZone != NULL);
return *fZone;
}
@@ -2185,9 +2342,14 @@ Calendar::getTimeZone() const
TimeZone*
Calendar::orphanTimeZone()
{
- TimeZone *z = fZone;
// we let go of the time zone; the new time zone is the system default time zone
- fZone = TimeZone::createDefault();
+ TimeZone *defaultZone = TimeZone::createDefault();
+ if (defaultZone == NULL) {
+ // No error handling available. Must keep fZone non-NULL, there are many unchecked uses.
+ return NULL;
+ }
+ TimeZone *z = fZone;
+ fZone = defaultZone;
return z;
}
@@ -2306,11 +2468,11 @@ Calendar::getDayOfWeekType(UCalendarDaysOfWeek dayOfWeek, UErrorCode &status) co
status = U_ILLEGAL_ARGUMENT_ERROR;
return UCAL_WEEKDAY;
}
- if (fWeekendOnset == fWeekendCease) {
- if (dayOfWeek != fWeekendOnset)
- return UCAL_WEEKDAY;
- return (fWeekendOnsetMillis == 0) ? UCAL_WEEKEND : UCAL_WEEKEND_ONSET;
- }
+ if (fWeekendOnset == fWeekendCease) {
+ if (dayOfWeek != fWeekendOnset)
+ return UCAL_WEEKDAY;
+ return (fWeekendOnsetMillis == 0) ? UCAL_WEEKEND : UCAL_WEEKEND_ONSET;
+ }
if (fWeekendOnset < fWeekendCease) {
if (dayOfWeek < fWeekendOnset || dayOfWeek > fWeekendCease) {
return UCAL_WEEKDAY;
@@ -2818,22 +2980,10 @@ void Calendar::computeTime(UErrorCode& status) {
// Adjust time to the next valid wall clock time.
// At this point, tmpTime is on or after the zone offset transition causing
// the skipped time range.
-
- BasicTimeZone *btz = getBasicTimeZone();
- if (btz) {
- TimeZoneTransition transition;
- UBool hasTransition = btz->getPreviousTransition(tmpTime, TRUE, transition);
- if (hasTransition) {
- t = transition.getTime();
- } else {
- // Could not find any transitions.
- // Note: This should never happen.
- status = U_INTERNAL_PROGRAM_ERROR;
- }
- } else {
- // If not BasicTimeZone, return unsupported error for now.
- // TODO: We may support non-BasicTimeZone in future.
- status = U_UNSUPPORTED_ERROR;
+ UDate immediatePrevTransition;
+ UBool hasTransition = getImmediatePreviousZoneTransition(tmpTime, &immediatePrevTransition, status);
+ if (U_SUCCESS(status) && hasTransition) {
+ t = immediatePrevTransition;
}
}
} else {
@@ -2850,6 +3000,30 @@ void Calendar::computeTime(UErrorCode& status) {
}
/**
+ * Find the previous zone transtion near the given time.
+ */
+UBool Calendar::getImmediatePreviousZoneTransition(UDate base, UDate *transitionTime, UErrorCode& status) const {
+ BasicTimeZone *btz = getBasicTimeZone();
+ if (btz) {
+ TimeZoneTransition trans;
+ UBool hasTransition = btz->getPreviousTransition(base, TRUE, trans);
+ if (hasTransition) {
+ *transitionTime = trans.getTime();
+ return TRUE;
+ } else {
+ // Could not find any transitions.
+ // Note: This should never happen.
+ status = U_INTERNAL_PROGRAM_ERROR;
+ }
+ } else {
+ // If not BasicTimeZone, return unsupported error for now.
+ // TODO: We may support non-BasicTimeZone in future.
+ status = U_UNSUPPORTED_ERROR;
+ }
+ return FALSE;
+}
+
+/**
* Compute the milliseconds in the day from the fields. This is a
* value from 0 to 23:59:59.999 inclusive, unless fields are out of
* range, in which case it can be an arbitrary value. This value
@@ -3236,10 +3410,12 @@ int32_t Calendar::handleGetExtendedYearFromWeekFields(int32_t yearWoy, int32_t w
if (first < 0) {
first += 7;
}
- int32_t nextFirst = julianDayToDayOfWeek(nextJan1Start + 1) - firstDayOfWeek;
- if (nextFirst < 0) {
- nextFirst += 7;
- }
+
+ //// (nextFirst was not used below)
+ // int32_t nextFirst = julianDayToDayOfWeek(nextJan1Start + 1) - firstDayOfWeek;
+ // if (nextFirst < 0) {
+ // nextFirst += 7;
+ //}
int32_t minDays = getMinimalDaysInFirstWeek();
UBool jan1InPrevYear = FALSE; // January 1st in the year of WOY is the 1st week? (i.e. first week is < minimal )
« no previous file with comments | « source/i18n/bocsu.cpp ('k') | source/i18n/chnsecal.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698