static icu::UInitOnce gStaticZonesInitOnce {}; static UBool gStaticZonesInitialized = false; // Whether the static zones are initialized and ready to use.
for (;;) {
mid = static_cast<int32_t>((start + limit) / 2); if (lastMid == mid) { /* Have we moved? */ break; /* We haven't moved, and it wasn't found. */
}
lastMid = mid;
u = ures_getStringByIndex(array, mid, &len, &status); if (U_FAILURE(status)) { break;
}
U_DEBUG_TZ_MSG(("tz: compare to %s, %d .. [%d] .. %d\n", U_DEBUG_TZ_STR(u), start, mid, limit));
copy.setTo(true, u, len); int r = id.compare(copy); if(r==0) {
U_DEBUG_TZ_MSG(("fisa: found at %d\n", mid)); return mid;
} elseif(r<0) {
limit = mid;
} else {
start = mid;
}
}
U_DEBUG_TZ_MSG(("fisa: not found\n")); return -1;
}
/** * Fetch a specific zone by name. Replaces the getByKey call. * @param top Top timezone resource * @param id Time zone ID * @param oldbundle Bundle for reuse (or nullptr). see 'ures_open()' * @return the zone's bundle if found, or undefined if error. Reuses oldbundle.
*/ static UResourceBundle* getZoneByName(const UResourceBundle* top, const UnicodeString& id, UResourceBundle *oldbundle, UErrorCode& status) { // load the Rules object
UResourceBundle *tmp = ures_getByKey(top, kNAMES, nullptr, &status);
// search for the string
int32_t idx = findInStringArray(tmp, id, status);
if((idx == -1) && U_SUCCESS(status)) { // not found
status = U_MISSING_RESOURCE_ERROR; //ures_close(oldbundle); //oldbundle = nullptr;
} else {
U_DEBUG_TZ_MSG(("gzbn: oldbundle= size %d, type %d, %s\n", ures_getSize(tmp), ures_getType(tmp), u_errorName(status)));
tmp = ures_getByKey(top, kZONES, tmp, &status); // get Zones object from top
U_DEBUG_TZ_MSG(("gzbn: loaded ZONES, size %d, type %d, path %s %s\n", ures_getSize(tmp), ures_getType(tmp), ures_getPath(tmp), u_errorName(status)));
oldbundle = ures_getByIndex(tmp, idx, oldbundle, &status); // get nth Zone object
U_DEBUG_TZ_MSG(("gzbn: loaded z#%d, size %d, type %d, path %s, %s\n", idx, ures_getSize(oldbundle), ures_getType(oldbundle), ures_getPath(oldbundle), u_errorName(status)));
}
ures_close(tmp); if(U_FAILURE(status)) { //ures_close(oldbundle); return nullptr;
} else { return oldbundle;
}
}
/** * Given an ID, open the appropriate resource for the given time zone. * Dereference aliases if necessary. * @param id zone id * @param res resource, which must be ready for use (initialized but not open) * @param ec input-output error code * @return top-level resource bundle
*/ static UResourceBundle* openOlsonResource(const UnicodeString& id,
UResourceBundle& res,
UErrorCode& ec)
{ #ifdef U_DEBUG_TZ char buf[128];
id.extract(0, sizeof(buf)-1, buf, sizeof(buf), ""); #endif
UResourceBundle *top = ures_openDirect(nullptr, kZONEINFO, &ec);
U_DEBUG_TZ_MSG(("pre: res sz=%d\n", ures_getSize(&res))); /* &res = */ getZoneByName(top, id, &res, ec); // 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_getType(&res) == URES_INT) {
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, nullptr, &ec); // dereference Zones section
ures_getByIndex(ares, deref, &res, &ec);
ures_close(ares);
U_DEBUG_TZ_MSG(("alias to #%d (%s) - %s\n", deref, "??", u_errorName(ec)));
} else {
U_DEBUG_TZ_MSG(("not an alias - size %d\n", ures_getSize(&res)));
}
U_DEBUG_TZ_MSG(("%s - final status is %s\n", buf, u_errorName(ec))); return top;
}
// -------------------------------------
namespace {
void U_CALLCONV initStaticTimeZones() { // Initialize _GMT independently of other static data; it should // be valid even if we can't load the time zone UDataMemory.
ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
// new can't fail below, as we use placement new into statically allocated space. new(gRawGMT) SimpleTimeZone(0, UnicodeString(true, GMT_ID, GMT_ID_LENGTH)); new(gRawUNKNOWN) SimpleTimeZone(0, UnicodeString(true, UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH));
namespace {
TimeZone*
createSystemTimeZone(const UnicodeString& id, UErrorCode& ec) { if (U_FAILURE(ec)) { return nullptr;
}
TimeZone* z = nullptr;
StackUResourceBundle res;
U_DEBUG_TZ_MSG(("pre-err=%s\n", u_errorName(ec)));
UResourceBundle *top = openOlsonResource(id, res.ref(), ec);
U_DEBUG_TZ_MSG(("post-err=%s\n", u_errorName(ec))); if (U_SUCCESS(ec)) {
z = new OlsonTimeZone(top, res.getAlias(), id, ec); if (z == nullptr) {
ec = U_MEMORY_ALLOCATION_ERROR;
U_DEBUG_TZ_MSG(("cstz: olson time zone failed to initialize - err %s\n", u_errorName(ec)));
}
}
ures_close(top); if (U_FAILURE(ec)) {
U_DEBUG_TZ_MSG(("cstz: failed to create, err %s\n", u_errorName(ec))); delete z;
z = nullptr;
} return z;
}
/** * Lookup the given name in our system zone table. If found, * instantiate a new zone of that name and return it. If not * found, return 0.
*/
TimeZone*
createSystemTimeZone(const UnicodeString& id) {
UErrorCode ec = U_ZERO_ERROR; return createSystemTimeZone(id, ec);
}
}
TimeZone* U_EXPORT2
TimeZone::createTimeZone(const UnicodeString& ID)
{ /* We first try to lookup the zone ID in our system list. If this * fails, we try to parse it as a custom string GMT[+-]hh:mm. If * all else fails, we return GMT, which is probably not what the * user wants, but at least is a functioning TimeZone object. * * We cannot return nullptr, because that would break compatibility * with the JDK.
*/
TimeZone* result = createSystemTimeZone(ID);
if (result == nullptr) {
U_DEBUG_TZ_MSG(("failed to load system time zone with id - falling to custom"));
result = createCustomTimeZone(ID);
} if (result == nullptr) {
U_DEBUG_TZ_MSG(("failed to load time zone with id - falling to Etc/Unknown(GMT)")); const TimeZone& unknown = getUnknown(); // Unknown zone uses statically allocated memory, so creation of it can never fail due to OOM.
result = unknown.clone();
} return result;
}
// -------------------------------------
TimeZone* U_EXPORT2
TimeZone::detectHostTimeZone()
{ // We access system timezone data through uprv_tzset(), uprv_tzname(), and others, // which have platform specific implementations in putil.cpp
int32_t rawOffset = 0; constchar *hostID;
UBool hostDetectionSucceeded = true;
// First, try to create a system timezone, based // on the string ID in tzname[0].
uprv_tzset(); // Initialize tz... system data
uprv_tzname_clear_cache();
// Get the timezone ID from the host. This function should do // any required host-specific remapping; e.g., on Windows this // function maps the Windows Time Zone name to an ICU timezone ID.
hostID = uprv_tzname(0);
// Invert sign because UNIX semantics are backwards
rawOffset = uprv_timezone() * -U_MILLIS_PER_SECOND;
TimeZone* hostZone = nullptr;
UnicodeString hostStrID(hostID, -1, US_INV);
if (hostStrID.length() == 0) { // The host time zone detection (or remapping) above has failed and // we have no name at all. Fallback to using the Unknown zone.
hostStrID = UnicodeString(true, UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH);
hostDetectionSucceeded = false;
}
hostZone = createSystemTimeZone(hostStrID);
#if U_PLATFORM_USES_ONLY_WIN32_API // hostID points to a heap-allocated location on Windows.
uprv_free(const_cast<char *>(hostID)); #endif
int32_t hostIDLen = hostStrID.length(); if (hostZone != nullptr && rawOffset != hostZone->getRawOffset()
&& (3 <= hostIDLen && hostIDLen <= 4))
{ // Uh oh. This probably wasn't a good id. // It was probably an ambiguous abbreviation delete hostZone;
hostZone = nullptr;
}
// Construct a fixed standard zone with the host's ID // and raw offset. if (hostZone == nullptr && hostDetectionSucceeded) {
hostZone = new SimpleTimeZone(rawOffset, hostStrID);
}
// If we _still_ don't have a time zone, use the Unknown zone. // // Note: This is extremely unlikely situation. If // new SimpleTimeZone(...) above fails, the following // code may also fail. if (hostZone == nullptr) { // Unknown zone uses static allocated memory, so it must always exist. // However, clone() allocates memory and can fail.
hostZone = TimeZone::getUnknown().clone();
}
return hostZone;
}
// -------------------------------------
static UMutex gDefaultZoneMutex;
/** * Initialize DEFAULT_ZONE from the system default time zone. * Upon return, DEFAULT_ZONE will not be nullptr, unless operator new() * returns nullptr.
*/ staticvoid U_CALLCONV initDefault()
{
ucln_i18n_registerCleanup(UCLN_I18N_TIMEZONE, timeZone_cleanup);
Mutex lock(&gDefaultZoneMutex); // If setDefault() has already been called we can skip getting the // default zone information from the system. if (DEFAULT_ZONE != nullptr) { return;
}
// NOTE: this code is safely single threaded, being only // run via umtx_initOnce(). // // Some of the locale/timezone OS functions may not be thread safe, // // The operating system might actually use ICU to implement timezones. // So we may have ICU calling ICU here, like on AIX. // There shouldn't be a problem with this; initOnce does not hold a mutex // while the init function is being run.
// The code detecting the host time zone was separated from this // and implemented as TimeZone::detectHostTimeZone()
UResourceBundle *res = ures_openDirect(nullptr, kZONEINFO, &ec);
res = ures_getByKey(res, kNAMES, res, &ec); // dereference Zones section if (U_SUCCESS(ec)) {
int32_t size = ures_getSize(res);
int32_t* m = static_cast<int32_t*>(uprv_malloc(size * sizeof(int32_t))); if (m == nullptr) {
ec = U_MEMORY_ALLOCATION_ERROR;
} else {
int32_t numEntries = 0; for (int32_t i = 0; i < size; i++) {
UnicodeString id = ures_getUnicodeStringByIndex(res, i, &ec); if (U_FAILURE(ec)) { break;
} if (0 == id.compare(UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH)) { // exclude Etc/Unknown continue;
} if (type == UCAL_ZONE_TYPE_CANONICAL || type == UCAL_ZONE_TYPE_CANONICAL_LOCATION) {
UnicodeString canonicalID;
ZoneMeta::getCanonicalCLDRID(id, canonicalID, ec); if (U_FAILURE(ec)) { break;
} if (canonicalID != id) { // exclude aliases continue;
}
} if (type == UCAL_ZONE_TYPE_CANONICAL_LOCATION) { const char16_t *region = TimeZone::getRegion(id, ec); if (U_FAILURE(ec)) { break;
} if (u_strcmp(region, WORLD) == 0) { // exclude non-location ("001") continue;
}
}
m[numEntries++] = i;
} if (U_SUCCESS(ec)) {
int32_t *tmp = m;
m = static_cast<int32_t*>(uprv_realloc(tmp, numEntries * sizeof(int32_t))); if (m == nullptr) { // realloc failed.. use the original one even it has unused // area at the end
m = tmp;
}
switch(type) { case UCAL_ZONE_TYPE_ANY:
U_ASSERT(MAP_SYSTEM_ZONES == nullptr);
MAP_SYSTEM_ZONES = m;
LEN_SYSTEM_ZONES = numEntries; break; case UCAL_ZONE_TYPE_CANONICAL:
U_ASSERT(MAP_CANONICAL_SYSTEM_ZONES == nullptr);
MAP_CANONICAL_SYSTEM_ZONES = m;
LEN_CANONICAL_SYSTEM_ZONES = numEntries; break; case UCAL_ZONE_TYPE_CANONICAL_LOCATION:
U_ASSERT(MAP_CANONICAL_SYSTEM_LOCATION_ZONES == nullptr);
MAP_CANONICAL_SYSTEM_LOCATION_ZONES = m;
LEN_CANONICAL_SYSTEM_LOCATION_ZONES = numEntries; break;
}
}
}
}
ures_close(res);
}
/** * This is the default implementation for subclasses that do not * override this method. This implementation calls through to the * 8-argument getOffset() method after suitable computations, and * correctly adjusts GMT millis to local millis when necessary.
*/ void TimeZone::getOffset(UDate date, UBool local, int32_t& rawOffset,
int32_t& dstOffset, UErrorCode& ec) const { if (U_FAILURE(ec)) { return;
}
rawOffset = getRawOffset(); if (!local) {
date += rawOffset; // now in local standard millis
}
// When local == true, date might not be in local standard // millis. getOffset taking 7 parameters used here assume // the given time in day is local standard time. // At STD->DST transition, there is a range of time which // does not exist. When 'date' is in this time range // (and local == true), this method interprets the specified // local time as DST. At DST->STD transition, there is a // range of time which occurs twice. In this case, this // method interprets the specified local time as STD. // To support the behavior above, we need to call getOffset // (with 7 args) twice when local == true and DST is // detected in the initial call. for (int32_t pass=0; ; ++pass) {
int32_t year, month, dom, dow, millis; double day = ClockMath::floorDivide(date, U_MILLIS_PER_DAY, &millis);
// out of the range if (day < INT32_MIN || day > INT32_MAX) {
ec = U_ILLEGAL_ARGUMENT_ERROR; return;
}
Grego::dayToFields(day, year, month, dom, dow, ec); if (U_FAILURE(ec)) return;
// Recompute if local==true, dstOffset!=0. if (pass!=0 || !local || dstOffset == 0) { break;
} // adjust to local standard millis
date -= dstOffset;
}
}
// -------------------------------------
// New available IDs API as of ICU 2.4. Uses StringEnumeration API.
class TZEnumeration : public StringEnumeration { private:
// Map into to zones. Our results are zone[map[i]] for // i=0..len-1, where zone[i] is the i-th Olson zone. If map==nullptr // then our results are zone[i] for i=0..len-1. Len will be zero // if the zone data could not be loaded.
int32_t* map;
int32_t* localMap;
int32_t len;
int32_t pos;
// Walk through the base map
UResourceBundle *res = ures_openDirect(nullptr, kZONEINFO, &ec);
res = ures_getByKey(res, kNAMES, res, &ec); // dereference Zones section for (int32_t i = 0; i < baseLen; i++) {
int32_t zidx = baseMap[i];
UnicodeString id = ures_getUnicodeStringByIndex(res, zidx, &ec); if (U_FAILURE(ec)) { break;
} if (region != nullptr) { // Filter by region char tzregion[4]; // max 3 letters + null term
TimeZone::getRegion(id, tzregion, sizeof(tzregion), ec); if (U_FAILURE(ec)) { break;
} if (uprv_stricmp(tzregion, region) != 0) { // region does not match continue;
}
} if (rawOffset != nullptr) { // Filter by raw offset // Note: This is VERY inefficient
TimeZone *z = createSystemTimeZone(id, ec); if (U_FAILURE(ec)) { break;
}
int32_t tzoffset = z->getRawOffset(); delete z;
// resolve zone index by name
UResourceBundle *names = ures_getByKey(rb, kNAMES, nullptr, &ec);
int32_t idx = findInStringArray(names, id, ec);
result = ures_getStringByIndex(names, idx, nullptr, &ec);
// open the zone bundle by index
ures_getByKey(rb, kZONES, rb, &ec);
ures_getByIndex(rb, idx, rb, &ec);
if (U_SUCCESS(ec)) { if (ures_getType(rb) == URES_INT) { // this is a link - dereference the link
int32_t deref = ures_getInt(rb, &ec); const char16_t* tmp = ures_getStringByIndex(names, deref, nullptr, &ec); if (U_SUCCESS(ec)) {
result = tmp;
}
}
}
const char16_t *uregion = nullptr; // "Etc/Unknown" is not a system zone ID, // but in the zone data if (id.compare(UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH) != 0) {
uregion = getRegion(id);
} if (uregion == nullptr) {
status = U_ILLEGAL_ARGUMENT_ERROR; return 0;
}
resultLen = u_strlen(uregion); // A region code is represented by invariant characters
u_UCharsToChars(uregion, region, uprv_min(resultLen, capacity));
if (capacity < resultLen) {
status = U_BUFFER_OVERFLOW_ERROR; return resultLen;
}
/** * Parse a custom time zone identifier and return a corresponding zone. * @param id a string of the form GMT[+-]hh:mm, GMT[+-]hhmm, or * GMT[+-]hh. * @return a newly created SimpleTimeZone with the given offset and * no Daylight Savings Time, or null if the id cannot be parsed.
*/
TimeZone*
TimeZone::createCustomTimeZone(const UnicodeString& id)
{
int32_t sign, hour, min, sec; if (parseCustomID(id, sign, hour, min, sec)) {
UnicodeString customID;
formatCustomID(hour, min, sec, (sign < 0), customID);
int32_t offset = sign * ((hour * 60 + min) * 60 + sec) * 1000; returnnew SimpleTimeZone(offset, customID);
} return nullptr;
}
if (id[GMT_ID_LENGTH] == MINUS /*'-'*/) {
sign = -1;
} elseif (id[GMT_ID_LENGTH] != PLUS /*'+'*/) { returnfalse;
}
int32_t start = GMT_ID_LENGTH + 1;
int32_t pos = start;
hour = ICU_Utility::parseNumber(id, pos, 10); if (pos == id.length()) { // Handle the following cases // HHmmss // Hmmss // HHmm // Hmm // HH // H
// Get all digits // Should be 1 to 6 digits.
int32_t length = pos - start; switch (length) { case 1: // H case 2: // HH // already set to hour break; case 3: // Hmm case 4: // HHmm
min = hour % 100;
hour /= 100; break; case 5: // Hmmss case 6: // HHmmss
sec = hour % 100;
min = (hour/100) % 100;
hour /= 10000; break; default: // invalid range returnfalse;
}
} else { // Handle the following cases // HH:mm:ss // H:mm:ss // HH:mm // H:mm if (pos - start < 1 || pos - start > 2 || id[pos] != COLON) { returnfalse;
}
pos++; // skip : after H or HH if (id.length() == pos) { returnfalse;
}
start = pos;
min = ICU_Utility::parseNumber(id, pos, 10); if (pos - start != 2) { returnfalse;
} if (id.length() > pos) { if (id[pos] != COLON) { returnfalse;
}
pos++; // skip : after mm
start = pos;
sec = ICU_Utility::parseNumber(id, pos, 10); if (pos - start != 2 || id.length() > pos) { returnfalse;
}
}
} if (hour > kMAX_CUSTOM_HOUR ||
min > kMAX_CUSTOM_MIN ||
sec > kMAX_CUSTOM_SEC) { returnfalse;
} returntrue;
}
UnicodeString&
TimeZone::formatCustomID(int32_t hour, int32_t min, int32_t sec,
UBool negative, UnicodeString& id) { // Create time zone ID - GMT[+|-]hhmm[ss]
id.setTo(GMT_ID, GMT_ID_LENGTH); if (hour | min | sec) { if (negative) {
id += static_cast<char16_t>(MINUS);
} else {
id += static_cast<char16_t>(PLUS);
}
if (hour < 10) {
id += static_cast<char16_t>(ZERO_DIGIT);
} else {
id += static_cast<char16_t>(ZERO_DIGIT + hour / 10);
}
id += static_cast<char16_t>(ZERO_DIGIT + hour % 10);
id += static_cast<char16_t>(COLON); if (min < 10) {
id += static_cast<char16_t>(ZERO_DIGIT);
} else {
id += static_cast<char16_t>(ZERO_DIGIT + min / 10);
}
id += static_cast<char16_t>(ZERO_DIGIT + min % 10);
if (sec) {
id += static_cast<char16_t>(COLON); if (sec < 10) {
id += static_cast<char16_t>(ZERO_DIGIT);
} else {
id += static_cast<char16_t>(ZERO_DIGIT + sec / 10);
}
id += static_cast<char16_t>(ZERO_DIGIT + sec % 10);
}
} return id;
}
if (U_SUCCESS(status)) { if (len >= static_cast<int32_t>(sizeof(TZDATA_VERSION))) { // Ensure that there is always space for a trailing nul in TZDATA_VERSION
len = sizeof(TZDATA_VERSION) - 1;
}
u_UCharsToChars(tzver, TZDATA_VERSION, len);
}
}
UnicodeString&
TimeZone::getCanonicalID(const UnicodeString& id, UnicodeString& canonicalID, UBool& isSystemID,
UErrorCode& status)
{
canonicalID.remove();
isSystemID = false; if (U_FAILURE(status)) { return canonicalID;
} if (id.compare(UNKNOWN_ZONE_ID, UNKNOWN_ZONE_ID_LENGTH) == 0) { // special case - Etc/Unknown is a canonical ID, but not system ID
canonicalID.fastCopyFrom(id);
isSystemID = false;
} else {
ZoneMeta::getCanonicalCLDRID(id, canonicalID, status); if (U_SUCCESS(status)) {
isSystemID = true;
} else { // Not a system ID
status = U_ZERO_ERROR;
getCustomID(id, canonicalID, status);
}
} return canonicalID;
}
// canonicalize the input ID
UnicodeString canonicalID;
UBool isSystemID = false;
getCanonicalID(id, canonicalID, isSystemID, status); if (U_FAILURE(status) || !isSystemID) { // mapping data is only applicable to tz database IDs if (status == U_ILLEGAL_ARGUMENT_ERROR) { // getWindowsID() sets an empty string where // getCanonicalID() sets a U_ILLEGAL_ARGUMENT_ERROR.
status = U_ZERO_ERROR;
} return winid;
}
ures_getByKey(zones, winidKey, zones, &tmperr); // use tmperr, because windows mapping might not // be available by design if (U_FAILURE(tmperr)) {
ures_close(zones); return id;
}
const char16_t *tzid = nullptr;
int32_t len = 0;
UBool gotID = false; if (region) { const char16_t *tzids = ures_getStringByKey(zones, region, &len, &tmperr); // use tmperr, because // regional mapping is optional if (U_SUCCESS(tmperr)) { // first ID delimited by space is the default one const char16_t* end = u_strchr(tzids, static_cast<char16_t>(0x20)); if (end == nullptr) {
id.setTo(tzids, -1);
} else {
id.setTo(tzids, static_cast<int32_t>(end - tzids));
}
gotID = true;
}
}
if (!gotID) {
tzid = ures_getStringByKey(zones, "001", &len, &status); // using status, because "001" must be // available at this point if (U_SUCCESS(status)) {
id.setTo(tzid, len);
}
}
ures_close(zones); return id;
}
U_NAMESPACE_END
#endif/* #if !UCONFIG_NO_FORMATTING */
//eof
Messung V0.5
¤ Dauer der Verarbeitung: 0.56 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.