ICU-5624 64bit time zone transition support changes merged from Yoshito's work branch. Also updated time zone code to use region mapping data only from zoneinfo64 (so zoneFormatting data in supplementalData is no longer used).
X-SVN-Rev: 27644
This commit is contained in:
parent
1fa6d6b8fb
commit
d79344d97d
@ -23,4 +23,4 @@
|
||||
#
|
||||
|
||||
MISC_SOURCE = \
|
||||
zoneinfo.txt supplementalData.txt likelySubtags.txt plurals.txt numberingSystems.txt icuver.txt icustd.txt metaZones.txt windowsZones.txt keyTypeData.txt timezoneTypes.txt
|
||||
zoneinfo64.txt supplementalData.txt likelySubtags.txt plurals.txt numberingSystems.txt icuver.txt icustd.txt metaZones.txt windowsZones.txt keyTypeData.txt timezoneTypes.txt
|
||||
|
File diff suppressed because it is too large
Load Diff
3944
icu4c/source/data/misc/zoneinfo64.txt
Normal file
3944
icu4c/source/data/misc/zoneinfo64.txt
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
/*
|
||||
**********************************************************************
|
||||
* Copyright (c) 2003-2009, International Business Machines
|
||||
* Copyright (c) 2003-2010, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
**********************************************************************
|
||||
* Author: Alan Liu
|
||||
@ -21,6 +21,7 @@
|
||||
#include "uassert.h"
|
||||
#include "uvector.h"
|
||||
#include <float.h> // DBL_MAX
|
||||
#include "uresimp.h" // struct UResourceBundle
|
||||
|
||||
#ifdef U_DEBUG_TZ
|
||||
# include <stdio.h>
|
||||
@ -44,8 +45,32 @@ static void debug_tz_msg(const char *pat, ...)
|
||||
#define U_DEBUG_TZ_MSG(x)
|
||||
#endif
|
||||
|
||||
static UBool arrayEqual(const void *a1, const void *a2, int32_t size) {
|
||||
if (a1 == NULL && a2 == NULL) {
|
||||
return TRUE;
|
||||
}
|
||||
if (a1 != NULL && a2 == NULL || a1 == NULL && a2 != NULL) {
|
||||
return FALSE;
|
||||
}
|
||||
if (a1 == a2) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return (uprv_memcmp(a1, a2, size) == 0);
|
||||
}
|
||||
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
#define kTRANS "trans"
|
||||
#define kTRANSPRE32 "transPre32"
|
||||
#define kTRANSPOST32 "transPost32"
|
||||
#define kTYPEOFFSETS "typeOffsets"
|
||||
#define kTYPEMAP "typeMap"
|
||||
#define kLINKS "links"
|
||||
#define kFINALRULE "finalRule"
|
||||
#define kFINALRAW "finalRaw"
|
||||
#define kFINALYEAR "finalYear"
|
||||
|
||||
#define SECONDS_PER_DAY (24*60*60)
|
||||
|
||||
static const int32_t ZEROS[] = {0,0};
|
||||
@ -66,10 +91,15 @@ UOBJECT_DEFINE_RTTI_IMPLEMENTATION(OlsonTimeZone)
|
||||
* constructor fails so the resultant object is well-behaved.
|
||||
*/
|
||||
void OlsonTimeZone::constructEmpty() {
|
||||
transitionCount = 0;
|
||||
transitionCountPre32 = transitionCount32 = transitionCountPost32 = 0;
|
||||
transitionTimesPre32 = transitionTimes32 = transitionTimesPost32 = NULL;
|
||||
|
||||
typeMapData = NULL;
|
||||
|
||||
typeCount = 1;
|
||||
transitionTimes = typeOffsets = ZEROS;
|
||||
typeData = (const uint8_t*) ZEROS;
|
||||
typeOffsets = ZEROS;
|
||||
|
||||
finalZone = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -82,7 +112,7 @@ void OlsonTimeZone::constructEmpty() {
|
||||
OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top,
|
||||
const UResourceBundle* res,
|
||||
UErrorCode& ec) :
|
||||
finalYear(INT32_MAX), finalMillis(DBL_MAX), finalZone(0), transitionRulesInitialized(FALSE)
|
||||
finalZone(NULL), transitionRulesInitialized(FALSE)
|
||||
{
|
||||
clearTransitionRules();
|
||||
U_DEBUG_TZ_MSG(("OlsonTimeZone(%s)\n", ures_getKey((UResourceBundle*)res)));
|
||||
@ -94,121 +124,125 @@ OlsonTimeZone::OlsonTimeZone(const UResourceBundle* top,
|
||||
// // TODO remove nonconst casts below when ures_* API is fixed
|
||||
// setID(ures_getKey((UResourceBundle*) res)); // cast away const
|
||||
|
||||
// Size 1 is an alias TO another zone (int)
|
||||
// HOWEVER, the caller should dereference this and never pass it in to us
|
||||
// Size 3 is a purely historical zone (no final rules)
|
||||
// Size 4 is like size 3, but with an alias list at the end
|
||||
// Size 5 is a hybrid zone, with historical and final elements
|
||||
// Size 6 is like size 5, but with an alias list at the end
|
||||
int32_t size = ures_getSize(res);
|
||||
if (size < 3 || size > 6) {
|
||||
ec = U_INVALID_FORMAT_ERROR;
|
||||
}
|
||||
|
||||
// Transitions list may be empty
|
||||
int32_t i;
|
||||
UResourceBundle* r = ures_getByIndex(res, 0, NULL, &ec);
|
||||
transitionTimes = ures_getIntVector(r, &i, &ec);
|
||||
if ((i<0 || i>0x7FFF) && U_SUCCESS(ec)) {
|
||||
ec = U_INVALID_FORMAT_ERROR;
|
||||
}
|
||||
transitionCount = (int16_t) i;
|
||||
|
||||
// Type offsets list must be of even size, with size >= 2
|
||||
r = ures_getByIndex(res, 1, r, &ec);
|
||||
typeOffsets = ures_getIntVector(r, &i, &ec);
|
||||
if ((i<2 || i>0x7FFE || ((i&1)!=0)) && U_SUCCESS(ec)) {
|
||||
ec = U_INVALID_FORMAT_ERROR;
|
||||
}
|
||||
typeCount = (int16_t) i >> 1;
|
||||
|
||||
// Type data must be of the same size as the transitions list
|
||||
r = ures_getByIndex(res, 2, r, &ec);
|
||||
int32_t len;
|
||||
typeData = ures_getBinary(r, &len, &ec);
|
||||
ures_close(r);
|
||||
if (len != transitionCount && U_SUCCESS(ec)) {
|
||||
UResourceBundle r;
|
||||
ures_initStackObject(&r);
|
||||
|
||||
// Pre-32bit second transitions
|
||||
ures_getByKey(res, kTRANSPRE32, &r, &ec);
|
||||
transitionTimesPre32 = ures_getIntVector(&r, &len, &ec);
|
||||
transitionCountPre32 = len >> 1;
|
||||
if (ec == U_MISSING_RESOURCE_ERROR) {
|
||||
// No pre-32bit transitions
|
||||
transitionTimesPre32 = NULL;
|
||||
transitionCountPre32 = 0;
|
||||
ec = U_ZERO_ERROR;
|
||||
} else if (U_SUCCESS(ec) && (len < 0 || len > 0x7FFF || (len & 1) != 0) /* len must be even */) {
|
||||
ec = U_INVALID_FORMAT_ERROR;
|
||||
}
|
||||
|
||||
#if defined (U_DEBUG_TZ)
|
||||
U_DEBUG_TZ_MSG(("OlsonTimeZone(%s) - size = %d, typecount %d transitioncount %d - err %s\n", ures_getKey((UResourceBundle*)res), size, typeCount, transitionCount, u_errorName(ec)));
|
||||
if(U_SUCCESS(ec)) {
|
||||
int32_t jj;
|
||||
for(jj=0;jj<transitionCount;jj++) {
|
||||
int32_t year, month, dom, dow;
|
||||
double millis=0;
|
||||
double days = ClockMath::floorDivide(((double)transitionTimes[jj])*1000.0, (double)U_MILLIS_PER_DAY, millis);
|
||||
|
||||
Grego::dayToFields(days, year, month, dom, dow);
|
||||
U_DEBUG_TZ_MSG((" Transition %d: time %d (%04d.%02d.%02d+%.1fh), typedata%d\n", jj, transitionTimes[jj],
|
||||
year, month+1, dom, (millis/kOneHour), typeData[jj]));
|
||||
// U_DEBUG_TZ_MSG((" offset%d\n", typeOffsets[jj]));
|
||||
int16_t f = jj;
|
||||
f <<= 1;
|
||||
U_DEBUG_TZ_MSG((" offsets[%d+%d]=(%d+%d)=(%d==%d)\n", (int)f,(int)f+1,(int)typeOffsets[f],(int)typeOffsets[f+1],(int)zoneOffset(jj),
|
||||
(int)typeOffsets[f]+(int)typeOffsets[f+1]));
|
||||
}
|
||||
// 32bit second transitions
|
||||
ures_getByKey(res, kTRANS, &r, &ec);
|
||||
transitionTimes32 = ures_getIntVector(&r, &len, &ec);
|
||||
transitionCount32 = len;
|
||||
if (ec == U_MISSING_RESOURCE_ERROR) {
|
||||
// No 32bit transitions
|
||||
transitionTimes32 = NULL;
|
||||
transitionCount32 = 0;
|
||||
ec = U_ZERO_ERROR;
|
||||
} else if (U_SUCCESS(ec) && (len < 0 || len > 0x7FFF)) {
|
||||
ec = U_INVALID_FORMAT_ERROR;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Process final rule and data, if any
|
||||
if (size >= 5) {
|
||||
int32_t ruleidLen = 0;
|
||||
const UChar* idUStr = ures_getStringByIndex(res, 3, &ruleidLen, &ec);
|
||||
UnicodeString ruleid(TRUE, idUStr, ruleidLen);
|
||||
r = ures_getByIndex(res, 4, NULL, &ec);
|
||||
const int32_t* data = ures_getIntVector(r, &len, &ec);
|
||||
#if defined U_DEBUG_TZ
|
||||
const char *rKey = ures_getKey(r);
|
||||
const char *zKey = ures_getKey((UResourceBundle*)res);
|
||||
#endif
|
||||
ures_close(r);
|
||||
if (U_SUCCESS(ec)) {
|
||||
if (data != 0 && len == 2) {
|
||||
int32_t rawOffset = data[0] * U_MILLIS_PER_SECOND;
|
||||
// Subtract one from the actual final year; we
|
||||
// actually store final year - 1, and compare
|
||||
// using > rather than >=. This allows us to use
|
||||
// INT32_MAX as an exclusive upper limit for all
|
||||
// years, including INT32_MAX.
|
||||
U_ASSERT(data[1] > INT32_MIN);
|
||||
finalYear = data[1] - 1;
|
||||
// Also compute the millis for Jan 1, 0:00 GMT of the
|
||||
// finalYear. This reduces runtime computations.
|
||||
finalMillis = Grego::fieldsToDay(data[1], 0, 1) * U_MILLIS_PER_DAY;
|
||||
U_DEBUG_TZ_MSG(("zone%s|%s: {%d,%d}, finalYear%d, finalMillis%.1lf\n",
|
||||
zKey,rKey, data[0], data[1], finalYear, finalMillis));
|
||||
r = TimeZone::loadRule(top, ruleid, NULL, ec);
|
||||
if (U_SUCCESS(ec)) {
|
||||
// 3, 1, -1, 7200, 0, 9, -31, -1, 7200, 0, 3600
|
||||
data = ures_getIntVector(r, &len, &ec);
|
||||
if (U_SUCCESS(ec) && len == 11) {
|
||||
UnicodeString emptyStr;
|
||||
U_DEBUG_TZ_MSG(("zone%s, rule%s: {%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d}\n", zKey, ures_getKey(r),
|
||||
data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8], data[9], data[10]));
|
||||
finalZone = new SimpleTimeZone(rawOffset, emptyStr,
|
||||
(int8_t)data[0], (int8_t)data[1], (int8_t)data[2],
|
||||
data[3] * U_MILLIS_PER_SECOND,
|
||||
(SimpleTimeZone::TimeMode) data[4],
|
||||
(int8_t)data[5], (int8_t)data[6], (int8_t)data[7],
|
||||
data[8] * U_MILLIS_PER_SECOND,
|
||||
(SimpleTimeZone::TimeMode) data[9],
|
||||
data[10] * U_MILLIS_PER_SECOND, ec);
|
||||
// Make sure finalZone was created
|
||||
if (finalZone == NULL) {
|
||||
ec = U_MEMORY_ALLOCATION_ERROR;
|
||||
}
|
||||
} else {
|
||||
ec = U_INVALID_FORMAT_ERROR;
|
||||
}
|
||||
}
|
||||
ures_close(r);
|
||||
} else {
|
||||
ec = U_INVALID_FORMAT_ERROR;
|
||||
}
|
||||
// Post-32bit second transitions
|
||||
ures_getByKey(res, kTRANSPOST32, &r, &ec);
|
||||
transitionTimesPost32 = ures_getIntVector(&r, &len, &ec);
|
||||
transitionCountPost32 = len >> 1;
|
||||
if (ec == U_MISSING_RESOURCE_ERROR) {
|
||||
// No pre-32bit transitions
|
||||
transitionTimesPost32 = NULL;
|
||||
transitionCountPost32 = 0;
|
||||
ec = U_ZERO_ERROR;
|
||||
} else if (U_SUCCESS(ec) && (len < 0 || len > 0x7FFF || (len & 1) != 0) /* len must be even */) {
|
||||
ec = U_INVALID_FORMAT_ERROR;
|
||||
}
|
||||
|
||||
// Type offsets list must be of even size, with size >= 2
|
||||
ures_getByKey(res, kTYPEOFFSETS, &r, &ec);
|
||||
typeOffsets = ures_getIntVector(&r, &len, &ec);
|
||||
if (U_SUCCESS(ec) && (len < 2 || len > 0x7FFE || (len & 1) != 0)) {
|
||||
ec = U_INVALID_FORMAT_ERROR;
|
||||
}
|
||||
typeCount = (int16_t) len >> 1;
|
||||
|
||||
// Type map data must be of the same size as the transition count
|
||||
typeMapData = NULL;
|
||||
if (transitionCount() > 0) {
|
||||
ures_getByKey(res, kTYPEMAP, &r, &ec);
|
||||
typeMapData = ures_getBinary(&r, &len, &ec);
|
||||
if (ec == U_MISSING_RESOURCE_ERROR) {
|
||||
// no type mapping data
|
||||
ec = U_INVALID_FORMAT_ERROR;
|
||||
} else if (U_SUCCESS(ec) && len != transitionCount()) {
|
||||
ec = U_INVALID_FORMAT_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// Process final rule and data, if any
|
||||
const UChar *ruleIdUStr = ures_getStringByKey(res, kFINALRULE, &len, &ec);
|
||||
ures_getByKey(res, kFINALRAW, &r, &ec);
|
||||
int32_t ruleRaw = ures_getInt(&r, &ec);
|
||||
ures_getByKey(res, kFINALYEAR, &r, &ec);
|
||||
int32_t ruleYear = ures_getInt(&r, &ec);
|
||||
if (U_SUCCESS(ec)) {
|
||||
UnicodeString ruleID(TRUE, ruleIdUStr, len);
|
||||
UResourceBundle *rule = TimeZone::loadRule(top, ruleID, NULL, ec);
|
||||
const int32_t *ruleData = ures_getIntVector(rule, &len, &ec);
|
||||
if (U_SUCCESS(ec) && len == 11) {
|
||||
UnicodeString emptyStr;
|
||||
finalZone = new SimpleTimeZone(
|
||||
ruleRaw * U_MILLIS_PER_SECOND,
|
||||
emptyStr,
|
||||
(int8_t)ruleData[0], (int8_t)ruleData[1], (int8_t)ruleData[2],
|
||||
ruleData[3] * U_MILLIS_PER_SECOND,
|
||||
(SimpleTimeZone::TimeMode) ruleData[4],
|
||||
(int8_t)ruleData[5], (int8_t)ruleData[6], (int8_t)ruleData[7],
|
||||
ruleData[8] * U_MILLIS_PER_SECOND,
|
||||
(SimpleTimeZone::TimeMode) ruleData[9],
|
||||
ruleData[10] * U_MILLIS_PER_SECOND, ec);
|
||||
if (finalZone == NULL) {
|
||||
ec = U_MEMORY_ALLOCATION_ERROR;
|
||||
} else {
|
||||
finalStartYear = ruleYear;
|
||||
|
||||
// Note: Setting finalStartYear to the finalZone is problematic. When a date is around
|
||||
// year boundary, SimpleTimeZone may return false result when DST is observed at the
|
||||
// beginning of year. We could apply safe margin (day or two), but when one of recurrent
|
||||
// rules falls around year boundary, it could return false result. Without setting the
|
||||
// start year, finalZone works fine around the year boundary of the start year.
|
||||
|
||||
// finalZone->setStartYear(finalStartYear);
|
||||
|
||||
|
||||
// Compute the millis for Jan 1, 0:00 GMT of the finalYear
|
||||
|
||||
// Note: finalStartMillis is used for detecting either if
|
||||
// historic transition data or finalZone to be used. In an
|
||||
// extreme edge case - for example, two transitions fall into
|
||||
// small windows of time around the year boundary, this may
|
||||
// result incorrect offset computation. But I think it will
|
||||
// never happen practically. Yoshito - Feb 20, 2010
|
||||
finalStartMillis = Grego::fieldsToDay(finalStartYear, 0, 1) * U_MILLIS_PER_DAY;
|
||||
}
|
||||
} else {
|
||||
ec = U_INVALID_FORMAT_ERROR;
|
||||
}
|
||||
ures_close(rule);
|
||||
} else if (ec == U_MISSING_RESOURCE_ERROR) {
|
||||
// No final zone
|
||||
ec = U_ZERO_ERROR;
|
||||
}
|
||||
ures_close(&r);
|
||||
}
|
||||
|
||||
if (U_FAILURE(ec)) {
|
||||
@ -228,17 +262,27 @@ OlsonTimeZone::OlsonTimeZone(const OlsonTimeZone& other) :
|
||||
* Assignment operator
|
||||
*/
|
||||
OlsonTimeZone& OlsonTimeZone::operator=(const OlsonTimeZone& other) {
|
||||
transitionCount = other.transitionCount;
|
||||
transitionTimesPre32 = other.transitionTimesPre32;
|
||||
transitionTimes32 = other.transitionTimes32;
|
||||
transitionTimesPost32 = other.transitionTimesPost32;
|
||||
|
||||
transitionCountPre32 = other.transitionCountPre32;
|
||||
transitionCount32 = other.transitionCount32;
|
||||
transitionCountPost32 = other.transitionCountPost32;
|
||||
|
||||
typeCount = other.typeCount;
|
||||
transitionTimes = other.transitionTimes;
|
||||
typeOffsets = other.typeOffsets;
|
||||
typeData = other.typeData;
|
||||
finalYear = other.finalYear;
|
||||
finalMillis = other.finalMillis;
|
||||
typeMapData = other.typeMapData;
|
||||
|
||||
delete finalZone;
|
||||
finalZone = (other.finalZone != 0) ?
|
||||
(SimpleTimeZone*) other.finalZone->clone() : 0;
|
||||
|
||||
finalStartYear = other.finalStartYear;
|
||||
finalStartMillis = other.finalStartMillis;
|
||||
|
||||
clearTransitionRules();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -315,8 +359,7 @@ int32_t OlsonTimeZone::getOffset(uint8_t era, int32_t year, int32_t month,
|
||||
year = -year;
|
||||
}
|
||||
|
||||
if (year > finalYear) { // [sic] >, not >=; see above
|
||||
U_ASSERT(finalZone != 0);
|
||||
if (finalZone != NULL && year >= finalStartYear) {
|
||||
return finalZone->getOffset(era, year, month, dom, dow,
|
||||
millis, monthLength, ec);
|
||||
}
|
||||
@ -336,10 +379,7 @@ void OlsonTimeZone::getOffset(UDate date, UBool local, int32_t& rawoff,
|
||||
if (U_FAILURE(ec)) {
|
||||
return;
|
||||
}
|
||||
// The check against finalMillis will suffice most of the time, except
|
||||
// for the case in which finalMillis == DBL_MAX, date == DBL_MAX,
|
||||
// and finalZone == 0. For this case we add "&& finalZone != 0".
|
||||
if (date >= finalMillis && finalZone != 0) {
|
||||
if (finalZone != NULL && date >= finalStartMillis) {
|
||||
finalZone->getOffset(date, local, rawoff, dstoff, ec);
|
||||
} else {
|
||||
getHistoricalOffset(date, local, kFormer, kLatter, rawoff, dstoff);
|
||||
@ -352,7 +392,7 @@ OlsonTimeZone::getOffsetFromLocal(UDate date, int32_t nonExistingTimeOpt, int32_
|
||||
if (U_FAILURE(ec)) {
|
||||
return;
|
||||
}
|
||||
if (date >= finalMillis && finalZone != 0) {
|
||||
if (finalZone != NULL && date >= finalStartMillis) {
|
||||
finalZone->getOffsetFromLocal(date, nonExistingTimeOpt, duplicatedTimeOpt, rawoff, dstoff, ec);
|
||||
} else {
|
||||
getHistoricalOffset(date, TRUE, nonExistingTimeOpt, duplicatedTimeOpt, rawoff, dstoff);
|
||||
@ -393,6 +433,25 @@ void printTime(double ms) {
|
||||
}
|
||||
#endif
|
||||
|
||||
int64_t
|
||||
OlsonTimeZone::transitionTimeInSeconds(int16_t transIdx) const {
|
||||
U_ASSERT(transIdx >= 0 && transIdx < transitionCount());
|
||||
|
||||
if (transIdx < transitionCountPre32) {
|
||||
return (((int64_t)((uint32_t)transitionTimesPre32[transIdx << 1])) << 32)
|
||||
| ((int64_t)((uint32_t)transitionTimesPre32[(transIdx << 1) + 1]));
|
||||
}
|
||||
|
||||
transIdx -= transitionCountPre32;
|
||||
if (transIdx < transitionCount32) {
|
||||
return (int64_t)transitionTimes32[transIdx];
|
||||
}
|
||||
|
||||
transIdx -= transitionCount32;
|
||||
return (((int64_t)((uint32_t)transitionTimesPost32[transIdx << 1])) << 32)
|
||||
| ((int64_t)((uint32_t)transitionTimesPost32[(transIdx << 1) + 1]));
|
||||
}
|
||||
|
||||
void
|
||||
OlsonTimeZone::getHistoricalOffset(UDate date, UBool local,
|
||||
int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt,
|
||||
@ -402,94 +461,75 @@ OlsonTimeZone::getHistoricalOffset(UDate date, UBool local,
|
||||
#if defined U_DEBUG_TZ
|
||||
printTime(date*1000.0);
|
||||
#endif
|
||||
if (transitionCount != 0) {
|
||||
int16_t transCount = transitionCount();
|
||||
|
||||
if (transCount > 0) {
|
||||
double sec = uprv_floor(date / U_MILLIS_PER_SECOND);
|
||||
// Linear search from the end is the fastest approach, since
|
||||
// most lookups will happen at/near the end.
|
||||
int16_t i;
|
||||
for (i = transitionCount - 1; i > 0; --i) {
|
||||
int32_t transition = transitionTimes[i];
|
||||
if (!local && sec < transitionTimeInSeconds(0)) {
|
||||
// Before the first transition time
|
||||
rawoff = initialRawOffset() * U_MILLIS_PER_SECOND;
|
||||
dstoff = initialDstOffset() * U_MILLIS_PER_SECOND;
|
||||
} else {
|
||||
// Linear search from the end is the fastest approach, since
|
||||
// most lookups will happen at/near the end.
|
||||
int16_t transIdx;
|
||||
for (transIdx = transCount - 1; transIdx >= 0; transIdx--) {
|
||||
int64_t transition = transitionTimeInSeconds(transIdx);
|
||||
|
||||
if (local) {
|
||||
int32_t offsetBefore = zoneOffset(typeData[i-1]);
|
||||
UBool dstBefore = dstOffset(typeData[i-1]) != 0;
|
||||
if (local) {
|
||||
int32_t offsetBefore = zoneOffsetAt(transIdx - 1);
|
||||
UBool dstBefore = dstOffsetAt(transIdx - 1) != 0;
|
||||
|
||||
int32_t offsetAfter = zoneOffset(typeData[i]);
|
||||
UBool dstAfter = dstOffset(typeData[i]) != 0;
|
||||
int32_t offsetAfter = zoneOffsetAt(transIdx);
|
||||
UBool dstAfter = dstOffsetAt(transIdx) != 0;
|
||||
|
||||
UBool dstToStd = dstBefore && !dstAfter;
|
||||
UBool stdToDst = !dstBefore && dstAfter;
|
||||
|
||||
if (offsetAfter - offsetBefore >= 0) {
|
||||
// Positive transition, which makes a non-existing local time range
|
||||
if (((NonExistingTimeOpt & kStdDstMask) == kStandard && dstToStd)
|
||||
|| ((NonExistingTimeOpt & kStdDstMask) == kDaylight && stdToDst)) {
|
||||
transition += offsetBefore;
|
||||
} else if (((NonExistingTimeOpt & kStdDstMask) == kStandard && stdToDst)
|
||||
|| ((NonExistingTimeOpt & kStdDstMask) == kDaylight && dstToStd)) {
|
||||
transition += offsetAfter;
|
||||
} else if ((NonExistingTimeOpt & kFormerLatterMask) == kLatter) {
|
||||
transition += offsetBefore;
|
||||
UBool dstToStd = dstBefore && !dstAfter;
|
||||
UBool stdToDst = !dstBefore && dstAfter;
|
||||
|
||||
if (offsetAfter - offsetBefore >= 0) {
|
||||
// Positive transition, which makes a non-existing local time range
|
||||
if (((NonExistingTimeOpt & kStdDstMask) == kStandard && dstToStd)
|
||||
|| ((NonExistingTimeOpt & kStdDstMask) == kDaylight && stdToDst)) {
|
||||
transition += offsetBefore;
|
||||
} else if (((NonExistingTimeOpt & kStdDstMask) == kStandard && stdToDst)
|
||||
|| ((NonExistingTimeOpt & kStdDstMask) == kDaylight && dstToStd)) {
|
||||
transition += offsetAfter;
|
||||
} else if ((NonExistingTimeOpt & kFormerLatterMask) == kLatter) {
|
||||
transition += offsetBefore;
|
||||
} else {
|
||||
// Interprets the time with rule before the transition,
|
||||
// default for non-existing time range
|
||||
transition += offsetAfter;
|
||||
}
|
||||
} else {
|
||||
// Interprets the time with rule before the transition,
|
||||
// default for non-existing time range
|
||||
transition += offsetAfter;
|
||||
}
|
||||
} else {
|
||||
// Negative transition, which makes a duplicated local time range
|
||||
if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && dstToStd)
|
||||
|| ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && stdToDst)) {
|
||||
transition += offsetAfter;
|
||||
} else if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && stdToDst)
|
||||
|| ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && dstToStd)) {
|
||||
transition += offsetBefore;
|
||||
} else if ((DuplicatedTimeOpt & kFormerLatterMask) == kFormer) {
|
||||
transition += offsetBefore;
|
||||
} else {
|
||||
// Interprets the time with rule after the transition,
|
||||
// default for duplicated local time range
|
||||
transition += offsetAfter;
|
||||
// Negative transition, which makes a duplicated local time range
|
||||
if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && dstToStd)
|
||||
|| ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && stdToDst)) {
|
||||
transition += offsetAfter;
|
||||
} else if (((DuplicatedTimeOpt & kStdDstMask) == kStandard && stdToDst)
|
||||
|| ((DuplicatedTimeOpt & kStdDstMask) == kDaylight && dstToStd)) {
|
||||
transition += offsetBefore;
|
||||
} else if ((DuplicatedTimeOpt & kFormerLatterMask) == kFormer) {
|
||||
transition += offsetBefore;
|
||||
} else {
|
||||
// Interprets the time with rule after the transition,
|
||||
// default for duplicated local time range
|
||||
transition += offsetAfter;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (sec >= transition) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (sec >= transition) {
|
||||
U_DEBUG_TZ_MSG(("Found@%d: time=%.1f, localtransition=%d (orig %d) dz %d\n", i, sec, transition, transitionTimes[i],
|
||||
zoneOffset(typeData[i-1])));
|
||||
#if defined U_DEBUG_TZ
|
||||
printTime(transition*1000.0);
|
||||
printTime(transitionTimes[i]*1000.0);
|
||||
#endif
|
||||
break;
|
||||
} else {
|
||||
U_DEBUG_TZ_MSG(("miss@%d: time=%.1f, localtransition=%d (orig %d) dz %d\n", i, sec, transition, transitionTimes[i],
|
||||
zoneOffset(typeData[i-1])));
|
||||
#if defined U_DEBUG_TZ
|
||||
printTime(transition*1000.0);
|
||||
printTime(transitionTimes[i]*1000.0);
|
||||
#endif
|
||||
}
|
||||
// transIdx could be -1 when local=true
|
||||
rawoff = rawOffsetAt(transIdx) * U_MILLIS_PER_SECOND;
|
||||
dstoff = dstOffsetAt(transIdx) * U_MILLIS_PER_SECOND;
|
||||
}
|
||||
|
||||
U_ASSERT(i>=0 && i<transitionCount);
|
||||
|
||||
// Check invariants for GMT times; if these pass for GMT times
|
||||
// the local logic should be working too.
|
||||
U_ASSERT(local || sec < transitionTimes[0] || sec >= transitionTimes[i]);
|
||||
U_ASSERT(local || i == transitionCount-1 || sec < transitionTimes[i+1]);
|
||||
|
||||
U_DEBUG_TZ_MSG(("getHistoricalOffset(%.1f, %s, %d, %d, raw, dst) - trans %d\n",
|
||||
date, local?"T":"F", NonExistingTimeOpt, DuplicatedTimeOpt, i));
|
||||
|
||||
// Since ICU tzdata 2007c, the first transition data is actually not a
|
||||
// transition, but used for representing the initial offset. So the code
|
||||
// below works even if i == 0.
|
||||
int16_t index = typeData[i];
|
||||
rawoff = rawOffset(index) * U_MILLIS_PER_SECOND;
|
||||
dstoff = dstOffset(index) * U_MILLIS_PER_SECOND;
|
||||
} else {
|
||||
// No transitions, single pair of offsets only
|
||||
rawoff = rawOffset(0) * U_MILLIS_PER_SECOND;
|
||||
dstoff = dstOffset(0) * U_MILLIS_PER_SECOND;
|
||||
rawoff = initialRawOffset() * U_MILLIS_PER_SECOND;
|
||||
dstoff = initialDstOffset() * U_MILLIS_PER_SECOND;
|
||||
}
|
||||
U_DEBUG_TZ_MSG(("getHistoricalOffset(%.1f, %s, %d, %d, raw, dst) - raw=%d, dst=%d\n",
|
||||
date, local?"T":"F", NonExistingTimeOpt, DuplicatedTimeOpt, rawoff, dstoff));
|
||||
@ -505,29 +545,27 @@ UBool OlsonTimeZone::useDaylightTime() const {
|
||||
// DST is in use in the current year (at any point in the year)
|
||||
// and returns TRUE if so.
|
||||
|
||||
int32_t days = (int32_t)ClockMath::floorDivide(uprv_getUTCtime(), (double)U_MILLIS_PER_DAY); // epoch days
|
||||
|
||||
int32_t year, month, dom, dow;
|
||||
|
||||
Grego::dayToFields(days, year, month, dom, dow);
|
||||
|
||||
if (year > finalYear) { // [sic] >, not >=; see above
|
||||
U_ASSERT(finalZone != 0 && finalZone->useDaylightTime());
|
||||
return TRUE;
|
||||
UDate current = uprv_getUTCtime();
|
||||
if (finalZone != NULL && current >= finalStartMillis) {
|
||||
return finalZone->useDaylightTime();
|
||||
}
|
||||
|
||||
int32_t year, month, dom, dow, doy, mid;
|
||||
Grego::timeToFields(current, year, month, dom, dow, doy, mid);
|
||||
|
||||
// Find start of this year, and start of next year
|
||||
int32_t start = (int32_t) Grego::fieldsToDay(year, 0, 1) * SECONDS_PER_DAY;
|
||||
int32_t limit = (int32_t) Grego::fieldsToDay(year+1, 0, 1) * SECONDS_PER_DAY;
|
||||
double start = Grego::fieldsToDay(year, 0, 1) * SECONDS_PER_DAY;
|
||||
double limit = Grego::fieldsToDay(year+1, 0, 1) * SECONDS_PER_DAY;
|
||||
|
||||
// Return TRUE if DST is observed at any time during the current
|
||||
// year.
|
||||
for (int16_t i=0; i<transitionCount; ++i) {
|
||||
if (transitionTimes[i] >= limit) {
|
||||
for (int16_t i = 0; i < transitionCount(); ++i) {
|
||||
double transition = transitionTime(i);
|
||||
if (transition >= limit) {
|
||||
break;
|
||||
}
|
||||
if ((transitionTimes[i] >= start && dstOffset(typeData[i]) != 0)
|
||||
|| (transitionTimes[i] > start && i > 0 && dstOffset(typeData[i - 1]) != 0)) {
|
||||
if ((transition >= start && dstOffsetAt(i) != 0)
|
||||
|| (transition > start && dstOffsetAt(i - 1) != 0)) {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
@ -535,7 +573,7 @@ UBool OlsonTimeZone::useDaylightTime() const {
|
||||
}
|
||||
int32_t
|
||||
OlsonTimeZone::getDSTSavings() const{
|
||||
if(finalZone!=NULL){
|
||||
if (finalZone != NULL){
|
||||
return finalZone->getDSTSavings();
|
||||
}
|
||||
return TimeZone::getDSTSavings();
|
||||
@ -559,29 +597,39 @@ OlsonTimeZone::hasSameRules(const TimeZone &other) const {
|
||||
}
|
||||
const OlsonTimeZone* z = (const OlsonTimeZone*) &other;
|
||||
|
||||
// [sic] pointer comparison: typeData points into
|
||||
// [sic] pointer comparison: typeMapData points into
|
||||
// memory-mapped or DLL space, so if two zones have the same
|
||||
// pointer, they are equal.
|
||||
if (typeData == z->typeData) {
|
||||
if (typeMapData == z->typeMapData) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// If the pointers are not equal, the zones may still
|
||||
// be equal if their rules and transitions are equal
|
||||
// If the pointers are not equal, the zones may still
|
||||
// be equal if their rules and transitions are equal
|
||||
if (finalZone == NULL && z->finalZone != NULL
|
||||
|| finalZone != NULL && z->finalZone == NULL
|
||||
|| finalZone != NULL && z->finalZone != NULL && *finalZone != *z->finalZone) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (finalZone != NULL) {
|
||||
if (finalStartYear != z->finalStartYear || finalStartMillis != z->finalStartMillis) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
if (typeCount != z->typeCount
|
||||
|| transitionCountPre32 != z->transitionCountPre32
|
||||
|| transitionCount32 != z->transitionCount32
|
||||
|| transitionCountPost32 != z->transitionCountPost32) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return
|
||||
(finalYear == z->finalYear &&
|
||||
// Don't compare finalMillis; if finalYear is ==, so is finalMillis
|
||||
((finalZone == 0 && z->finalZone == 0) ||
|
||||
(finalZone != 0 && z->finalZone != 0 && *finalZone == *z->finalZone)) &&
|
||||
|
||||
transitionCount == z->transitionCount &&
|
||||
typeCount == z->typeCount &&
|
||||
uprv_memcmp(transitionTimes, z->transitionTimes,
|
||||
sizeof(transitionTimes[0]) * transitionCount) == 0 &&
|
||||
uprv_memcmp(typeOffsets, z->typeOffsets,
|
||||
(sizeof(typeOffsets[0]) * typeCount) << 1) == 0 &&
|
||||
uprv_memcmp(typeData, z->typeData,
|
||||
(sizeof(typeData[0]) * typeCount)) == 0);
|
||||
arrayEqual(transitionTimesPre32, z->transitionTimesPre32, sizeof(transitionTimesPre32[0]) * transitionCountPre32 << 1)
|
||||
&& arrayEqual(transitionTimes32, z->transitionTimes32, sizeof(transitionTimes32[0]) * transitionCount32)
|
||||
&& arrayEqual(transitionTimesPost32, z->transitionTimesPost32, sizeof(transitionTimesPost32[0]) * transitionCountPost32 << 1)
|
||||
&& arrayEqual(typeOffsets, z->typeOffsets, sizeof(typeOffsets[0]) * typeCount << 1)
|
||||
&& arrayEqual(typeMapData, z->typeMapData, sizeof(typeMapData[0]) * transitionCount());
|
||||
}
|
||||
|
||||
void
|
||||
@ -637,36 +685,37 @@ OlsonTimeZone::initTransitionRules(UErrorCode& status) {
|
||||
UnicodeString dstName = tzid + UNICODE_STRING_SIMPLE("(DST)");
|
||||
|
||||
int32_t raw, dst;
|
||||
if (transitionCount > 0) {
|
||||
|
||||
// Create initial rule
|
||||
raw = initialRawOffset() * U_MILLIS_PER_SECOND;
|
||||
dst = initialDstOffset() * U_MILLIS_PER_SECOND;
|
||||
initialRule = new InitialTimeZoneRule((dst == 0 ? stdName : dstName), raw, dst);
|
||||
// Check to make sure initialRule was created
|
||||
if (initialRule == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
deleteTransitionRules();
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t transCount = transitionCount();
|
||||
if (transCount > 0) {
|
||||
int16_t transitionIdx, typeIdx;
|
||||
|
||||
// Note: Since 2007c, the very first transition data is a dummy entry
|
||||
// added for resolving a offset calculation problem.
|
||||
|
||||
// Create initial rule
|
||||
typeIdx = (int16_t)typeData[0]; // initial type
|
||||
raw = rawOffset(typeIdx) * U_MILLIS_PER_SECOND;
|
||||
dst = dstOffset(typeIdx) * U_MILLIS_PER_SECOND;
|
||||
initialRule = new InitialTimeZoneRule((dst == 0 ? stdName : dstName), raw, dst);
|
||||
// Check to make sure initialRule was created
|
||||
if (initialRule == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
deleteTransitionRules();
|
||||
return;
|
||||
}
|
||||
|
||||
// We probably no longer need to check the first "real" transition
|
||||
// here, because the new tzcode remove such transitions already.
|
||||
// For now, keeping this code for just in case. Feb 19, 2010 Yoshito
|
||||
firstTZTransitionIdx = 0;
|
||||
for (transitionIdx = 1; transitionIdx < transitionCount; transitionIdx++) {
|
||||
firstTZTransitionIdx++;
|
||||
if (typeIdx != (int16_t)typeData[transitionIdx]) {
|
||||
for (transitionIdx = 0; transitionIdx < transCount; transitionIdx++) {
|
||||
if (typeMapData[transitionIdx] != 0) { // type 0 is the initial type
|
||||
break;
|
||||
}
|
||||
firstTZTransitionIdx++;
|
||||
}
|
||||
if (transitionIdx == transitionCount) {
|
||||
if (transitionIdx == transCount) {
|
||||
// Actually no transitions...
|
||||
} else {
|
||||
// Build historic rule array
|
||||
UDate* times = (UDate*)uprv_malloc(sizeof(UDate)*transitionCount); /* large enough to store all transition times */
|
||||
UDate* times = (UDate*)uprv_malloc(sizeof(UDate)*transCount); /* large enough to store all transition times */
|
||||
if (times == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
deleteTransitionRules();
|
||||
@ -675,10 +724,10 @@ OlsonTimeZone::initTransitionRules(UErrorCode& status) {
|
||||
for (typeIdx = 0; typeIdx < typeCount; typeIdx++) {
|
||||
// Gather all start times for each pair of offsets
|
||||
int32_t nTimes = 0;
|
||||
for (transitionIdx = firstTZTransitionIdx; transitionIdx < transitionCount; transitionIdx++) {
|
||||
if (typeIdx == (int16_t)typeData[transitionIdx]) {
|
||||
UDate tt = ((UDate)transitionTimes[transitionIdx]) * U_MILLIS_PER_SECOND;
|
||||
if (tt < finalMillis) {
|
||||
for (transitionIdx = firstTZTransitionIdx; transitionIdx < transCount; transitionIdx++) {
|
||||
if (typeIdx == (int16_t)typeMapData[transitionIdx]) {
|
||||
UDate tt = (UDate)transitionTime(transitionIdx);
|
||||
if (finalZone == NULL || tt <= finalStartMillis) {
|
||||
// Exclude transitions after finalMillis
|
||||
times[nTimes++] = tt;
|
||||
}
|
||||
@ -686,8 +735,8 @@ OlsonTimeZone::initTransitionRules(UErrorCode& status) {
|
||||
}
|
||||
if (nTimes > 0) {
|
||||
// Create a TimeArrayTimeZoneRule
|
||||
raw = rawOffset(typeIdx) * U_MILLIS_PER_SECOND;
|
||||
dst = dstOffset(typeIdx) * U_MILLIS_PER_SECOND;
|
||||
raw = typeOffsets[typeIdx << 1] * U_MILLIS_PER_SECOND;
|
||||
dst = typeOffsets[(typeIdx << 1) + 1] * U_MILLIS_PER_SECOND;
|
||||
if (historicRules == NULL) {
|
||||
historicRuleCount = typeCount;
|
||||
historicRules = (TimeArrayTimeZoneRule**)uprv_malloc(sizeof(TimeArrayTimeZoneRule*)*historicRuleCount);
|
||||
@ -715,8 +764,8 @@ OlsonTimeZone::initTransitionRules(UErrorCode& status) {
|
||||
uprv_free(times);
|
||||
|
||||
// Create initial transition
|
||||
typeIdx = (int16_t)typeData[firstTZTransitionIdx];
|
||||
firstTZTransition = new TimeZoneTransition(((UDate)transitionTimes[firstTZTransitionIdx]) * U_MILLIS_PER_SECOND,
|
||||
typeIdx = (int16_t)typeMapData[firstTZTransitionIdx];
|
||||
firstTZTransition = new TimeZoneTransition((UDate)transitionTime(firstTZTransitionIdx),
|
||||
*initialRule, *historicRules[typeIdx]);
|
||||
// Check to make sure firstTZTransition was created.
|
||||
if (firstTZTransition == NULL) {
|
||||
@ -726,30 +775,18 @@ OlsonTimeZone::initTransitionRules(UErrorCode& status) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (initialRule == NULL) {
|
||||
// No historic transitions
|
||||
raw = rawOffset(0) * U_MILLIS_PER_SECOND;
|
||||
dst = dstOffset(0) * U_MILLIS_PER_SECOND;
|
||||
initialRule = new InitialTimeZoneRule((dst == 0 ? stdName : dstName), raw, dst);
|
||||
// Check to make sure initialRule was created.
|
||||
if (initialRule == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
deleteTransitionRules();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (finalZone != NULL) {
|
||||
// Get the first occurence of final rule starts
|
||||
UDate startTime = (UDate)finalMillis;
|
||||
UDate startTime = (UDate)finalStartMillis;
|
||||
TimeZoneRule *firstFinalRule = NULL;
|
||||
|
||||
if (finalZone->useDaylightTime()) {
|
||||
/*
|
||||
* Note: When an OlsonTimeZone is constructed, we should set the final year
|
||||
* as the start year of finalZone. However, the bounday condition used for
|
||||
* getting offset from finalZone has some problems. So setting the start year
|
||||
* in the finalZone will cause a problem. For now, we do not set the valid
|
||||
* start year when the construction time and create a clone and set the
|
||||
* start year when extracting rules.
|
||||
* getting offset from finalZone has some problems.
|
||||
* For now, we do not set the valid start year when the construction time
|
||||
* and create a clone and set the start year when extracting rules.
|
||||
*/
|
||||
finalZoneWithStartYear = (SimpleTimeZone*)finalZone->clone();
|
||||
// Check to make sure finalZone was actually cloned.
|
||||
@ -758,9 +795,7 @@ OlsonTimeZone::initTransitionRules(UErrorCode& status) {
|
||||
deleteTransitionRules();
|
||||
return;
|
||||
}
|
||||
// finalYear is 1 year before the actual final year.
|
||||
// See the comment in the construction method.
|
||||
finalZoneWithStartYear->setStartYear(finalYear + 1);
|
||||
finalZoneWithStartYear->setStartYear(finalStartYear);
|
||||
|
||||
TimeZoneTransition tzt;
|
||||
finalZoneWithStartYear->getNextTransition(startTime, false, tzt);
|
||||
@ -773,8 +808,9 @@ OlsonTimeZone::initTransitionRules(UErrorCode& status) {
|
||||
}
|
||||
startTime = tzt.getTime();
|
||||
} else {
|
||||
// final rule with no transitions
|
||||
finalZoneWithStartYear = (SimpleTimeZone*)finalZone->clone();
|
||||
// Check to make sure finalZoneWithStartYear received proper clone before dereference.
|
||||
// Check to make sure finalZone was actually cloned.
|
||||
if (finalZoneWithStartYear == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
deleteTransitionRules();
|
||||
@ -791,8 +827,8 @@ OlsonTimeZone::initTransitionRules(UErrorCode& status) {
|
||||
}
|
||||
}
|
||||
TimeZoneRule *prevRule = NULL;
|
||||
if (transitionCount > 0) {
|
||||
prevRule = historicRules[typeData[transitionCount - 1]];
|
||||
if (transCount > 0) {
|
||||
prevRule = historicRules[typeMapData[transCount - 1]];
|
||||
}
|
||||
if (prevRule == NULL) {
|
||||
// No historic transitions, but only finalZone available
|
||||
@ -836,14 +872,15 @@ OlsonTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition
|
||||
}
|
||||
if (historicRules != NULL) {
|
||||
// Find a historical transition
|
||||
int16_t ttidx = transitionCount - 1;
|
||||
int16_t transCount = transitionCount();
|
||||
int16_t ttidx = transCount - 1;
|
||||
for (; ttidx >= firstTZTransitionIdx; ttidx--) {
|
||||
UDate t = ((UDate)transitionTimes[ttidx]) * U_MILLIS_PER_SECOND;
|
||||
UDate t = (UDate)transitionTime(ttidx);
|
||||
if (base > t || (!inclusive && base == t)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ttidx == transitionCount - 1) {
|
||||
if (ttidx == transCount - 1) {
|
||||
if (firstFinalTZTransition != NULL) {
|
||||
result = *firstFinalTZTransition;
|
||||
return TRUE;
|
||||
@ -855,9 +892,9 @@ OlsonTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition
|
||||
return TRUE;
|
||||
} else {
|
||||
// Create a TimeZoneTransition
|
||||
TimeZoneRule *to = historicRules[typeData[ttidx + 1]];
|
||||
TimeZoneRule *from = historicRules[typeData[ttidx]];
|
||||
UDate startTime = ((UDate)transitionTimes[ttidx+1]) * U_MILLIS_PER_SECOND;
|
||||
TimeZoneRule *to = historicRules[typeMapData[ttidx + 1]];
|
||||
TimeZoneRule *from = historicRules[typeMapData[ttidx]];
|
||||
UDate startTime = (UDate)transitionTime(ttidx+1);
|
||||
|
||||
// The transitions loaded from zoneinfo.res may contain non-transition data
|
||||
UnicodeString fromName, toName;
|
||||
@ -895,15 +932,15 @@ OlsonTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransi
|
||||
} else {
|
||||
result = *firstFinalTZTransition;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (historicRules != NULL) {
|
||||
// Find a historical transition
|
||||
int16_t ttidx = transitionCount - 1;
|
||||
int16_t ttidx = transitionCount() - 1;
|
||||
for (; ttidx >= firstTZTransitionIdx; ttidx--) {
|
||||
UDate t = ((UDate)transitionTimes[ttidx]) * U_MILLIS_PER_SECOND;
|
||||
UDate t = (UDate)transitionTime(ttidx);
|
||||
if (base > t || (inclusive && base == t)) {
|
||||
break;
|
||||
}
|
||||
@ -916,9 +953,9 @@ OlsonTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransi
|
||||
return TRUE;
|
||||
} else {
|
||||
// Create a TimeZoneTransition
|
||||
TimeZoneRule *to = historicRules[typeData[ttidx]];
|
||||
TimeZoneRule *from = historicRules[typeData[ttidx-1]];
|
||||
UDate startTime = ((UDate)transitionTimes[ttidx]) * U_MILLIS_PER_SECOND;
|
||||
TimeZoneRule *to = historicRules[typeMapData[ttidx]];
|
||||
TimeZoneRule *from = historicRules[typeMapData[ttidx-1]];
|
||||
UDate startTime = (UDate)transitionTime(ttidx);
|
||||
|
||||
// The transitions loaded from zoneinfo.res may contain non-transition data
|
||||
UnicodeString fromName, toName;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
**********************************************************************
|
||||
* Copyright (c) 2003-2007, International Business Machines
|
||||
* Copyright (c) 2003-2010, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
**********************************************************************
|
||||
* Author: Alan Liu
|
||||
@ -24,7 +24,7 @@ U_NAMESPACE_BEGIN
|
||||
class SimpleTimeZone;
|
||||
|
||||
/**
|
||||
* A time zone based on the Olson database. Olson time zones change
|
||||
* A time zone based on the Olson tz database. Olson time zones change
|
||||
* behavior over time. The raw offset, rules, presence or absence of
|
||||
* daylight savings time, and even the daylight savings amount can all
|
||||
* vary.
|
||||
@ -37,56 +37,61 @@ class SimpleTimeZone;
|
||||
*
|
||||
* 1. Zones. These have keys corresponding to the Olson IDs, e.g.,
|
||||
* "Asia/Shanghai". Each resource describes the behavior of the given
|
||||
* zone. Zones come in several formats, which are differentiated
|
||||
* based on length.
|
||||
* zone. Zones come in two different formats.
|
||||
*
|
||||
* a. Alias (int, length 1). An alias zone is an int resource. The
|
||||
* integer is the zone number of the target zone. The key of this
|
||||
* resource is an alternate name for the target zone. Aliases
|
||||
* represent Olson links and ICU compatibility IDs.
|
||||
* a. Zone (table). A zone is a table resource contains several
|
||||
* type of resources below:
|
||||
*
|
||||
* - typeOffsets:intvector (Required)
|
||||
*
|
||||
* Sets of UTC raw/dst offset pairs in seconds. Entries at
|
||||
* 2n represents raw offset and 2n+1 represents dst offset
|
||||
* paired with the raw offset at 2n. The very first pair represents
|
||||
* the initial zone offset (before the first transition) always.
|
||||
*
|
||||
* b. Simple zone (array, length 3). The three subelements are:
|
||||
*
|
||||
* i. An intvector of transitions. These are given in epoch
|
||||
* seconds. This may be an empty invector (length 0). If the
|
||||
* transtions list is empty, then the zone's behavior is fixed and
|
||||
* given by the offset list, which will contain exactly one pair.
|
||||
* Otherwise each transtion indicates a time after which (inclusive)
|
||||
* the associated offset pair is in effect.
|
||||
*
|
||||
* ii. An intvector of offsets. These are in pairs of raw offset /
|
||||
* DST offset, in units of seconds. There will be at least one pair
|
||||
* (length >= 2 && length % 2 == 0).
|
||||
*
|
||||
* iii. A binary resource. This is of the same length as the
|
||||
* transitions vector, so length may be zero. Each unsigned byte
|
||||
* corresponds to one transition, and has a value of 0..n-1, where n
|
||||
* is the number of pairs in the offset vector. This forms a map
|
||||
* between transitions and offset pairs.
|
||||
*
|
||||
* c. Simple zone with aliases (array, length 4). This is like a
|
||||
* simple zone, but also contains a fourth element:
|
||||
*
|
||||
* iv. An intvector of aliases. This list includes this zone
|
||||
* itself, and lists all aliases of this zone.
|
||||
*
|
||||
* d. Complex zone (array, length 5). This is like a simple zone,
|
||||
* but contains two more elements:
|
||||
*
|
||||
* iv. A string, giving the name of a rule. This is the "final
|
||||
* rule", which governs the zone's behavior beginning in the "final
|
||||
* year". The rule ID is given without leading underscore, e.g.,
|
||||
* "EU".
|
||||
*
|
||||
* v. An intvector of length 2, containing the raw offset for the
|
||||
* final rule (in seconds), and the final year. The final rule
|
||||
* takes effect for years >= the final year.
|
||||
*
|
||||
* e. Complex zone with aliases (array, length 6). This is like a
|
||||
* complex zone, but also contains a sixth element:
|
||||
* - trans:intvector (Optional)
|
||||
*
|
||||
* List of transition times represented by 32bit seconds from the
|
||||
* epoch (1970-01-01T00:00Z) in ascending order.
|
||||
*
|
||||
* - transPre32/transPost32:intvector (Optional)
|
||||
*
|
||||
* List of transition times before/after 32bit minimum seconds.
|
||||
* Each time is represented by a pair of 32bit integer.
|
||||
*
|
||||
* vi. An intvector of aliases. This list includes this zone
|
||||
* itself, and lists all aliases of this zone.
|
||||
* - typeMap:bin (Optional)
|
||||
*
|
||||
* Array of bytes representing the mapping between each transition
|
||||
* time (transPre32/trans/transPost32) and its corresponding offset
|
||||
* data (typeOffsets).
|
||||
*
|
||||
* - finalRule:string (Optional)
|
||||
*
|
||||
* If a recurrent transition rule is applicable to a zone forever
|
||||
* after the final transition time, finalRule represents the rule
|
||||
* in Rules data.
|
||||
*
|
||||
* - finalRaw:int (Optional)
|
||||
*
|
||||
* When finalRule is available, finalRaw is required and specifies
|
||||
* the raw (base) offset of the rule.
|
||||
*
|
||||
* - finalYear:int (Optional)
|
||||
*
|
||||
* When finalRule is available, finalYear is required and specifies
|
||||
* the start year of the rule.
|
||||
*
|
||||
* - links:intvector (Optional)
|
||||
*
|
||||
* When this zone data is shared with other zones, links specifies
|
||||
* all zones including the zone itself. Each zone is referenced by
|
||||
* integer index.
|
||||
*
|
||||
* b. Link (int, length 1). A link zone is an int resource. The
|
||||
* integer is the zone number of the target zone. The key of this
|
||||
* resource is an alternate name for the target zone. This data
|
||||
* is corresponding to Link data in the tz database.
|
||||
*
|
||||
*
|
||||
* 2. Rules. These have keys corresponding to the Olson rule IDs,
|
||||
* with an underscore prepended, e.g., "_EU". Each resource describes
|
||||
@ -100,18 +105,10 @@ class SimpleTimeZone;
|
||||
* used), with the times and the DST savings multiplied by 1000 to
|
||||
* scale from seconds to milliseconds.
|
||||
*
|
||||
* 3. Countries. These have keys corresponding to the 2-letter ISO
|
||||
* country codes, with a percent sign prepended, e.g., "%US". Each
|
||||
* resource is an intvector listing the zones associated with the
|
||||
* given country. The special entry "%" corresponds to "no country",
|
||||
* that is, the category of zones assigned to no country in the Olson
|
||||
* DB.
|
||||
*
|
||||
* 4. Metadata. Metadata is stored under the key "_". It is an
|
||||
* intvector of length three containing the number of zones resources,
|
||||
* rule resources, and country resources. For the purposes of this
|
||||
* count, the metadata entry itself is considered a rule resource,
|
||||
* since its key begins with an underscore.
|
||||
* 3. Regions. An array specifies mapping between zones and regions.
|
||||
* Each item is either a 2-letter ISO country code or "001"
|
||||
* (UN M.49 - World). This data is generated from "zone.tab"
|
||||
* in the tz database.
|
||||
*/
|
||||
class OlsonTimeZone: public BasicTimeZone {
|
||||
public:
|
||||
@ -289,60 +286,86 @@ private:
|
||||
int32_t NonExistingTimeOpt, int32_t DuplicatedTimeOpt,
|
||||
int32_t& rawoff, int32_t& dstoff) const;
|
||||
|
||||
int32_t zoneOffset(int16_t index) const;
|
||||
int32_t rawOffset(int16_t index) const;
|
||||
int32_t dstOffset(int16_t index) const;
|
||||
int16_t transitionCount() const;
|
||||
|
||||
int64_t transitionTimeInSeconds(int16_t transIdx) const;
|
||||
double transitionTime(int16_t transIdx) const;
|
||||
|
||||
/*
|
||||
* Following 3 methods return an offset at the given transition time index.
|
||||
* When the index is negative, return the initial offset.
|
||||
*/
|
||||
int32_t zoneOffsetAt(int16_t transIdx) const;
|
||||
int32_t rawOffsetAt(int16_t transIdx) const;
|
||||
int32_t dstOffsetAt(int16_t transIdx) const;
|
||||
|
||||
/*
|
||||
* Following methods return the initial offset.
|
||||
*/
|
||||
int32_t initialRawOffset() const;
|
||||
int32_t initialDstOffset() const;
|
||||
|
||||
/**
|
||||
* Number of transitions, 0..~370
|
||||
* Number of transitions in each time range
|
||||
*/
|
||||
int16_t transitionCount;
|
||||
int16_t transitionCountPre32;
|
||||
int16_t transitionCount32;
|
||||
int16_t transitionCountPost32;
|
||||
|
||||
/**
|
||||
* Time of each transition in seconds from 1970 epoch before 32bit second range (<= 1900).
|
||||
* Each transition in this range is represented by a pair of int32_t.
|
||||
* Length is transitionCount int32_t's. NULL if no transitions in this range.
|
||||
*/
|
||||
const int32_t *transitionTimesPre32; // alias into res; do not delete
|
||||
|
||||
/**
|
||||
* Time of each transition in seconds from 1970 epoch in 32bit second range.
|
||||
* Length is transitionCount int32_t's. NULL if no transitions in this range.
|
||||
*/
|
||||
const int32_t *transitionTimes32; // alias into res; do not delete
|
||||
|
||||
/**
|
||||
* Time of each transition in seconds from 1970 epoch after 32bit second range (>= 2038).
|
||||
* Each transition in this range is represented by a pair of int32_t.
|
||||
* Length is transitionCount int32_t's. NULL if no transitions in this range.
|
||||
*/
|
||||
const int32_t *transitionTimesPost32; // alias into res; do not delete
|
||||
|
||||
/**
|
||||
* Number of types, 1..255
|
||||
*/
|
||||
int16_t typeCount;
|
||||
|
||||
/**
|
||||
* Time of each transition in seconds from 1970 epoch.
|
||||
* Length is transitionCount int32_t's.
|
||||
*/
|
||||
const int32_t *transitionTimes; // alias into res; do not delete
|
||||
|
||||
/**
|
||||
* Offset from GMT in seconds for each type.
|
||||
* Length is typeCount int32_t's.
|
||||
* Length is typeCount int32_t's. At least one type (a pair of int32_t)
|
||||
* is required.
|
||||
*/
|
||||
const int32_t *typeOffsets; // alias into res; do not delete
|
||||
|
||||
/**
|
||||
* Type description data, consisting of transitionCount uint8_t
|
||||
* type indices (from 0..typeCount-1).
|
||||
* Length is transitionCount int8_t's.
|
||||
* Length is transitionCount int16_t's. NULL if no transitions.
|
||||
*/
|
||||
const uint8_t *typeData; // alias into res; do not delete
|
||||
const uint8_t *typeMapData; // alias into res; do not delete
|
||||
|
||||
/**
|
||||
* The last year for which the transitions data are to be used
|
||||
* rather than the finalZone. If there is no finalZone, then this
|
||||
* is set to INT32_MAX. NOTE: This corresponds to the year _before_
|
||||
* the one indicated by finalMillis.
|
||||
*/
|
||||
int32_t finalYear;
|
||||
|
||||
/**
|
||||
* The millis for the start of the first year for which finalZone
|
||||
* is to be used, or DBL_MAX if finalZone is 0. NOTE: This is
|
||||
* 0:00 GMT Jan 1, <finalYear + 1> (not <finalMillis>).
|
||||
*/
|
||||
double finalMillis;
|
||||
|
||||
/**
|
||||
* A SimpleTimeZone that governs the behavior for years > finalYear.
|
||||
* If and only if finalYear == INT32_MAX then finalZone == 0.
|
||||
* A SimpleTimeZone that governs the behavior for date >= finalMillis.
|
||||
*/
|
||||
SimpleTimeZone *finalZone; // owned, may be NULL
|
||||
|
||||
/**
|
||||
* For date >= finalMillis, the finalZone will be used.
|
||||
*/
|
||||
double finalStartMillis;
|
||||
|
||||
/**
|
||||
* For year >= finalYear, the finalZone will be used.
|
||||
*/
|
||||
int32_t finalStartYear;
|
||||
|
||||
/* BasicTimeZone support */
|
||||
void clearTransitionRules(void);
|
||||
void deleteTransitionRules(void);
|
||||
@ -358,20 +381,42 @@ private:
|
||||
UBool transitionRulesInitialized;
|
||||
};
|
||||
|
||||
inline int32_t
|
||||
OlsonTimeZone::zoneOffset(int16_t index) const {
|
||||
index <<= 1;
|
||||
return typeOffsets[index] + typeOffsets[index+1];
|
||||
inline int16_t
|
||||
OlsonTimeZone::transitionCount() const {
|
||||
return transitionCountPre32 + transitionCount32 + transitionCountPost32;
|
||||
}
|
||||
|
||||
inline double
|
||||
OlsonTimeZone::transitionTime(int16_t transIdx) const {
|
||||
return (double)transitionTimeInSeconds(transIdx) * U_MILLIS_PER_SECOND;
|
||||
}
|
||||
|
||||
inline int32_t
|
||||
OlsonTimeZone::rawOffset(int16_t index) const {
|
||||
return typeOffsets[(uint32_t)(index << 1)];
|
||||
OlsonTimeZone::zoneOffsetAt(int16_t transIdx) const {
|
||||
int16_t typeIdx = (transIdx >= 0 ? typeMapData[transIdx] : 0) << 1;
|
||||
return typeOffsets[typeIdx] + typeOffsets[typeIdx + 1];
|
||||
}
|
||||
|
||||
inline int32_t
|
||||
OlsonTimeZone::dstOffset(int16_t index) const {
|
||||
return typeOffsets[(uint32_t)((index << 1) + 1)];
|
||||
OlsonTimeZone::rawOffsetAt(int16_t transIdx) const {
|
||||
int16_t typeIdx = (transIdx >= 0 ? typeMapData[transIdx] : 0) << 1;
|
||||
return typeOffsets[typeIdx];
|
||||
}
|
||||
|
||||
inline int32_t
|
||||
OlsonTimeZone::dstOffsetAt(int16_t transIdx) const {
|
||||
int16_t typeIdx = (transIdx >= 0 ? typeMapData[transIdx] : 0) << 1;
|
||||
return typeOffsets[typeIdx + 1];
|
||||
}
|
||||
|
||||
inline int32_t
|
||||
OlsonTimeZone::initialRawOffset() const {
|
||||
return typeOffsets[0];
|
||||
}
|
||||
|
||||
inline int32_t
|
||||
OlsonTimeZone::initialDstOffset() const {
|
||||
return typeOffsets[1];
|
||||
}
|
||||
|
||||
U_NAMESPACE_END
|
||||
|
@ -81,12 +81,13 @@ static char gStrBuf[256];
|
||||
#include "uassert.h"
|
||||
#include "zonemeta.h"
|
||||
|
||||
#define kZONEINFO "zoneinfo"
|
||||
#define kZONEINFO "zoneinfo64"
|
||||
#define kREGIONS "Regions"
|
||||
#define kZONES "Zones"
|
||||
#define kRULES "Rules"
|
||||
#define kNAMES "Names"
|
||||
#define kDEFAULT "Default"
|
||||
#define kTZVERSION "TZVersion"
|
||||
#define kLINKS "links"
|
||||
#define kMAX_CUSTOM_HOUR 23
|
||||
#define kMAX_CUSTOM_MIN 59
|
||||
#define kMAX_CUSTOM_SEC 59
|
||||
@ -97,6 +98,8 @@ static char gStrBuf[256];
|
||||
|
||||
// Static data and constants
|
||||
|
||||
static const UChar WORLD[] = {0x30, 0x30, 0x31, 0x00}; /* "001" */
|
||||
|
||||
static const UChar GMT_ID[] = {0x47, 0x4D, 0x54, 0x00}; /* "GMT" */
|
||||
static const UChar Z_STR[] = {0x7A, 0x00}; /* "z" */
|
||||
static const UChar ZZZZ_STR[] = {0x7A, 0x7A, 0x7A, 0x7A, 0x00}; /* "zzzz" */
|
||||
@ -116,18 +119,9 @@ static U_NAMESPACE_QUALIFIER TimeZone* _GMT = NULL; // cf. TimeZone::GMT
|
||||
static char TZDATA_VERSION[16];
|
||||
static UBool TZDataVersionInitialized = FALSE;
|
||||
|
||||
#ifdef U_USE_TIMEZONE_OBSOLETE_2_8
|
||||
static U_NAMESPACE_QUALIFIER UnicodeString* OLSON_IDS = 0;
|
||||
#endif
|
||||
|
||||
U_CDECL_BEGIN
|
||||
static UBool U_CALLCONV timeZone_cleanup(void)
|
||||
{
|
||||
#ifdef U_USE_TIMEZONE_OBSOLETE_2_8
|
||||
delete []OLSON_IDS;
|
||||
OLSON_IDS = 0;
|
||||
#endif
|
||||
|
||||
delete DEFAULT_ZONE;
|
||||
DEFAULT_ZONE = NULL;
|
||||
|
||||
@ -305,7 +299,7 @@ static UResourceBundle* openOlsonResource(const UnicodeString& id,
|
||||
// Dereference if this is an alias. Docs say result should be 1
|
||||
// but it is 0 in 2.8 (?).
|
||||
U_DEBUG_TZ_MSG(("Loading zone '%s' (%s, size %d) - %s\n", buf, ures_getKey((UResourceBundle*)&res), ures_getSize(&res), u_errorName(ec)));
|
||||
if (ures_getSize(&res) <= 1 && getOlsonMeta(top)) {
|
||||
if (ures_getType(&res) == URES_INT && getOlsonMeta(top)) {
|
||||
int32_t deref = ures_getInt(&res, &ec) + 0;
|
||||
U_DEBUG_TZ_MSG(("getInt: %s - type is %d\n", u_errorName(ec), ures_getType(&res)));
|
||||
UResourceBundle *ares = ures_getByKey(top, kZONES, NULL, &ec); // dereference Zones section
|
||||
@ -319,68 +313,6 @@ static UResourceBundle* openOlsonResource(const UnicodeString& id,
|
||||
return top;
|
||||
}
|
||||
|
||||
#ifdef U_USE_TIMEZONE_OBSOLETE_2_8
|
||||
|
||||
/**
|
||||
* Load all the ids from the "zoneinfo" resource bundle into a static
|
||||
* array that we hang onto. This is _only_ used to implement the
|
||||
* deprecated createAvailableIDs() API.
|
||||
*/
|
||||
static UBool loadOlsonIDs() {
|
||||
if (OLSON_IDS != 0) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
UErrorCode ec = U_ZERO_ERROR;
|
||||
UnicodeString* ids = 0;
|
||||
int32_t count = 0;
|
||||
UResourceBundle *top = ures_openDirect(0, kZONEINFO, &ec);
|
||||
UResourceBundle *nres = ures_getByKey(top, kNAMES, NULL, &ec); // dereference Names section
|
||||
if (U_SUCCESS(ec)) {
|
||||
getOlsonMeta(top);
|
||||
int32_t start = 0;
|
||||
count = ures_getSize(nres);
|
||||
ids = new UnicodeString[(count > 0) ? count : 1];
|
||||
// Null pointer check
|
||||
if (ids != NULL) {
|
||||
for (int32_t i=0; i<count; ++i) {
|
||||
int32_t idLen = 0;
|
||||
const UChar* id = ures_getStringByIndex(nres, i, &idLen, &ec);
|
||||
ids[i].fastCopyFrom(UnicodeString(TRUE, id, idLen));
|
||||
if (U_FAILURE(ec)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ec = U_MEMORY_ALLOCATION_ERROR;
|
||||
}
|
||||
}
|
||||
ures_close(nres);
|
||||
ures_close(top);
|
||||
|
||||
if (U_FAILURE(ec)) {
|
||||
delete[] ids;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Keep mutexed operations as short as possible by doing all
|
||||
// computations first, then doing pointer copies within the mutex.
|
||||
umtx_lock(&LOCK);
|
||||
if (OLSON_IDS == 0) {
|
||||
OLSON_IDS = ids;
|
||||
ids = 0;
|
||||
ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
|
||||
}
|
||||
umtx_unlock(&LOCK);
|
||||
|
||||
// If another thread initialized the statics first, then delete
|
||||
// our unused data.
|
||||
delete[] ids;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
const TimeZone* U_EXPORT2
|
||||
@ -789,38 +721,56 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
char key[] = {0, 0, 0, 0,0, 0, 0,0, 0, 0,0}; // e.g., "US", or "Default" for no country
|
||||
if (country) {
|
||||
uprv_strncat(key, country, 2);
|
||||
} else {
|
||||
uprv_strcpy(key, kDEFAULT);
|
||||
}
|
||||
|
||||
UErrorCode ec = U_ZERO_ERROR;
|
||||
UResourceBundle *top = ures_openDirect(0, kZONEINFO, &ec);
|
||||
top = ures_getByKey(top, kREGIONS, top, &ec); // dereference 'Regions' section
|
||||
if (U_SUCCESS(ec)) {
|
||||
UResourceBundle res;
|
||||
ures_initStackObject(&res);
|
||||
ures_getByKey(top, key, &res, &ec);
|
||||
// The list of zones is a list of integers, from 0..n-1,
|
||||
// where n is the total number of system zones.
|
||||
const int32_t* v = ures_getIntVector(&res, &len, &ec);
|
||||
if (U_SUCCESS(ec)) {
|
||||
U_ASSERT(len > 0);
|
||||
map = (int32_t*)uprv_malloc(sizeof(int32_t) * len);
|
||||
if (map != 0) {
|
||||
for (uint16_t i=0; i<len; ++i) {
|
||||
U_ASSERT(v[i] >= 0 && v[i] < OLSON_ZONE_COUNT);
|
||||
map[i] = v[i];
|
||||
}
|
||||
}
|
||||
UResourceBundle *res = ures_openDirect(0, kZONEINFO, &ec);
|
||||
ures_getByKey(res, kREGIONS, res, &ec);
|
||||
if (U_SUCCESS(ec) && ures_getType(res) == URES_ARRAY) {
|
||||
UChar uCountry[] = {0, 0, 0, 0};
|
||||
if (country) {
|
||||
u_charsToUChars(country, uCountry, 2);
|
||||
} else {
|
||||
U_DEBUG_TZ_MSG(("Failed to load tz for region %s: %s\n", country, u_errorName(ec)));
|
||||
u_strcpy(uCountry, WORLD);
|
||||
}
|
||||
|
||||
// count matches
|
||||
int32_t count = 0;
|
||||
int32_t i;
|
||||
const UChar *region;
|
||||
for (i = 0; i < ures_getSize(res); i++) {
|
||||
region = ures_getStringByIndex(res, i, NULL, &ec);
|
||||
if (U_FAILURE(ec)) {
|
||||
break;
|
||||
}
|
||||
if (u_strcmp(uCountry, region) == 0) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
if (count > 0) {
|
||||
map = (int32_t*)uprv_malloc(sizeof(int32_t) * count);
|
||||
if (map != NULL) {
|
||||
int32_t idx = 0;
|
||||
for (i = 0; i < ures_getSize(res); i++) {
|
||||
region = ures_getStringByIndex(res, i, NULL, &ec);
|
||||
if (U_FAILURE(ec)) {
|
||||
break;
|
||||
}
|
||||
if (u_strcmp(uCountry, region) == 0) {
|
||||
map[idx++] = i;
|
||||
}
|
||||
}
|
||||
if (U_SUCCESS(ec)) {
|
||||
len = count;
|
||||
} else {
|
||||
uprv_free(map);
|
||||
map = NULL;
|
||||
}
|
||||
} else {
|
||||
U_DEBUG_TZ_MSG(("Failed to load tz for region %s: %s\n", country, u_errorName(ec)));
|
||||
}
|
||||
}
|
||||
ures_close(&res);
|
||||
}
|
||||
ures_close(top);
|
||||
ures_close(res);
|
||||
}
|
||||
|
||||
TZEnumeration(const TZEnumeration &other) : StringEnumeration(), map(NULL), len(0), pos(0) {
|
||||
@ -886,132 +836,6 @@ TimeZone::createEnumeration(const char* country) {
|
||||
return new TZEnumeration(country);
|
||||
}
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
#ifdef U_USE_TIMEZONE_OBSOLETE_2_8
|
||||
|
||||
const UnicodeString**
|
||||
TimeZone::createAvailableIDs(int32_t rawOffset, int32_t& numIDs)
|
||||
{
|
||||
// We are creating a new array to existing UnicodeString pointers.
|
||||
// The caller will delete the array when done, but not the pointers
|
||||
// in the array.
|
||||
|
||||
numIDs = 0;
|
||||
if (!loadOlsonIDs()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Allocate more space than we'll need. The end of the array will
|
||||
// be blank.
|
||||
const UnicodeString** ids =
|
||||
(const UnicodeString** )uprv_malloc(OLSON_ZONE_COUNT * sizeof(UnicodeString *));
|
||||
if (ids == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uprv_memset(ids, 0, sizeof(UnicodeString*) * OLSON_ZONE_COUNT);
|
||||
|
||||
UnicodeString s;
|
||||
for (int32_t i=0; i<OLSON_ZONE_COUNT; ++i) {
|
||||
// This is VERY inefficient.
|
||||
TimeZone* z = TimeZone::createTimeZone(OLSON_IDS[i]);
|
||||
// Make sure we get back the ID we wanted (if the ID is
|
||||
// invalid we get back GMT).
|
||||
if (z != 0 && z->getID(s) == OLSON_IDS[i] &&
|
||||
z->getRawOffset() == rawOffset) {
|
||||
ids[numIDs++] = &OLSON_IDS[i]; // [sic]
|
||||
}
|
||||
delete z;
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
const UnicodeString**
|
||||
TimeZone::createAvailableIDs(const char* country, int32_t& numIDs) {
|
||||
|
||||
// We are creating a new array to existing UnicodeString pointers.
|
||||
// The caller will delete the array when done, but not the pointers
|
||||
// in the array.
|
||||
|
||||
numIDs = 0;
|
||||
if (!loadOlsonIDs()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
char key[] = { 0, 0, 0,0, 0, 0,0, 0, 0 }; // e.g., "US", or "Default" for non-country zones
|
||||
if (country) {
|
||||
uprv_strncat(key, country, 2);
|
||||
} else {
|
||||
uprv_strcpy(key, kDEFAULT);
|
||||
}
|
||||
|
||||
const UnicodeString** ids = 0;
|
||||
|
||||
UErrorCode ec = U_ZERO_ERROR;
|
||||
UResourceBundle *top = ures_openDirect(0, kZONEINFO, &ec);
|
||||
UResourceBundle *ares = ures_getByKey(top, kREGIONS, NULL, &ec); // dereference Regions section
|
||||
if (U_SUCCESS(ec)) {
|
||||
getOlsonMeta(top);
|
||||
UResourceBundle res;
|
||||
ures_initStackObject(&res);
|
||||
ures_getByKey(ares, key, &res, &ec);
|
||||
U_DEBUG_TZ_MSG(("caI: on %s, err %s\n", country, u_errorName(ec)));
|
||||
if (U_SUCCESS(ec)) {
|
||||
/* The list of zones is a list of integers, from 0..n-1,
|
||||
* where n is the total number of system zones. The
|
||||
* numbering corresponds exactly to the ordering of
|
||||
* OLSON_IDS.
|
||||
*/
|
||||
const int32_t* v = ures_getIntVector(&res, &numIDs, &ec);
|
||||
ids = (const UnicodeString**)
|
||||
uprv_malloc(numIDs * sizeof(UnicodeString*));
|
||||
if (ids == 0) {
|
||||
numIDs = 0;
|
||||
} else {
|
||||
for (int32_t i=0; i<numIDs; ++i) {
|
||||
ids[i] = &OLSON_IDS[v[i]]; // [sic]
|
||||
}
|
||||
}
|
||||
}
|
||||
ures_close(&res);
|
||||
}
|
||||
ures_close(ares);
|
||||
ures_close(top);
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
// -------------------------------------
|
||||
|
||||
const UnicodeString**
|
||||
TimeZone::createAvailableIDs(int32_t& numIDs)
|
||||
{
|
||||
// We are creating a new array to existing UnicodeString pointers.
|
||||
// The caller will delete the array when done, but not the pointers
|
||||
// in the array.
|
||||
numIDs = 0;
|
||||
if (!loadOlsonIDs()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const UnicodeString** ids =
|
||||
(const UnicodeString** )uprv_malloc(OLSON_ZONE_COUNT * sizeof(UnicodeString *));
|
||||
if (ids != 0) {
|
||||
numIDs = OLSON_ZONE_COUNT;
|
||||
for (int32_t i=0; i<numIDs; ++i) {
|
||||
ids[i] = &OLSON_IDS[i];
|
||||
}
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// ---------------------------------------
|
||||
|
||||
int32_t U_EXPORT2
|
||||
@ -1023,19 +847,11 @@ TimeZone::countEquivalentIDs(const UnicodeString& id) {
|
||||
U_DEBUG_TZ_MSG(("countEquivalentIDs..\n"));
|
||||
UResourceBundle *top = openOlsonResource(id, res, ec);
|
||||
if (U_SUCCESS(ec)) {
|
||||
int32_t size = ures_getSize(&res);
|
||||
U_DEBUG_TZ_MSG(("cEI: success (size %d, key %s)..\n", size, ures_getKey(&res)));
|
||||
if (size == 4 || size == 6) {
|
||||
UResourceBundle r;
|
||||
ures_initStackObject(&r);
|
||||
ures_getByIndex(&res, size-1, &r, &ec);
|
||||
//result = ures_getSize(&r); // doesn't work
|
||||
ures_getIntVector(&r, &result, &ec);
|
||||
U_DEBUG_TZ_MSG(("ceI: result %d, err %s\n", result, u_errorName(ec)));
|
||||
ures_close(&r);
|
||||
}
|
||||
} else {
|
||||
U_DEBUG_TZ_MSG(("cEI: fail, %s\n", u_errorName(ec)));
|
||||
UResourceBundle r;
|
||||
ures_initStackObject(&r);
|
||||
ures_getByKey(&res, kLINKS, &r, &ec);
|
||||
ures_getIntVector(&r, &result, &ec);
|
||||
ures_close(&r);
|
||||
}
|
||||
ures_close(&res);
|
||||
ures_close(top);
|
||||
@ -1054,17 +870,17 @@ TimeZone::getEquivalentID(const UnicodeString& id, int32_t index) {
|
||||
UResourceBundle *top = openOlsonResource(id, res, ec);
|
||||
int32_t zone = -1;
|
||||
if (U_SUCCESS(ec)) {
|
||||
int32_t size = ures_getSize(&res);
|
||||
if (size == 4 || size == 6) {
|
||||
UResourceBundle r;
|
||||
ures_initStackObject(&r);
|
||||
ures_getByIndex(&res, size-1, &r, &ec);
|
||||
const int32_t* v = ures_getIntVector(&r, &size, &ec);
|
||||
UResourceBundle r;
|
||||
ures_initStackObject(&r);
|
||||
int32_t size;
|
||||
ures_getByKey(&res, kLINKS, &r, &ec);
|
||||
const int32_t* v = ures_getIntVector(&r, &size, &ec);
|
||||
if (U_SUCCESS(ec)) {
|
||||
if (index >= 0 && index < size && getOlsonMeta()) {
|
||||
zone = v[index];
|
||||
}
|
||||
ures_close(&r);
|
||||
}
|
||||
ures_close(&r);
|
||||
}
|
||||
ures_close(&res);
|
||||
if (zone >= 0) {
|
||||
@ -1106,7 +922,7 @@ TimeZone::dereferOlsonLink(const UnicodeString& id) {
|
||||
ures_getByIndex(rb, idx, rb, &ec);
|
||||
|
||||
if (U_SUCCESS(ec)) {
|
||||
if (ures_getSize(rb) == 1) {
|
||||
if (ures_getType(rb) == URES_INT) {
|
||||
// this is a link - dereference the link
|
||||
int32_t deref = ures_getInt(rb, &ec);
|
||||
const UChar* tmp = ures_getStringByIndex(names, deref, NULL, &ec);
|
||||
@ -1122,11 +938,27 @@ TimeZone::dereferOlsonLink(const UnicodeString& id) {
|
||||
return result;
|
||||
}
|
||||
|
||||
UResourceBundle*
|
||||
TimeZone::getIDArray(UErrorCode& status) {
|
||||
UResourceBundle *rb = ures_openDirect(NULL, kZONEINFO, &status);
|
||||
ures_getByKey(rb, kNAMES, rb, &status);
|
||||
return rb;
|
||||
const UChar*
|
||||
TimeZone::getRegion(const UnicodeString& id) {
|
||||
const UChar *result = WORLD;
|
||||
UErrorCode ec = U_ZERO_ERROR;
|
||||
UResourceBundle *rb = ures_openDirect(NULL, kZONEINFO, &ec);
|
||||
|
||||
// resolve zone index by name
|
||||
UResourceBundle *res = ures_getByKey(rb, kNAMES, NULL, &ec);
|
||||
int32_t idx = findInStringArray(res, id, ec);
|
||||
|
||||
// get region mapping
|
||||
ures_getByKey(rb, kREGIONS, res, &ec);
|
||||
const UChar *tmp = ures_getStringByIndex(res, idx, NULL, &ec);
|
||||
if (U_SUCCESS(ec)) {
|
||||
result = tmp;
|
||||
}
|
||||
|
||||
ures_close(res);
|
||||
ures_close(rb);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// ---------------------------------------
|
||||
@ -1491,8 +1323,8 @@ TimeZone::getTZDataVersion(UErrorCode& status)
|
||||
UMTX_CHECK(&LOCK, !TZDataVersionInitialized, needsInit);
|
||||
if (needsInit) {
|
||||
int32_t len = 0;
|
||||
UResourceBundle *bundle = ures_openDirect(NULL, "zoneinfo", &status);
|
||||
const UChar *tzver = ures_getStringByKey(bundle, "TZVersion",
|
||||
UResourceBundle *bundle = ures_openDirect(NULL, kZONEINFO, &status);
|
||||
const UChar *tzver = ures_getStringByKey(bundle, kTZVERSION,
|
||||
&len, &status);
|
||||
|
||||
if (U_SUCCESS(status)) {
|
||||
|
@ -186,72 +186,6 @@ public:
|
||||
*/
|
||||
static StringEnumeration* U_EXPORT2 createEnumeration(const char* country);
|
||||
|
||||
#ifdef U_USE_TIMEZONE_OBSOLETE_2_8
|
||||
/**
|
||||
* Returns a list of time zone IDs, one for each time zone with a given GMT offset.
|
||||
* The return value is a list because there may be several times zones with the same
|
||||
* GMT offset that differ in the way they handle daylight savings time. For example,
|
||||
* the state of Arizona doesn't observe Daylight Savings time. So if you ask for
|
||||
* the time zone IDs corresponding to GMT-7:00, you'll get back two time zone IDs:
|
||||
* "America/Denver," which corresponds to Mountain Standard Time in the winter and
|
||||
* Mountain Daylight Time in the summer, and "America/Phoenix", which corresponds to
|
||||
* Mountain Standard Time year-round, even in the summer.
|
||||
* <P>
|
||||
* The caller owns the list that is returned, but does not own the strings contained
|
||||
* in that list. Delete the array with uprv_free(), but DON'T delete the elements in the array.
|
||||
*
|
||||
* <p>NOTE: uprv_free() is declared in the private header source/common/cmemory.h.
|
||||
*
|
||||
* @param rawOffset An offset from GMT in milliseconds.
|
||||
* @param numIDs Receives the number of items in the array that is returned.
|
||||
* @return An array of UnicodeString pointers, where each UnicodeString is
|
||||
* a time zone ID for a time zone with the given GMT offset. If
|
||||
* there is no time zone that matches the GMT offset
|
||||
* specified, NULL is returned.
|
||||
* @obsolete ICU 2.8. Use createEnumeration(int32_t) instead since this API will be removed in that release.
|
||||
*/
|
||||
static const UnicodeString** createAvailableIDs(int32_t rawOffset, int32_t& numIDs);
|
||||
|
||||
/**
|
||||
* Returns a list of time zone IDs associated with the given
|
||||
* country. Some zones are affiliated with no country (e.g.,
|
||||
* "UTC"); these may also be retrieved, as a group.
|
||||
*
|
||||
* <P>The caller owns the list that is returned, but does not own
|
||||
* the strings contained in that list. Delete the array with uprv_free(), but
|
||||
* <b>DON'T</b> delete the elements in the array.
|
||||
*
|
||||
* <p>NOTE: uprv_free() is declared in the private header source/common/cmemory.h.
|
||||
*
|
||||
* @param country The ISO 3166 two-letter country code, or NULL to
|
||||
* retrieve zones not affiliated with any country.
|
||||
* @param numIDs Receives the number of items in the array that is
|
||||
* returned.
|
||||
* @return An array of UnicodeString pointers, where each
|
||||
* UnicodeString is a time zone ID for a time zone with the given
|
||||
* country. If there is no time zone that matches the country
|
||||
* specified, NULL is returned.
|
||||
* @obsolete ICU 2.8. Use createEnumeration(const char*) instead since this API will be removed in that release.
|
||||
*/
|
||||
static const UnicodeString** createAvailableIDs(const char* country,
|
||||
int32_t& numIDs);
|
||||
|
||||
/**
|
||||
* Returns a list of all time zone IDs supported by the TimeZone class (i.e., all
|
||||
* IDs that it's legal to pass to createTimeZone()). The caller owns the list that
|
||||
* is returned, but does not own the strings contained in that list. Delete the array with uprv_free(),
|
||||
* but DON'T delete the elements in the array.
|
||||
*
|
||||
* <p>NOTE: uprv_free() is declared in the private header source/common/cmemory.h.
|
||||
*
|
||||
* @param numIDs Receives the number of zone IDs returned.
|
||||
* @return An array of UnicodeString pointers, where each is a time zone ID
|
||||
* supported by the TimeZone class.
|
||||
* @obsolete ICU 2.8. Use createEnumeration(void) instead since this API will be removed in that release.
|
||||
*/
|
||||
static const UnicodeString** createAvailableIDs(int32_t& numIDs);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns the number of IDs in the equivalency group that
|
||||
* includes the given ID. An equivalency group contains zones
|
||||
@ -747,13 +681,17 @@ private:
|
||||
* the id itself is returned. When the given id is known and it is a link, then
|
||||
* dereferenced zone id is returned. When the given id is unknown, then it returns
|
||||
* NULL.
|
||||
* @param id Receives the dereferenced zone id string
|
||||
* @param id zone id string
|
||||
* @return the dereferenced zone or NULL
|
||||
*/
|
||||
static const UChar* dereferOlsonLink(const UnicodeString& id);
|
||||
|
||||
/* Retuns a resource bundle array contains all time zone IDs. This is only used by ZoneMeta class. */
|
||||
static UResourceBundle* getIDArray(UErrorCode& status);
|
||||
/**
|
||||
* Returns the region code associated with the given zone.
|
||||
* @param id zone id string
|
||||
* @return the region associated with the given zone
|
||||
*/
|
||||
static const UChar* getRegion(const UnicodeString& id);
|
||||
|
||||
/**
|
||||
* Parses the given custom time zone identifier
|
||||
|
@ -21,12 +21,19 @@
|
||||
#include "gregoimp.h"
|
||||
#include "cstring.h"
|
||||
#include "ucln_in.h"
|
||||
#include "uassert.h"
|
||||
|
||||
// Metazone mapping tables
|
||||
static UMTX gZoneMetaLock = NULL;
|
||||
|
||||
// Metazone mapping table
|
||||
static UHashtable *gOlsonToMeta = NULL;
|
||||
static UBool gOlsonToMetaInitialized = FALSE;
|
||||
|
||||
// Country info vectors
|
||||
static UVector *gSingleZoneCountries = NULL;
|
||||
static UVector *gMultiZonesCountries = NULL;
|
||||
static UBool gCountryInfoVectorsInitialized = FALSE;
|
||||
|
||||
U_CDECL_BEGIN
|
||||
|
||||
|
||||
@ -43,6 +50,10 @@ static UBool U_CALLCONV zoneMeta_cleanup(void)
|
||||
}
|
||||
gOlsonToMetaInitialized = FALSE;
|
||||
|
||||
delete gSingleZoneCountries;
|
||||
delete gMultiZonesCountries;
|
||||
gCountryInfoVectorsInitialized = FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@ -77,11 +88,6 @@ U_CDECL_END
|
||||
U_NAMESPACE_BEGIN
|
||||
|
||||
#define ZID_KEY_MAX 128
|
||||
static const char gSupplementalData[] = "supplementalData";
|
||||
static const char gZoneFormattingTag[] = "zoneFormatting";
|
||||
static const char gTerritoryTag[] = "territory";
|
||||
static const char gMultizoneTag[] = "multizone";
|
||||
static const UChar gWorld[] = {0x30, 0x30, 0x31, 0x00}; // "001"
|
||||
|
||||
static const char gMetaZones[] = "metaZones";
|
||||
static const char gMetazoneInfo[] = "metazoneInfo";
|
||||
@ -91,6 +97,8 @@ static const char gKeyTypeData[] = "keyTypeData";
|
||||
static const char gTypeAliasTag[] = "typeAlias";
|
||||
static const char gTimezoneTag[] = "timezone";
|
||||
|
||||
static const UChar gWorld[] = {0x30, 0x30, 0x31, 0x00}; // "001"
|
||||
|
||||
static const UChar gDefaultFrom[] = {0x31, 0x39, 0x37, 0x30, 0x2D, 0x30, 0x31, 0x2D, 0x30, 0x31,
|
||||
0x20, 0x30, 0x30, 0x3A, 0x30, 0x30, 0x00}; // "1970-01-01 00:00"
|
||||
static const UChar gDefaultTo[] = {0x39, 0x39, 0x39, 0x39, 0x2D, 0x31, 0x32, 0x2D, 0x33, 0x31,
|
||||
@ -216,72 +224,131 @@ ZoneMeta::getCanonicalSystemID(const UnicodeString &tzid, UnicodeString &systemI
|
||||
|
||||
UnicodeString& U_EXPORT2
|
||||
ZoneMeta::getCanonicalCountry(const UnicodeString &tzid, UnicodeString &canonicalCountry) {
|
||||
const UChar *territory = NULL;
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
UnicodeString canonicalID;
|
||||
|
||||
getCanonicalSystemID(tzid, canonicalID, status);
|
||||
if (U_SUCCESS(status) && canonicalID.length() < ZID_KEY_MAX) {
|
||||
char tzkey[ZID_KEY_MAX];
|
||||
canonicalID.extract(0, canonicalID.length(), tzkey, sizeof(tzkey), US_INV);
|
||||
// replace '/' with ':'
|
||||
char *p = tzkey;
|
||||
while (*p) {
|
||||
if (*p == '/') {
|
||||
*p = ':';
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
UResourceBundle *rb = ures_openDirect(NULL, gSupplementalData, &status);
|
||||
ures_getByKey(rb, gZoneFormattingTag, rb, &status);
|
||||
ures_getByKey(rb, tzkey, rb, &status);
|
||||
territory = ures_getStringByKey(rb, gTerritoryTag, NULL, &status);
|
||||
if (U_SUCCESS(status)) {
|
||||
if (u_strcmp(territory, gWorld) == 0) {
|
||||
territory = NULL;
|
||||
}
|
||||
}
|
||||
ures_close(rb);
|
||||
}
|
||||
|
||||
if (territory == NULL) {
|
||||
canonicalCountry.remove();
|
||||
const UChar *region = TimeZone::getRegion(tzid);
|
||||
if (u_strcmp(gWorld, region) != 0) {
|
||||
canonicalCountry.setTo(region, -1);
|
||||
} else {
|
||||
canonicalCountry.setTo(territory, -1);
|
||||
canonicalCountry.remove();
|
||||
}
|
||||
return canonicalCountry;
|
||||
}
|
||||
|
||||
UnicodeString& U_EXPORT2
|
||||
ZoneMeta::getSingleCountry(const UnicodeString &tzid, UnicodeString &country) {
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
|
||||
// Get canonical country for the zone
|
||||
getCanonicalCountry(tzid, country);
|
||||
const UChar *region = TimeZone::getRegion(tzid);
|
||||
if (u_strcmp(gWorld, region) == 0) {
|
||||
// special case - "001"
|
||||
country.remove();
|
||||
return country;
|
||||
}
|
||||
|
||||
if (!country.isEmpty()) {
|
||||
UResourceBundle *supplementalDataBundle = ures_openDirect(NULL, gSupplementalData, &status);
|
||||
UResourceBundle *zoneFormatting = ures_getByKey(supplementalDataBundle, gZoneFormattingTag, NULL, &status);
|
||||
UResourceBundle *multizone = ures_getByKey(zoneFormatting, gMultizoneTag, NULL, &status);
|
||||
// Checking the cached results
|
||||
UErrorCode status = U_ZERO_ERROR;
|
||||
UBool initialized;
|
||||
UMTX_CHECK(&gZoneMetaLock, gCountryInfoVectorsInitialized, initialized);
|
||||
if (!initialized) {
|
||||
// Create empty vectors
|
||||
umtx_lock(&gZoneMetaLock);
|
||||
{
|
||||
if (!gCountryInfoVectorsInitialized) {
|
||||
// No deleters for these UVectors, it's a reference to a resource bundle string.
|
||||
gSingleZoneCountries = new UVector(NULL, uhash_compareUChars, status);
|
||||
if (gSingleZoneCountries == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
}
|
||||
gMultiZonesCountries = new UVector(NULL, uhash_compareUChars, status);
|
||||
if (gMultiZonesCountries == NULL) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
}
|
||||
|
||||
if (U_SUCCESS(status)) {
|
||||
while (ures_hasNext(multizone)) {
|
||||
int32_t len;
|
||||
const UChar* multizoneCountry = ures_getNextString(multizone, &len, NULL, &status);
|
||||
if (country.compare(multizoneCountry, len) == 0) {
|
||||
// Included in the multizone country list
|
||||
country.remove();
|
||||
break;
|
||||
if (U_SUCCESS(status)) {
|
||||
gCountryInfoVectorsInitialized = TRUE;
|
||||
} else {
|
||||
delete gSingleZoneCountries;
|
||||
delete gMultiZonesCountries;
|
||||
}
|
||||
}
|
||||
}
|
||||
umtx_unlock(&gZoneMetaLock);
|
||||
|
||||
ures_close(multizone);
|
||||
ures_close(zoneFormatting);
|
||||
ures_close(supplementalDataBundle);
|
||||
if (U_FAILURE(status)) {
|
||||
country.remove();
|
||||
return country;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if it was already cached
|
||||
UBool cached = FALSE;
|
||||
UBool multiZones = FALSE;
|
||||
umtx_lock(&gZoneMetaLock);
|
||||
{
|
||||
multiZones = cached = gMultiZonesCountries->contains((void*)region);
|
||||
if (!multiZones) {
|
||||
cached = gSingleZoneCountries->contains((void*)region);
|
||||
}
|
||||
}
|
||||
umtx_unlock(&gZoneMetaLock);
|
||||
|
||||
if (!cached) {
|
||||
// We need to go through all zones associated with the region.
|
||||
// This is relatively heavy operation.
|
||||
|
||||
U_ASSERT(u_strlen(region) == 2);
|
||||
|
||||
char buf[] = {0, 0, 0};
|
||||
u_UCharsToChars(region, buf, 2);
|
||||
|
||||
StringEnumeration *ids = TimeZone::createEnumeration(buf);
|
||||
int32_t idsLen = ids->count(status);
|
||||
if (U_SUCCESS(status) && idsLen > 1) {
|
||||
// multiple zones are available for the region
|
||||
UnicodeString canonical, tmp;
|
||||
const UnicodeString *id = ids->snext(status);
|
||||
getCanonicalSystemID(*id, canonical, status);
|
||||
if (U_SUCCESS(status)) {
|
||||
// check if there are any other canonical zone in the group
|
||||
while (id = ids->snext(status)) {
|
||||
getCanonicalSystemID(*id, tmp, status);
|
||||
if (U_FAILURE(status)) {
|
||||
break;
|
||||
}
|
||||
if (canonical != tmp) {
|
||||
// another canonical zone was found
|
||||
multiZones = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (U_FAILURE(status)) {
|
||||
// no single country by default for any error cases
|
||||
multiZones = TRUE;
|
||||
}
|
||||
delete ids;
|
||||
|
||||
// Cache the result
|
||||
umtx_lock(&gZoneMetaLock);
|
||||
{
|
||||
UErrorCode ec = U_ZERO_ERROR;
|
||||
if (multiZones) {
|
||||
if (!gMultiZonesCountries->contains((void*)region)) {
|
||||
gMultiZonesCountries->addElement((void*)region, ec);
|
||||
}
|
||||
} else {
|
||||
if (!gSingleZoneCountries->contains((void*)region)) {
|
||||
gSingleZoneCountries->addElement((void*)region, ec);
|
||||
}
|
||||
}
|
||||
}
|
||||
umtx_unlock(&gZoneMetaLock);
|
||||
}
|
||||
|
||||
if (multiZones) {
|
||||
country.remove();
|
||||
} else {
|
||||
country.setTo(region, -1);
|
||||
}
|
||||
return country;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/***********************************************************************
|
||||
* COPYRIGHT:
|
||||
* Copyright (c) 1997-2009, International Business Machines Corporation
|
||||
* Copyright (c) 1997-2010, International Business Machines Corporation
|
||||
* and others. All Rights Reserved.
|
||||
***********************************************************************/
|
||||
|
||||
@ -531,21 +531,7 @@ void IntlCalendarTest::TestJapaneseFormat() {
|
||||
|
||||
// Test parse with incomplete information
|
||||
fmt = new SimpleDateFormat(UnicodeString("G y"), Locale("en_US@calendar=japanese"), status);
|
||||
/* The test data below should points to 1868-09-08T00:00:00 in America/Los_Angeles.
|
||||
* The time calculated by original test code uses -7:00 UTC offset, because it assumes
|
||||
* DST is observed (because of a timezone bug, DST is observed for early 20th century
|
||||
* day to infinite past time). The bug was fixed and DST is no longer used for time before
|
||||
* 1900 for any zones. However, ICU timezone transition data is represented by 32-bit integer
|
||||
* (sec) and cannot represent transitions before 1901 defined in Olson tzdata. For example,
|
||||
* based on Olson definition, offset -7:52:58 should be used for Nov 18, 1883 or older dates.
|
||||
* If ICU properly capture entire Olson zone definition, the start time of "Meiji 1" is
|
||||
* -3197117222000. -Yoshito
|
||||
*/
|
||||
/* TODO: When ICU support the Olson LMT offset for America/Los_Angeles, we need to update
|
||||
* the reference data.
|
||||
*/
|
||||
//aDate = -3197120400000.;
|
||||
aDate = -3197116800000.;
|
||||
aDate = -3197117222000.0;
|
||||
CHECK(status, "creating date format instance");
|
||||
if(!fmt) {
|
||||
errln("Coudln't create en_US instance");
|
||||
@ -597,8 +583,7 @@ void IntlCalendarTest::TestJapaneseFormat() {
|
||||
}
|
||||
{
|
||||
UnicodeString expect = CharsToUnicodeString("\\u5b89\\u6c385\\u5e747\\u67084\\u65e5\\u6728\\u66dc\\u65e5");
|
||||
//UDate expectDate = -6106035600000.0;
|
||||
UDate expectDate = -6106032000000.0; // 1776-07-04T00:00:00Z-0800
|
||||
UDate expectDate = -6106032422000.0; // 1776-07-04T00:00:00Z-075258
|
||||
Locale loc("ja_JP@calendar=japanese");
|
||||
|
||||
status = U_ZERO_ERROR;
|
||||
@ -616,9 +601,7 @@ void IntlCalendarTest::TestJapaneseFormat() {
|
||||
}
|
||||
{ // This Feb 29th falls on a leap year by gregorian year, but not by Japanese year.
|
||||
UnicodeString expect = CharsToUnicodeString("\\u5EB7\\u6B632\\u5e742\\u670829\\u65e5\\u65e5\\u66dc\\u65e5");
|
||||
// Add -1:00 to the following for historical TZ - aliu
|
||||
//UDate expectDate = -16214403600000.0; // courtesy of date format round trip test
|
||||
UDate expectDate = -16214400000000.0; // 1456-03-09T00:00:00Z-0800
|
||||
UDate expectDate = -16214400422000.0; // 1456-03-09T00:00Z-075258
|
||||
Locale loc("ja_JP@calendar=japanese");
|
||||
|
||||
status = U_ZERO_ERROR;
|
||||
|
@ -1,5 +1,5 @@
|
||||
/********************************************************************
|
||||
* Copyright (c) 1997-2009, International Business Machines
|
||||
* Copyright (c) 1997-2010, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
********************************************************************/
|
||||
|
||||
@ -460,8 +460,7 @@ void TimeZoneRegressionTest:: Test4126678()
|
||||
TimeZone *tz = TimeZone::createTimeZone("PST");
|
||||
cal->adoptTimeZone(tz);
|
||||
|
||||
cal->set(1998 - 1900, UCAL_APRIL, 5, 10, 0);
|
||||
//Date dt = new Date(1998-1900, Calendar::APRIL, 5, 10, 0);
|
||||
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));
|
||||
@ -481,21 +480,7 @@ void TimeZoneRegressionTest:: Test4126678()
|
||||
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();
|
||||
/* Because of better historical timezone support based on Olson data,
|
||||
* DST is not observed in year 98. Thus, the expected result is changed.
|
||||
* As of Mar 2007, ICU timezone transition data is represented by 32-bit.
|
||||
* When we support 64-bit Olson transition data, the actual offset in
|
||||
* AD 98 for America/Los_Angeles will be changed again (-7:52:58). Until
|
||||
* then, expected result is offset == raw_offset. -Yoshito
|
||||
*/
|
||||
/*
|
||||
if (offset == raw_offset)
|
||||
errln("Offsets should not match when in DST");
|
||||
*/
|
||||
/* TODO: When ICU support the Olson LMT offset for America/Los_Angeles, we need to update
|
||||
* the reference data.
|
||||
*/
|
||||
if (offset != raw_offset)
|
||||
errln("Offsets should match");
|
||||
|
||||
delete cal;
|
||||
|
4
icu4c/source/test/testdata/calendar.txt
vendored
4
icu4c/source/test/testdata/calendar.txt
vendored
@ -1,4 +1,4 @@
|
||||
// Copyright (c) 2008 International Business Machines
|
||||
// Copyright (c) 2008-2010 International Business Machines
|
||||
// Corporation and others. All Rights Reserved.
|
||||
calendar:table(nofallback) {
|
||||
Info {
|
||||
@ -348,7 +348,7 @@ calendar:table(nofallback) {
|
||||
"MILLIS=-180799750799999",
|
||||
"add",
|
||||
"YEAR=100000", // year + 100000
|
||||
"MILLIS=2974930005600001",
|
||||
"MILLIS=2974930006022001",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Some Portions Copyright (c) 2006-2009 IBM and others. All Rights Reserved.
|
||||
# Some Portions Copyright (c) 2006-2010 IBM and others. All Rights Reserved.
|
||||
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
@ -112,7 +112,7 @@ CPPFLAGS+= -DTZDIR=\"$(TZDIR)\"
|
||||
|
||||
# more data
|
||||
XDATA=zone.tab yearistype.sh leapseconds iso3166.tab
|
||||
ICUDATA=ZoneMetaData.java icu_zone.txt tz2icu zoneinfo.txt
|
||||
ICUDATA=ZoneMetaData.java icu_zone.txt tz2icu zoneinfo64.txt
|
||||
|
||||
$(ZICTARG): $(OBJECTS) $(TDATA) yearistype $(srcdir)/tz2icu.h
|
||||
$(CC) $(CFLAGS) $(TZORIG_EXTRA_CFLAGS) $(LFLAGS) -I$(srcdir) $(OBJECTS) $(LDLIBS) -o $@
|
||||
|
@ -1,7 +1,7 @@
|
||||
|
||||
/*
|
||||
**********************************************************************
|
||||
* Copyright (c) 2003-2008, International Business Machines
|
||||
* Copyright (c) 2003-2010, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
**********************************************************************
|
||||
* Author: Alan Liu
|
||||
@ -48,10 +48,11 @@
|
||||
#include "tz2icu.h"
|
||||
#include "unicode/uversion.h"
|
||||
|
||||
#define USE64BITDATA
|
||||
|
||||
using namespace std;
|
||||
|
||||
bool ICU44PLUS = TRUE;
|
||||
string TZ_RESOURCE_NAME = ICU_TZ_RESOURCE;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Time utilities
|
||||
//--------------------------------------------------------------------
|
||||
@ -287,7 +288,7 @@ bool readbool(ifstream& file) {
|
||||
* Read the zoneinfo file structure (see tzfile.h) into a ZoneInfo
|
||||
* @param file an already-open file stream
|
||||
*/
|
||||
void readzoneinfo(ifstream& file, ZoneInfo& info, bool is64bitData=false) {
|
||||
void readzoneinfo(ifstream& file, ZoneInfo& info, bool is64bitData) {
|
||||
int32_t i;
|
||||
|
||||
// Check for TZ_ICU_MAGIC signature at file start. If we get a
|
||||
@ -360,7 +361,7 @@ void readzoneinfo(ifstream& file, ZoneInfo& info, bool is64bitData=false) {
|
||||
|
||||
// Build transitions vector out of corresponding times and types.
|
||||
bool insertInitial = false;
|
||||
if (is64bitData) {
|
||||
if (is64bitData && !ICU44PLUS) {
|
||||
if (timecnt > 0) {
|
||||
int32_t minidx = -1;
|
||||
for (i=0; i<timecnt; ++i) {
|
||||
@ -436,7 +437,7 @@ void readzoneinfo(ifstream& file, ZoneInfo& info, bool is64bitData=false) {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
initialTypeIdx = 0;
|
||||
initialTypeIdx = 0;
|
||||
}
|
||||
assert(initialTypeIdx >= 0);
|
||||
// Add the initial type associated with the lowest int32 time
|
||||
@ -545,15 +546,16 @@ void handleFile(string path, string id) {
|
||||
throw invalid_argument("can't open file");
|
||||
}
|
||||
|
||||
// eat 32bit data part
|
||||
ZoneInfo info;
|
||||
readzoneinfo(file, info);
|
||||
readzoneinfo(file, info, false);
|
||||
|
||||
// Check for errors
|
||||
if (!file) {
|
||||
throw invalid_argument("read error");
|
||||
}
|
||||
|
||||
#ifdef USE64BITDATA
|
||||
// we only use 64bit part
|
||||
ZoneInfo info64;
|
||||
readzoneinfo(file, info64, true);
|
||||
|
||||
@ -590,27 +592,6 @@ void handleFile(string path, string id) {
|
||||
}
|
||||
|
||||
ZONEINFO[id] = info64;
|
||||
|
||||
#else
|
||||
// Check eof-relative pos (there may be a cleaner way to do this)
|
||||
int64_t eofPos = (int64_t) file.tellg();
|
||||
char buf[32];
|
||||
file.read(buf, 4);
|
||||
file.seekg(0, ios::end);
|
||||
eofPos = eofPos - (int64_t) file.tellg();
|
||||
if (eofPos) {
|
||||
// 2006c merged 32 and 64 bit versions in a fat binary
|
||||
// 64 version starts at the end of 32 bit version.
|
||||
// Therefore, if the file is *not* consumed, check
|
||||
// if it is maybe being restarted.
|
||||
if (strncmp(buf, TZ_ICU_MAGIC, 4) != 0) {
|
||||
ostringstream os;
|
||||
os << (-eofPos) << " unprocessed bytes at end";
|
||||
throw invalid_argument(os.str());
|
||||
}
|
||||
}
|
||||
ZONEINFO[id] = info;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1034,7 +1015,6 @@ void readFinalZonesAndRules(istream& in) {
|
||||
|
||||
void ZoneInfo::print(ostream& os, const string& id) const {
|
||||
// Implement compressed format #2:
|
||||
|
||||
os << " /* " << id << " */ ";
|
||||
|
||||
if (aliasTo >= 0) {
|
||||
@ -1043,22 +1023,75 @@ void ZoneInfo::print(ostream& os, const string& id) const {
|
||||
return;
|
||||
}
|
||||
|
||||
os << ":array {" << endl;
|
||||
if (ICU44PLUS) {
|
||||
os << ":table {" << endl;
|
||||
} else {
|
||||
os << ":array {" << endl;
|
||||
}
|
||||
|
||||
vector<Transition>::const_iterator trn;
|
||||
vector<ZoneType>::const_iterator typ;
|
||||
|
||||
bool first=true;
|
||||
os << " :intvector { ";
|
||||
for (trn = transitions.begin(); trn != transitions.end(); ++trn) {
|
||||
if (!first) os << ", ";
|
||||
first = false;
|
||||
os << trn->time;
|
||||
bool first;
|
||||
|
||||
if (ICU44PLUS) {
|
||||
trn = transitions.begin();
|
||||
|
||||
// pre 32bit transitions
|
||||
if (trn != transitions.end() && trn->time < LOWEST_TIME32) {
|
||||
os << " transPre32:intvector { ";
|
||||
for (first = true; trn != transitions.end() && trn->time < LOWEST_TIME32; ++trn) {
|
||||
if (!first) {
|
||||
os<< ", ";
|
||||
}
|
||||
first = false;
|
||||
os << (int32_t)(trn->time >> 32) << ", " << (int32_t)(trn->time & 0x00000000ffffffff);
|
||||
}
|
||||
os << " }" << endl;
|
||||
}
|
||||
|
||||
// 32bit transtions
|
||||
if (trn != transitions.end() && trn->time < HIGHEST_TIME32) {
|
||||
os << " trans:intvector { ";
|
||||
for (first = true; trn != transitions.end() && trn->time < HIGHEST_TIME32; ++trn) {
|
||||
if (!first) {
|
||||
os << ", ";
|
||||
}
|
||||
first = false;
|
||||
os << trn->time;
|
||||
}
|
||||
os << " }" << endl;
|
||||
}
|
||||
|
||||
// post 32bit transitons
|
||||
if (trn != transitions.end()) {
|
||||
os << " transPost32:intvector { ";
|
||||
for (first = true; trn != transitions.end(); ++trn) {
|
||||
if (!first) {
|
||||
os<< ", ";
|
||||
}
|
||||
first = false;
|
||||
os << (int32_t)(trn->time >> 32) << ", " << (int32_t)(trn->time & 0x00000000ffffffff);
|
||||
}
|
||||
os << " }" << endl;
|
||||
}
|
||||
} else {
|
||||
os << " :intvector { ";
|
||||
for (trn = transitions.begin(), first = true; trn != transitions.end(); ++trn) {
|
||||
if (!first) os << ", ";
|
||||
first = false;
|
||||
os << trn->time;
|
||||
}
|
||||
os << " }" << endl;
|
||||
}
|
||||
os << " }" << endl;
|
||||
|
||||
|
||||
first=true;
|
||||
os << " :intvector { ";
|
||||
if (ICU44PLUS) {
|
||||
os << " typeOffsets:intvector { ";
|
||||
} else {
|
||||
os << " :intvector { ";
|
||||
}
|
||||
for (typ = types.begin(); typ != types.end(); ++typ) {
|
||||
if (!first) os << ", ";
|
||||
first = false;
|
||||
@ -1066,23 +1099,43 @@ void ZoneInfo::print(ostream& os, const string& id) const {
|
||||
}
|
||||
os << " }" << endl;
|
||||
|
||||
os << " :bin { \"" << hex << setfill('0');
|
||||
for (trn = transitions.begin(); trn != transitions.end(); ++trn) {
|
||||
os << setw(2) << trn->type;
|
||||
if (ICU44PLUS) {
|
||||
if (transitions.size() != 0) {
|
||||
os << " typeMap:bin { \"" << hex << setfill('0');
|
||||
for (trn = transitions.begin(); trn != transitions.end(); ++trn) {
|
||||
os << setw(2) << trn->type;
|
||||
}
|
||||
os << dec << "\" }" << endl;
|
||||
}
|
||||
} else {
|
||||
os << " :bin { \"" << hex << setfill('0');
|
||||
for (trn = transitions.begin(); trn != transitions.end(); ++trn) {
|
||||
os << setw(2) << trn->type;
|
||||
}
|
||||
os << dec << "\" }" << endl;
|
||||
}
|
||||
os << dec << "\" }" << endl;
|
||||
|
||||
// Final zone info, if any
|
||||
if (finalYear != -1) {
|
||||
os << " \"" << finalRuleID << "\"" << endl;
|
||||
os << " :intvector { " << finalOffset << ", "
|
||||
<< finalYear << " }" << endl;
|
||||
if (ICU44PLUS) {
|
||||
os << " finalRule { \"" << finalRuleID << "\" }" << endl;
|
||||
os << " finalRaw:int { " << finalOffset << " }" << endl;
|
||||
os << " finalYear:int { " << finalYear << " }" << endl;
|
||||
} else {
|
||||
os << " \"" << finalRuleID << "\"" << endl;
|
||||
os << " :intvector { " << finalOffset << ", "
|
||||
<< finalYear << " }" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Alias list, if any
|
||||
if (aliases.size() != 0) {
|
||||
first = true;
|
||||
os << " :intvector { ";
|
||||
if (ICU44PLUS) {
|
||||
os << " links:intvector { ";
|
||||
} else {
|
||||
os << " :intvector { ";
|
||||
}
|
||||
for (set<int32_t>::const_iterator i=aliases.begin(); i!=aliases.end(); ++i) {
|
||||
if (!first) os << ", ";
|
||||
first = false;
|
||||
@ -1100,7 +1153,7 @@ operator<<(ostream& os, const ZoneMap& zoneinfo) {
|
||||
for (ZoneMapIter it = zoneinfo.begin();
|
||||
it != zoneinfo.end();
|
||||
++it) {
|
||||
if(c) os << ",";
|
||||
if(c && !ICU44PLUS) os << ",";
|
||||
it->second.print(os, it->first);
|
||||
os << "//Z#" << c++ << endl;
|
||||
}
|
||||
@ -1189,42 +1242,117 @@ void ZoneInfo::optimizeTypeList() {
|
||||
|
||||
if (aliasTo >= 0) return; // Nothing to do for aliases
|
||||
|
||||
// If there are zero transitions and one type, then leave that as-is.
|
||||
if (transitions.size() == 0) {
|
||||
if (types.size() != 1) {
|
||||
cerr << "Error: transition count = 0, type count = " << types.size() << endl;
|
||||
if (!ICU44PLUS) {
|
||||
// This is the old logic which has a bug, which occasionally removes
|
||||
// the type before the first transition. The problem was fixed
|
||||
// by inserting the dummy transition indirectly.
|
||||
|
||||
// If there are zero transitions and one type, then leave that as-is.
|
||||
if (transitions.size() == 0) {
|
||||
if (types.size() != 1) {
|
||||
cerr << "Error: transition count = 0, type count = " << types.size() << endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
set<SimplifiedZoneType> simpleset;
|
||||
for (vector<Transition>::const_iterator i=transitions.begin();
|
||||
i!=transitions.end(); ++i) {
|
||||
assert(i->type < (int32_t)types.size());
|
||||
simpleset.insert(types[i->type]);
|
||||
}
|
||||
|
||||
// Map types to integer indices
|
||||
map<SimplifiedZoneType,int32_t> simplemap;
|
||||
int32_t n=0;
|
||||
for (set<SimplifiedZoneType>::const_iterator i=simpleset.begin();
|
||||
i!=simpleset.end(); ++i) {
|
||||
simplemap[*i] = n++;
|
||||
}
|
||||
|
||||
// Remap transitions
|
||||
for (vector<Transition>::iterator i=transitions.begin();
|
||||
i!=transitions.end(); ++i) {
|
||||
assert(i->type < (int32_t)types.size());
|
||||
ZoneType oldtype = types[i->type];
|
||||
SimplifiedZoneType newtype(oldtype);
|
||||
assert(simplemap.find(newtype) != simplemap.end());
|
||||
i->type = simplemap[newtype];
|
||||
}
|
||||
|
||||
// Replace type list
|
||||
types.clear();
|
||||
copy(simpleset.begin(), simpleset.end(), back_inserter(types));
|
||||
|
||||
} else {
|
||||
if (types.size() > 1) {
|
||||
// Note: localtime uses the very first non-dst type as initial offsets.
|
||||
// If all types are DSTs, the very first type is treated as the initial offsets.
|
||||
|
||||
// Decide a type used as the initial offsets. ICU put the type at index 0.
|
||||
ZoneType initialType = types[0];
|
||||
for (vector<ZoneType>::const_iterator i=types.begin(); i!=types.end(); ++i) {
|
||||
if (i->dstoffset == 0) {
|
||||
initialType = *i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SimplifiedZoneType initialSimplifiedType(initialType);
|
||||
|
||||
// create a set of unique types, but ignoring fields which we're not interested in
|
||||
set<SimplifiedZoneType> simpleset;
|
||||
simpleset.insert(initialSimplifiedType);
|
||||
for (vector<Transition>::const_iterator i=transitions.begin(); i!=transitions.end(); ++i) {
|
||||
assert(i->type < (int32_t)types.size());
|
||||
simpleset.insert(types[i->type]);
|
||||
}
|
||||
|
||||
// Map types to integer indices, however, keeping the first type at offset 0
|
||||
map<SimplifiedZoneType,int32_t> simplemap;
|
||||
simplemap[initialSimplifiedType] = 0;
|
||||
int32_t n = 1;
|
||||
for (set<SimplifiedZoneType>::const_iterator i=simpleset.begin(); i!=simpleset.end(); ++i) {
|
||||
if (*i < initialSimplifiedType || initialSimplifiedType < *i) {
|
||||
simplemap[*i] = n++;
|
||||
}
|
||||
}
|
||||
|
||||
// Remap transitions
|
||||
for (vector<Transition>::iterator i=transitions.begin();
|
||||
i!=transitions.end(); ++i) {
|
||||
assert(i->type < (int32_t)types.size());
|
||||
ZoneType oldtype = types[i->type];
|
||||
SimplifiedZoneType newtype(oldtype);
|
||||
assert(simplemap.find(newtype) != simplemap.end());
|
||||
i->type = simplemap[newtype];
|
||||
}
|
||||
|
||||
// Replace type list
|
||||
types.clear();
|
||||
types.push_back(initialSimplifiedType);
|
||||
for (set<SimplifiedZoneType>::const_iterator i=simpleset.begin(); i!=simpleset.end(); ++i) {
|
||||
if (*i < initialSimplifiedType || initialSimplifiedType < *i) {
|
||||
types.push_back(*i);
|
||||
}
|
||||
}
|
||||
|
||||
// Reiterating transitions to remove any transitions which
|
||||
// do not actually change the raw/dst offsets
|
||||
int32_t prevTypeIdx = 0;
|
||||
for (vector<Transition>::iterator i=transitions.begin(); i!=transitions.end();) {
|
||||
if (i->type == prevTypeIdx) {
|
||||
// this is not a time transition, probably just name change
|
||||
// e.g. America/Resolute after 2006 in 2010b
|
||||
transitions.erase(i);
|
||||
} else {
|
||||
prevTypeIdx = i->type;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
set<SimplifiedZoneType> simpleset;
|
||||
for (vector<Transition>::const_iterator i=transitions.begin();
|
||||
i!=transitions.end(); ++i) {
|
||||
assert(i->type < (int32_t)types.size());
|
||||
simpleset.insert(types[i->type]);
|
||||
}
|
||||
|
||||
// Map types to integer indices
|
||||
map<SimplifiedZoneType,int32_t> simplemap;
|
||||
int32_t n=0;
|
||||
for (set<SimplifiedZoneType>::const_iterator i=simpleset.begin();
|
||||
i!=simpleset.end(); ++i) {
|
||||
simplemap[*i] = n++;
|
||||
}
|
||||
|
||||
// Remap transitions
|
||||
for (vector<Transition>::iterator i=transitions.begin();
|
||||
i!=transitions.end(); ++i) {
|
||||
assert(i->type < (int32_t)types.size());
|
||||
ZoneType oldtype = types[i->type];
|
||||
SimplifiedZoneType newtype(oldtype);
|
||||
assert(simplemap.find(newtype) != simplemap.end());
|
||||
i->type = simplemap[newtype];
|
||||
}
|
||||
|
||||
// Replace type list
|
||||
types.clear();
|
||||
copy(simpleset.begin(), simpleset.end(), back_inserter(types));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1233,6 +1361,17 @@ void ZoneInfo::optimizeTypeList() {
|
||||
void ZoneInfo::mergeFinalData(const FinalZone& fz) {
|
||||
int32_t year = fz.year;
|
||||
int64_t seconds = yearToSeconds(year);
|
||||
|
||||
if (!ICU44PLUS) {
|
||||
if (seconds > HIGHEST_TIME32) {
|
||||
// Avoid transitions beyond signed 32bit max second.
|
||||
// This may result incorrect offset computation around
|
||||
// HIGHEST_TIME32. This is a limitation of ICU
|
||||
// before 4.4.
|
||||
seconds = HIGHEST_TIME32;
|
||||
}
|
||||
}
|
||||
|
||||
vector<Transition>::iterator it =
|
||||
find_if(transitions.begin(), transitions.end(),
|
||||
bind2nd(ptr_fun(isAfter), seconds));
|
||||
@ -1292,22 +1431,35 @@ void FinalRule::print(ostream& os) const {
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
string rootpath, zonetab, version;
|
||||
bool validArgs = FALSE;
|
||||
|
||||
if (argc != 4) {
|
||||
cout << "Usage: tz2icu <dir> <cmap> <vers>" << endl
|
||||
<< " <dir> path to zoneinfo file tree generated by" << endl
|
||||
<< " ICU-patched version of zic" << endl
|
||||
<< " <cmap> country map, from tzdata archive," << endl
|
||||
<< " typically named \"zone.tab\"" << endl
|
||||
<< " <vers> version string, such as \"2003e\"" << endl;
|
||||
exit(1);
|
||||
} else {
|
||||
if (argc == 4 || argc == 5) {
|
||||
validArgs = TRUE;
|
||||
rootpath = argv[1];
|
||||
zonetab = argv[2];
|
||||
version = argv[3];
|
||||
if (argc == 5) {
|
||||
if (strcmp(argv[4], "--old") == 0) {
|
||||
ICU44PLUS = FALSE;
|
||||
TZ_RESOURCE_NAME = ICU_TZ_RESOURCE_OLD;
|
||||
} else {
|
||||
validArgs = FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!validArgs) {
|
||||
cout << "Usage: tz2icu <dir> <cmap> <tzver> [--old]" << endl
|
||||
<< " <dir> path to zoneinfo file tree generated by" << endl
|
||||
<< " ICU-patched version of zic" << endl
|
||||
<< " <cmap> country map, from tzdata archive," << endl
|
||||
<< " typically named \"zone.tab\"" << endl
|
||||
<< " <tzver> version string, such as \"2003e\"" << endl
|
||||
<< " --old generating resource format before ICU4.4" << endl;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
cout << "Olson data version: " << version << endl;
|
||||
cout << "ICU 4.4+ format: " << (ICU44PLUS ? "Yes" : "No") << endl;
|
||||
|
||||
try {
|
||||
ifstream finals(ICU_ZONE_FILE);
|
||||
@ -1326,70 +1478,6 @@ int main(int argc, char *argv[]) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
//############################################################################
|
||||
//# Note: We no longer use tz.alias to define alias for legacy ICU time zones.
|
||||
//# The contents of tz.alias were migrated into zic source format and
|
||||
//# processed by zic as 'Link'.
|
||||
//############################################################################
|
||||
#if 0
|
||||
// Read the legacy alias list and process it. Treat the legacy mappings
|
||||
// like links, but also record them in the "legacy" hash.
|
||||
try {
|
||||
ifstream aliases(ICU_TZ_ALIAS);
|
||||
if (!aliases) {
|
||||
cerr << "Error: Unable to open " ICU_TZ_ALIAS << endl;
|
||||
return 1;
|
||||
}
|
||||
int32_t n = 0;
|
||||
string line;
|
||||
while (getline(aliases, line)) {
|
||||
string::size_type lb = line.find('#');
|
||||
if (lb != string::npos) {
|
||||
line.resize(lb); // trim comments
|
||||
}
|
||||
vector<string> a;
|
||||
istringstream is(line);
|
||||
copy(istream_iterator<string>(is),istream_iterator<string>(),
|
||||
back_inserter(a));
|
||||
if (a.size() == 0) continue; // blank line
|
||||
if (a.size() != 2) {
|
||||
cerr << "Error: Can't parse \"" << line << "\" in "
|
||||
ICU_TZ_ALIAS << endl;
|
||||
exit(1);
|
||||
}
|
||||
++n;
|
||||
|
||||
string alias(a[0]), olson(a[1]);
|
||||
if (links.find(alias) != links.end()) {
|
||||
cerr << "Error: Alias \"" << alias
|
||||
<< "\" is an Olson zone in "
|
||||
ICU_TZ_ALIAS << endl;
|
||||
return 1;
|
||||
}
|
||||
if (reverseLinks.find(alias) != reverseLinks.end()) {
|
||||
cerr << "Error: Alias \"" << alias
|
||||
<< "\" is an Olson link to \"" << reverseLinks[olson]
|
||||
<< "\" in " << ICU_TZ_ALIAS << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Record source for error reporting
|
||||
if (linkSource.find(olson) == linkSource.end()) {
|
||||
linkSource[olson] = "ICU alias";
|
||||
}
|
||||
assert(linkSource.find(alias) == linkSource.end());
|
||||
linkSource[alias] = "ICU alias";
|
||||
|
||||
links[olson].insert(alias);
|
||||
reverseLinks[alias] = olson;
|
||||
}
|
||||
cout << "Finished reading " << n
|
||||
<< " aliases from " ICU_TZ_ALIAS << endl;
|
||||
} catch (const exception& error) {
|
||||
cerr << "Error: While reading " ICU_TZ_ALIAS ": " << error.what() << endl;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
try {
|
||||
// Recursively scan all files below the given path, accumulating
|
||||
// their data into ZONEINFO. All files must be TZif files. Any
|
||||
@ -1570,9 +1658,10 @@ int main(int argc, char *argv[]) {
|
||||
struct tm* now = localtime(&sec);
|
||||
int32_t thisYear = now->tm_year + 1900;
|
||||
|
||||
string filename = TZ_RESOURCE_NAME + ".txt";
|
||||
// Write out a resource-bundle source file containing data for
|
||||
// all zones.
|
||||
ofstream file(ICU_TZ_RESOURCE ".txt");
|
||||
ofstream file(filename.c_str());
|
||||
if (file) {
|
||||
file << "//---------------------------------------------------------" << endl
|
||||
<< "// Copyright (C) 2003";
|
||||
@ -1592,7 +1681,7 @@ int main(int argc, char *argv[]) {
|
||||
<< "// >> !!! >>> DO NOT EDIT <<< !!! <<" << endl
|
||||
<< "//---------------------------------------------------------" << endl
|
||||
<< endl
|
||||
<< ICU_TZ_RESOURCE ":table(nofallback) {" << endl
|
||||
<< TZ_RESOURCE_NAME << ":table(nofallback) {" << endl
|
||||
<< " TZVersion { \"" << version << "\" }" << endl
|
||||
<< " Zones:array { " << endl
|
||||
<< ZONEINFO // Zones (the actual data)
|
||||
@ -1615,35 +1704,47 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
file << " }" << endl;
|
||||
|
||||
// Emit country (region) map. Emitting the string zone IDs results
|
||||
// in a 188 kb binary resource; emitting the zone index numbers
|
||||
// trims this to 171 kb. More work for the runtime code, but
|
||||
// a smaller data footprint.
|
||||
file << " Regions { " << endl;
|
||||
int32_t rc = 0;
|
||||
for (map<string, set<string> >::const_iterator i=countryMap.begin();
|
||||
i != countryMap.end(); ++i) {
|
||||
string country = i->first;
|
||||
const set<string>& zones(i->second);
|
||||
file << " ";
|
||||
if(country[0]==0) {
|
||||
file << "Default";
|
||||
}
|
||||
file << country << ":intvector { ";
|
||||
bool first = true;
|
||||
for (set<string>::const_iterator j=zones.begin();
|
||||
j != zones.end(); ++j) {
|
||||
if (!first) file << ", ";
|
||||
first = false;
|
||||
if (zoneIDs.find(*j) == zoneIDs.end()) {
|
||||
cerr << "Error: Nonexistent zone in country map: " << *j << endl;
|
||||
return 1;
|
||||
// Emit country (region) map.
|
||||
if (ICU44PLUS) {
|
||||
file << " Regions:array {" << endl;
|
||||
int32_t zn = 0;
|
||||
for (ZoneMap::iterator i=ZONEINFO.begin(); i!=ZONEINFO.end(); ++i) {
|
||||
map<string, string>::iterator cit = reverseCountryMap.find(i->first);
|
||||
if (cit == reverseCountryMap.end()) {
|
||||
file << " \"001\",";
|
||||
} else {
|
||||
file << " \"" << cit->second << "\", ";
|
||||
}
|
||||
file << zoneIDs[*j]; // emit the zone's index number
|
||||
file << "//Z#" << zn++ << " " << i->first << endl;
|
||||
}
|
||||
file << " } //R#" << rc++ << endl;
|
||||
file << " }" << endl;
|
||||
} else {
|
||||
file << " Regions { " << endl;
|
||||
int32_t rc = 0;
|
||||
for (map<string, set<string> >::const_iterator i=countryMap.begin();
|
||||
i != countryMap.end(); ++i) {
|
||||
string country = i->first;
|
||||
const set<string>& zones(i->second);
|
||||
file << " ";
|
||||
if(country[0]==0) {
|
||||
file << "Default";
|
||||
}
|
||||
file << country << ":intvector { ";
|
||||
bool first = true;
|
||||
for (set<string>::const_iterator j=zones.begin();
|
||||
j != zones.end(); ++j) {
|
||||
if (!first) file << ", ";
|
||||
first = false;
|
||||
if (zoneIDs.find(*j) == zoneIDs.end()) {
|
||||
cerr << "Error: Nonexistent zone in country map: " << *j << endl;
|
||||
return 1;
|
||||
}
|
||||
file << zoneIDs[*j]; // emit the zone's index number
|
||||
}
|
||||
file << " } //R#" << rc++ << endl;
|
||||
}
|
||||
file << " }" << endl;
|
||||
}
|
||||
file << " }" << endl;
|
||||
|
||||
file << "}" << endl;
|
||||
}
|
||||
@ -1651,100 +1752,10 @@ int main(int argc, char *argv[]) {
|
||||
file.close();
|
||||
|
||||
if (file) { // recheck error bit
|
||||
cout << "Finished writing " ICU_TZ_RESOURCE ".txt" << endl;
|
||||
cout << "Finished writing " << TZ_RESOURCE_NAME << ".txt" << endl;
|
||||
} else {
|
||||
cerr << "Error: Unable to open/write to " ICU_TZ_RESOURCE ".txt" << endl;
|
||||
cerr << "Error: Unable to open/write to " << TZ_RESOURCE_NAME << ".txt" << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define ICU4J_TZ_CLASS "ZoneMetaData"
|
||||
|
||||
// Write out a Java source file containing only a few pieces of
|
||||
// meta-data missing from the core JDK: the equivalency lists and
|
||||
// the country map.
|
||||
ofstream java(ICU4J_TZ_CLASS ".java");
|
||||
if (java) {
|
||||
java << "//---------------------------------------------------------" << endl
|
||||
<< "// Copyright (C) 2003";
|
||||
if (thisYear > 2003) {
|
||||
java << "-" << thisYear;
|
||||
}
|
||||
java << ", International Business Machines" << endl
|
||||
<< "// Corporation and others. All Rights Reserved." << endl
|
||||
<< "//---------------------------------------------------------" << endl
|
||||
<< "// Build tool: tz2icu" << endl
|
||||
<< "// Build date: " << asctime(now) /* << endl -- asctime emits CR */
|
||||
<< "// Olson source: ftp://elsie.nci.nih.gov/pub/" << endl
|
||||
<< "// Olson version: " << version << endl
|
||||
<< "// ICU version: " << U_ICU_VERSION << endl
|
||||
<< "//---------------------------------------------------------" << endl
|
||||
<< "// >> !!! >> THIS IS A MACHINE-GENERATED FILE << !!! <<" << endl
|
||||
<< "// >> !!! >>> DO NOT EDIT <<< !!! <<" << endl
|
||||
<< "//---------------------------------------------------------" << endl
|
||||
<< endl
|
||||
<< "package com.ibm.icu.impl;" << endl
|
||||
<< endl
|
||||
<< "public final class " ICU4J_TZ_CLASS " {" << endl;
|
||||
|
||||
// Emit equivalency lists
|
||||
bool first1 = true;
|
||||
java << " public static final String VERSION = \"" + version + "\";" << endl;
|
||||
java << " public static final String[][] EQUIV = {" << endl;
|
||||
for (ZoneMap::const_iterator i=ZONEINFO.begin(); i!=ZONEINFO.end(); ++i) {
|
||||
if (i->second.isAlias() || i->second.getAliases().size() == 0) {
|
||||
continue;
|
||||
}
|
||||
if (!first1) java << "," << endl;
|
||||
first1 = false;
|
||||
// The ID of this zone (the canonical zone, to which the
|
||||
// aliases point) will be sorted into the list, so it
|
||||
// won't be at position 0. If we want to know which is
|
||||
// the canonical zone, we should move it to position 0.
|
||||
java << " { ";
|
||||
bool first2 = true;
|
||||
const set<int32_t>& s = i->second.getAliases();
|
||||
for (set<int32_t>::const_iterator j=s.begin(); j!=s.end(); ++j) {
|
||||
if (!first2) java << ", ";
|
||||
java << '"' << zoneIDlist[*j] << '"';
|
||||
first2 = false;
|
||||
}
|
||||
java << " }";
|
||||
}
|
||||
java << endl
|
||||
<< " };" << endl;
|
||||
|
||||
// Emit country map.
|
||||
first1 = true;
|
||||
java << " public static final String[][] COUNTRY = {" << endl;
|
||||
for (map<string, set<string> >::const_iterator i=countryMap.begin();
|
||||
i != countryMap.end(); ++i) {
|
||||
if (!first1) java << "," << endl;
|
||||
first1 = false;
|
||||
string country = i->first;
|
||||
const set<string>& zones(i->second);
|
||||
java << " { \"" << country << '"';
|
||||
for (set<string>::const_iterator j=zones.begin();
|
||||
j != zones.end(); ++j) {
|
||||
java << ", \"" << *j << '"';
|
||||
}
|
||||
java << " }";
|
||||
}
|
||||
java << endl
|
||||
<< " };" << endl;
|
||||
|
||||
java << "}" << endl;
|
||||
}
|
||||
|
||||
java.close();
|
||||
|
||||
if (java) { // recheck error bit
|
||||
cout << "Finished writing " ICU4J_TZ_CLASS ".java" << endl;
|
||||
} else {
|
||||
cerr << "Error: Unable to open/write to " ICU4J_TZ_CLASS ".java" << endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//eof
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*
|
||||
**********************************************************************
|
||||
* Copyright (c) 2003-2004, International Business Machines
|
||||
* Copyright (c) 2003-2010, International Business Machines
|
||||
* Corporation and others. All Rights Reserved.
|
||||
**********************************************************************
|
||||
* Author: Alan Liu
|
||||
@ -38,6 +38,7 @@ typedef unsigned char ICUZoneinfoVersion;
|
||||
* resource name within the file. That is, the output will be to the
|
||||
* file ICU_TZ_RESOURCE ".txt" and the resource within it will be
|
||||
* ICU_TZ_RESOURCE. */
|
||||
#define ICU_TZ_RESOURCE "zoneinfo"
|
||||
#define ICU_TZ_RESOURCE_OLD "zoneinfo"
|
||||
#define ICU_TZ_RESOURCE "zoneinfo64"
|
||||
|
||||
#endif
|
||||
|
@ -2371,22 +2371,11 @@ wp = ecpyalloc(_("no POSIX environment variable for zone"));
|
||||
* Rule Brazil is impacted by this limitation, because
|
||||
* the final set of rules are starting in 2038. Although
|
||||
* this code put the first couple of transitions populated
|
||||
* by the final rules, they will be dropped off when
|
||||
* collecting transition times. So, we need to keep
|
||||
* the start year of the final rule in 2038, not 2039.
|
||||
* Fortunately, the Brazil rules in 2038 and beyond use
|
||||
* the same base offset/dst saving amount. Thus, even
|
||||
* we skip the first couple of transitions, the final
|
||||
* rule set for 2038 works properly. So for now,
|
||||
* we do not increment the final rule start year only when
|
||||
* it falls into year 2038. We need to revisit this code
|
||||
* in future to fix the root cause of this problem (ICU
|
||||
* resource type limitation - signed int32).
|
||||
* Oct 7, 2008 - Yoshito */
|
||||
int finalStartYear = (year == 2038) ? year : year + 1;
|
||||
* by the final rules, they might be dropped off when
|
||||
* collecting transition times by tz2icu. */
|
||||
emit_icu_zone(icuFile,
|
||||
zpfirst->z_name, zp->z_gmtoff,
|
||||
rp, finalRuleIndex, finalStartYear);
|
||||
rp, finalRuleIndex, year + 1);
|
||||
/* only emit this for the first year */
|
||||
finalRule1 = NULL;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user