ICU-2966 historical Olson time zone support; use getOffset(UDate) rather than getOffset(<fields>)
X-SVN-Rev: 12837
This commit is contained in:
parent
d8d88d2da4
commit
b3ee4d570c
@ -606,78 +606,26 @@ GregorianCalendar::yearLength() const
|
|||||||
* @see Calendar#complete
|
* @see Calendar#complete
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
GregorianCalendar::computeFields(UErrorCode& status)
|
GregorianCalendar::computeFields(UErrorCode& ec) {
|
||||||
{
|
if (U_FAILURE(ec)) {
|
||||||
if (U_FAILURE(status))
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int32_t rawOffset = getTimeZone().getRawOffset();
|
|
||||||
double localMillis = internalGetTime() + rawOffset;
|
|
||||||
|
|
||||||
/* Check for very extreme values -- millis near Long.MIN_VALUE or
|
|
||||||
* Long.MAX_VALUE. For these values, adding the zone offset can push
|
|
||||||
* the millis past MAX_VALUE to MIN_VALUE, or vice versa. This produces
|
|
||||||
* the undesirable effect that the time can wrap around at the ends,
|
|
||||||
* yielding, for example, a UDate(Long.MAX_VALUE) with a big BC year
|
|
||||||
* (should be AD). Handle this by pinning such values to Long.MIN_VALUE
|
|
||||||
* or Long.MAX_VALUE. - liu 8/11/98 bug 4149677 */
|
|
||||||
|
|
||||||
/* {sfb} 9/04/98
|
|
||||||
* Since in C++ we use doubles instead of longs for dates, there is
|
|
||||||
* an inherent loss of range in the calendar (because in Java you have all 64
|
|
||||||
* bits to store data, while in C++ you have only 52 bits of mantissa.
|
|
||||||
* So, I will pin to these (2^52 - 1) values instead */
|
|
||||||
|
|
||||||
if(internalGetTime() > 0 && localMillis < 0 && rawOffset > 0) {
|
|
||||||
localMillis = LATEST_SUPPORTED_MILLIS;
|
|
||||||
}
|
|
||||||
else if(internalGetTime() < 0 && localMillis > 0 && rawOffset < 0) {
|
|
||||||
localMillis = EARLIEST_SUPPORTED_MILLIS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Time to fields takes the wall millis (Standard or DST).
|
// Compute local wall millis
|
||||||
timeToFields(localMillis, FALSE, status);
|
double millis = internalGetTime();
|
||||||
|
int32_t rawOffset, dstOffset;
|
||||||
|
getTimeZone().getOffset(millis, FALSE, rawOffset, dstOffset, ec);
|
||||||
|
millis += rawOffset + dstOffset;
|
||||||
|
|
||||||
uint8_t era = (uint8_t) internalGetEra();
|
// Convert local wall millis to local wall fields.
|
||||||
int32_t year = internalGet(UCAL_YEAR);
|
timeToFields(millis, FALSE, ec);
|
||||||
int32_t month = internalGet(UCAL_MONTH);
|
|
||||||
int32_t date = internalGet(UCAL_DATE);
|
|
||||||
uint8_t dayOfWeek = (uint8_t) internalGet(UCAL_DAY_OF_WEEK);
|
|
||||||
|
|
||||||
double days = uprv_floor(localMillis / kOneDay);
|
// Compute time-of-day fields
|
||||||
int32_t millisInDay = (int32_t) (localMillis - (days * kOneDay));
|
double days = uprv_floor(millis / kOneDay);
|
||||||
U_ASSERT(millisInDay >= 0);
|
int32_t millisInDay = (int32_t) (millis - (days * kOneDay));
|
||||||
|
|
||||||
// Call getOffset() to get the TimeZone offset. The millisInDay value must
|
// Fill in all time-related fields based on millisInDay. Call
|
||||||
// be standard local millis.
|
// internalSet() so as not to perturb flags.
|
||||||
int32_t gregoYear = getGregorianYear(status);
|
|
||||||
int32_t dstOffset = getTimeZone().getOffset((gregoYear>0?AD:BC), getGregorianYear(status), month, date, dayOfWeek, millisInDay,
|
|
||||||
monthLength(month), status) - rawOffset;
|
|
||||||
if(U_FAILURE(status))
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Adjust our millisInDay for DST, if necessary.
|
|
||||||
millisInDay += dstOffset;
|
|
||||||
|
|
||||||
// If DST has pushed us into the next day, we must call timeToFields() again.
|
|
||||||
// This happens in DST between 12:00 am and 1:00 am every day. The call to
|
|
||||||
// timeToFields() will give the wrong day, since the Standard time is in the
|
|
||||||
// previous day.
|
|
||||||
if (millisInDay >= U_MILLIS_PER_DAY) {
|
|
||||||
UDate dstMillis = localMillis + dstOffset;
|
|
||||||
millisInDay -= U_MILLIS_PER_DAY;
|
|
||||||
// As above, check for and pin extreme values
|
|
||||||
if(localMillis > 0 && dstMillis < 0 && dstOffset > 0) {
|
|
||||||
dstMillis = LATEST_SUPPORTED_MILLIS;
|
|
||||||
}
|
|
||||||
else if(localMillis < 0 && dstMillis > 0 && dstOffset < 0) {
|
|
||||||
dstMillis = EARLIEST_SUPPORTED_MILLIS;
|
|
||||||
}
|
|
||||||
timeToFields(dstMillis, FALSE, status);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill in all time-related fields based on millisInDay. Call internalSet()
|
|
||||||
// so as not to perturb flags.
|
|
||||||
internalSet(UCAL_MILLISECOND, millisInDay % 1000);
|
internalSet(UCAL_MILLISECOND, millisInDay % 1000);
|
||||||
millisInDay /= 1000;
|
millisInDay /= 1000;
|
||||||
internalSet(UCAL_SECOND, millisInDay % 60);
|
internalSet(UCAL_SECOND, millisInDay % 60);
|
||||||
@ -888,75 +836,35 @@ GregorianCalendar::computeTime(UErrorCode& status)
|
|||||||
millisInDay *= 1000;
|
millisInDay *= 1000;
|
||||||
millisInDay += internalGet(UCAL_MILLISECOND); // now have millis
|
millisInDay += internalGet(UCAL_MILLISECOND); // now have millis
|
||||||
|
|
||||||
// Compute the time zone offset and DST offset. There are two potential
|
// Compute local wall millis
|
||||||
// ambiguities here. We'll assume a 2:00 am (wall time) switchover time
|
|
||||||
// for discussion purposes here.
|
|
||||||
// 1. The transition into DST. Here, a designated time of 2:00 am - 2:59 am
|
|
||||||
// can be in standard or in DST depending. However, 2:00 am is an invalid
|
|
||||||
// representation (the representation jumps from 1:59:59 am Std to 3:00:00 am DST).
|
|
||||||
// We assume standard time.
|
|
||||||
// 2. The transition out of DST. Here, a designated time of 1:00 am - 1:59 am
|
|
||||||
// can be in standard or DST. Both are valid representations (the rep
|
|
||||||
// jumps from 1:59:59 DST to 1:00:00 Std).
|
|
||||||
// Again, we assume standard time.
|
|
||||||
// We use the TimeZone object, unless the user has explicitly set the ZONE_OFFSET
|
|
||||||
// or DST_OFFSET fields; then we use those fields.
|
|
||||||
const TimeZone& zone = getTimeZone();
|
|
||||||
int32_t zoneOffset = (fStamp[UCAL_ZONE_OFFSET] >= kMinimumUserStamp)
|
|
||||||
/*isSet(ZONE_OFFSET) && userSetZoneOffset*/ ?
|
|
||||||
internalGet(UCAL_ZONE_OFFSET) : zone.getRawOffset();
|
|
||||||
|
|
||||||
// Now add date and millisInDay together, to make millis contain local wall
|
|
||||||
// millis, with no zone or DST adjustments
|
|
||||||
millis += millisInDay;
|
millis += millisInDay;
|
||||||
|
|
||||||
int32_t dstOffset = 0;
|
// Compute the time zone offset and DST offset. There are two
|
||||||
if (fStamp[UCAL_ZONE_OFFSET] >= kMinimumUserStamp
|
// potential ambiguities here. We'll assume a 2:00 am (wall time)
|
||||||
/*isSet(DST_OFFSET) && userSetDSTOffset*/)
|
// switchover time for discussion purposes here.
|
||||||
|
// 1. The transition into DST. Here, a designated time of 2:00 am
|
||||||
|
// - 2:59 am can be in standard or in DST depending. However,
|
||||||
|
// 2:00 am is an invalid representation (the representation
|
||||||
|
// jumps from 1:59:59 am Std to 3:00:00 am DST). We assume
|
||||||
|
// standard time.
|
||||||
|
// 2. The transition out of DST. Here, a designated time of 1:00 am
|
||||||
|
// - 1:59 am can be in standard or DST. Both are valid
|
||||||
|
// representations (the rep jumps from 1:59:59 DST to 1:00:00
|
||||||
|
// Std). Again, we assume standard time.
|
||||||
|
|
||||||
|
// We use the TimeZone object, unless the user has explicitly set
|
||||||
|
// the ZONE_OFFSET field; this signals us to use the fields for
|
||||||
|
// raw and DST offset.
|
||||||
|
int32_t rawOffset, dstOffset;
|
||||||
|
if (fStamp[UCAL_ZONE_OFFSET] >= kMinimumUserStamp) {
|
||||||
|
rawOffset = internalGet(UCAL_ZONE_OFFSET);
|
||||||
dstOffset = internalGet(UCAL_DST_OFFSET);
|
dstOffset = internalGet(UCAL_DST_OFFSET);
|
||||||
else {
|
} else {
|
||||||
/* Normalize the millisInDay to 0..ONE_DAY-1. If the millis is out
|
getTimeZone().getOffset(millis, TRUE, rawOffset, dstOffset, status);
|
||||||
* of range, then we must call timeToFields() to recompute our
|
|
||||||
* fields. */
|
|
||||||
int32_t normalizedMillisInDay;
|
|
||||||
floorDivide(millis, (int32_t)kOneDay, normalizedMillisInDay);
|
|
||||||
|
|
||||||
// We need to have the month, the day, and the day of the week.
|
|
||||||
// Calling timeToFields will compute the MONTH and DATE fields.
|
|
||||||
// If we're lenient then we need to call timeToFields() to
|
|
||||||
// normalize the year, month, and date numbers.
|
|
||||||
uint8_t dow;
|
|
||||||
if (isLenient() || fStamp[UCAL_MONTH] == kUnset || fStamp[UCAL_DATE] == kUnset
|
|
||||||
|| millisInDay != normalizedMillisInDay) {
|
|
||||||
timeToFields(millis, TRUE, status); // Use wall time; true == do quick computation
|
|
||||||
dow = (uint8_t) internalGet(UCAL_DAY_OF_WEEK); // DOW is computed by timeToFields
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// It's tempting to try to use DAY_OF_WEEK here, if it
|
|
||||||
// is set, but we CAN'T. Even if it's set, it might have
|
|
||||||
// been set wrong by the user. We should rely only on
|
|
||||||
// the Julian day number, which has been computed correctly
|
|
||||||
// using the disambiguation algorithm above. [LIU]
|
|
||||||
dow = julianDayToDayOfWeek(julianDay);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dstOffset = zone.getOffset((uint8_t)era,
|
// Convert local wall millis to GMT millis
|
||||||
internalGet(UCAL_YEAR),
|
internalSetTime(millis - rawOffset - dstOffset);
|
||||||
internalGet(UCAL_MONTH),
|
|
||||||
internalGet(UCAL_DATE),
|
|
||||||
dow,
|
|
||||||
normalizedMillisInDay, // local wall time
|
|
||||||
monthLength(internalGet(UCAL_MONTH)),
|
|
||||||
status) -
|
|
||||||
zoneOffset;
|
|
||||||
// Note: Because we pass in wall millisInDay, rather than
|
|
||||||
// standard millisInDay, we interpret "1:00 am" on the day
|
|
||||||
// of cessation of DST as "1:00 am Std" (assuming the time
|
|
||||||
// of cessation is 2:00 am).
|
|
||||||
}
|
|
||||||
|
|
||||||
// Store our final computed GMT time, with timezone adjustments.
|
|
||||||
internalSetTime(millis - zoneOffset - dstOffset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------
|
// -------------------------------------
|
||||||
|
Loading…
Reference in New Issue
Block a user