]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/vtzone.cpp
ICU-64260.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / vtzone.cpp
index de37e2e068ce44b30fa4eb47e67ca38941857bfb..cb84c6260f630ca5e7cad41fc068e1b5ef376e0e 100644 (file)
@@ -1,10 +1,14 @@
+// © 2016 and later: Unicode, Inc. and others.
+// License & terms of use: http://www.unicode.org/copyright.html
 /*
 *******************************************************************************
-* Copyright (C) 2007-2008, International Business Machines Corporation and    *
-* others. All Rights Reserved.                                                *
+* Copyright (C) 2007-2016, International Business Machines Corporation and
+* others. All Rights Reserved.
 *******************************************************************************
 */
 
+#include "utypeinfo.h"  // for 'typeid' to work
+
 #include "unicode/utypes.h"
 
 #if !UCONFIG_NO_FORMATTING
@@ -16,7 +20,7 @@
 #include "cmemory.h"
 #include "uvector.h"
 #include "gregoimp.h"
-#include "uhash.h"
+#include "uassert.h"
 
 U_NAMESPACE_BEGIN
 
@@ -131,7 +135,7 @@ static UnicodeString& appendAsciiDigits(int32_t number, uint8_t length, UnicodeS
             digits[i++] = number % 10;
             number /= 10;
         } while (number != 0);
-        length = i;
+        length = static_cast<uint8_t>(i);
     } else {
         // fixed digits
         for (i = 0; i < length; i++) {
@@ -354,12 +358,12 @@ static void millisToOffset(int32_t millis, UnicodeString& str) {
 /*
  * Create a default TZNAME from TZID
  */
-static void getDefaultTZName(const UnicodeString tzid, UBool isDST, UnicodeString& tzname) {
-    tzname = tzid;
+static void getDefaultTZName(const UnicodeString &tzid, UBool isDST, UnicodeString& zonename) {
+    zonename = tzid;
     if (isDST) {
-        tzname += UNICODE_STRING_SIMPLE("(DST)");
+        zonename += UNICODE_STRING_SIMPLE("(DST)");
     } else {
-        tzname += UNICODE_STRING_SIMPLE("(STD)");
+        zonename += UNICODE_STRING_SIMPLE("(STD)");
     }
 }
 
@@ -412,20 +416,20 @@ static void parseRRULE(const UnicodeString& rrule, int32_t& month, int32_t& dow,
             goto rruleParseError;
         }
 
-        if (attr.compare(ICAL_FREQ) == 0) {
+        if (attr.compare(ICAL_FREQ, -1) == 0) {
             // only support YEARLY frequency type
-            if (value.compare(ICAL_YEARLY) == 0) {
+            if (value.compare(ICAL_YEARLY, -1) == 0) {
                 yearly = TRUE;
             } else {
                 goto rruleParseError;
             }
-        } else if (attr.compare(ICAL_UNTIL) == 0) {
+        } else if (attr.compare(ICAL_UNTIL, -1) == 0) {
             // ISO8601 UTC format, for example, "20060315T020000Z"
             until = parseDateTimeString(value, 0, status);
             if (U_FAILURE(status)) {
                 goto rruleParseError;
             }
-        } else if (attr.compare(ICAL_BYMONTH) == 0) {
+        } else if (attr.compare(ICAL_BYMONTH, -1) == 0) {
             // Note: BYMONTH may contain multiple months, but only single month make sense for
             // VTIMEZONE property.
             if (value.length() > 2) {
@@ -435,7 +439,7 @@ static void parseRRULE(const UnicodeString& rrule, int32_t& month, int32_t& dow,
             if (U_FAILURE(status) || month < 0 || month >= 12) {
                 goto rruleParseError;
             }
-        } else if (attr.compare(ICAL_BYDAY) == 0) {
+        } else if (attr.compare(ICAL_BYDAY, -1) == 0) {
             // Note: BYDAY may contain multiple day of week separated by comma.  It is unlikely used for
             // VTIMEZONE property.  We do not support the case.
 
@@ -474,7 +478,7 @@ static void parseRRULE(const UnicodeString& rrule, int32_t& month, int32_t& dow,
             } else {
                 goto rruleParseError;
             }
-        } else if (attr.compare(ICAL_BYMONTHDAY) == 0) {
+        } else if (attr.compare(ICAL_BYMONTHDAY, -1) == 0) {
             // Note: BYMONTHDAY may contain multiple days delimitted by comma
             //
             // A value of BYMONTHDAY could be negative, for example, -1 means
@@ -519,7 +523,7 @@ rruleParseError:
     }
 }
 
-static TimeZoneRule* createRuleByRRULE(const UnicodeString& tzname, int rawOffset, int dstSavings, UDate start,
+static TimeZoneRule* createRuleByRRULE(const UnicodeString& zonename, int rawOffset, int dstSavings, UDate start,
                                        UVector* dates, int fromOffset, UErrorCode& status) {
     if (U_FAILURE(status)) {
         return NULL;
@@ -536,7 +540,7 @@ static TimeZoneRule* createRuleByRRULE(const UnicodeString& tzname, int rawOffse
     UnicodeString rrule = *((UnicodeString*)dates->elementAt(0));
     int32_t month, dayOfWeek, nthDayOfWeek, dayOfMonth = 0;
     int32_t days[7];
-    int32_t daysCount = sizeof(days)/sizeof(days[0]);
+    int32_t daysCount = UPRV_LENGTHOF(days);
     UDate until;
 
     parseRRULE(rrule, month, dayOfWeek, nthDayOfWeek, days, daysCount, until, status);
@@ -613,7 +617,7 @@ static TimeZoneRule* createRuleByRRULE(const UnicodeString& tzname, int rawOffse
             UDate tmp_until;
             int32_t tmp_month, tmp_dayOfWeek, tmp_nthDayOfWeek;
             int32_t tmp_days[7];
-            int32_t tmp_daysCount = sizeof(tmp_days)/sizeof(tmp_days[0]);
+            int32_t tmp_daysCount = UPRV_LENGTHOF(tmp_days);
             parseRRULE(rrule, tmp_month, tmp_dayOfWeek, tmp_nthDayOfWeek, tmp_days, tmp_daysCount, tmp_until, status);
             if (U_FAILURE(status)) {
                 return NULL;
@@ -712,7 +716,7 @@ static TimeZoneRule* createRuleByRRULE(const UnicodeString& tzname, int rawOffse
     if (adtr == NULL) {
         goto unsupportedRRule;
     }
-    return new AnnualTimeZoneRule(tzname, rawOffset, dstSavings, adtr, startYear, endYear);
+    return new AnnualTimeZoneRule(zonename, rawOffset, dstSavings, adtr, startYear, endYear);
 
 unsupportedRRule:
     status = U_INVALID_STATE_ERROR;
@@ -722,7 +726,7 @@ unsupportedRRule:
 /*
  * Create a TimeZoneRule by the RDATE definition
  */
-static TimeZoneRule* createRuleByRDATE(const UnicodeString& tzname, int32_t rawOffset, int32_t dstSavings,
+static TimeZoneRule* createRuleByRDATE(const UnicodeString& zonename, int32_t rawOffset, int32_t dstSavings,
                                        UDate start, UVector* dates, int32_t fromOffset, UErrorCode& status) {
     if (U_FAILURE(status)) {
         return NULL;
@@ -731,7 +735,7 @@ static TimeZoneRule* createRuleByRDATE(const UnicodeString& tzname, int32_t rawO
     if (dates == NULL || dates->size() == 0) {
         // When no RDATE line is provided, use start (DTSTART)
         // as the transition time
-        retVal = new TimeArrayTimeZoneRule(tzname, rawOffset, dstSavings,
+        retVal = new TimeArrayTimeZoneRule(zonename, rawOffset, dstSavings,
             &start, 1, DateTimeRule::UTC_TIME);
     } else {
         // Create an array of transition times
@@ -749,7 +753,7 @@ static TimeZoneRule* createRuleByRDATE(const UnicodeString& tzname, int32_t rawO
                 return NULL;
             }
         }
-        retVal = new TimeArrayTimeZoneRule(tzname, rawOffset, dstSavings,
+        retVal = new TimeArrayTimeZoneRule(zonename, rawOffset, dstSavings,
             times, size, DateTimeRule::UTC_TIME);
         uprv_free(times);
     }
@@ -884,6 +888,7 @@ public:
 
     void write(const UnicodeString& str);
     void write(UChar ch);
+    void write(const UChar* str);
     //void write(const UChar* str, int32_t length);
 private:
     UnicodeString* out;
@@ -906,6 +911,11 @@ VTZWriter::write(UChar ch) {
     out->append(ch);
 }
 
+void
+VTZWriter::write(const UChar* str) {
+    out->append(str, -1);
+}
+
 /*
 void
 VTZWriter::write(const UChar* str, int32_t length) {
@@ -960,7 +970,7 @@ VTimeZone::VTimeZone(const VTimeZone& source)
     if (source.vtzlines != NULL) {
         UErrorCode status = U_ZERO_ERROR;
         int32_t size = source.vtzlines->size();
-        vtzlines = new UVector(uhash_deleteUnicodeString, uhash_compareUnicodeString, size, status);
+        vtzlines = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, size, status);
         if (U_SUCCESS(status)) {
             for (int32_t i = 0; i < size; i++) {
                 UnicodeString *line = (UnicodeString*)source.vtzlines->elementAt(i);
@@ -1005,7 +1015,7 @@ VTimeZone::operator=(const VTimeZone& right) {
         if (right.vtzlines != NULL) {
             UErrorCode status = U_ZERO_ERROR;
             int32_t size = right.vtzlines->size();
-            vtzlines = new UVector(uhash_deleteUnicodeString, uhash_compareUnicodeString, size, status);
+            vtzlines = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, size, status);
             if (U_SUCCESS(status)) {
                 for (int32_t i = 0; i < size; i++) {
                     UnicodeString *line = (UnicodeString*)right.vtzlines->elementAt(i);
@@ -1033,8 +1043,7 @@ VTimeZone::operator==(const TimeZone& that) const {
     if (this == &that) {
         return TRUE;
     }
-    if (getDynamicClassID() != that.getDynamicClassID()
-        || !BasicTimeZone::operator==(that)) {
+    if (typeid(*this) != typeid(that) || !BasicTimeZone::operator==(that)) {
         return FALSE;
     }
     VTimeZone *vtz = (VTimeZone*)&that;
@@ -1063,8 +1072,39 @@ VTimeZone::createVTimeZoneByID(const UnicodeString& ID) {
     UErrorCode status = U_ZERO_ERROR;
     UResourceBundle *bundle = NULL;
     const UChar* versionStr = NULL;
-    int32_t len;
-    bundle = ures_openDirect(NULL, "zoneinfo", &status);
+    int32_t len = 0;
+    bundle = ures_openDirect(NULL, "zoneinfo64", &status);
+    versionStr = ures_getStringByKey(bundle, "TZVersion", &len, &status);
+    if (U_SUCCESS(status)) {
+        vtz->icutzver.setTo(versionStr, len);
+    }
+    ures_close(bundle);
+    return vtz;
+}
+
+VTimeZone*
+VTimeZone::createVTimeZoneFromBasicTimeZone(const BasicTimeZone& basic_time_zone, UErrorCode &status) {
+    if (U_FAILURE(status)) {
+        return NULL;
+    }
+    VTimeZone *vtz = new VTimeZone();
+    if (vtz == NULL) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        return NULL;
+    }
+    vtz->tz = (BasicTimeZone *)basic_time_zone.clone();
+    if (vtz->tz == NULL) {
+        status = U_MEMORY_ALLOCATION_ERROR;
+        delete vtz;
+        return NULL;
+    }
+    vtz->tz->getID(vtz->olsonzid);
+
+    // Set ICU tzdata version
+    UResourceBundle *bundle = NULL;
+    const UChar* versionStr = NULL;
+    int32_t len = 0;
+    bundle = ures_openDirect(NULL, "zoneinfo64", &status);
     versionStr = ures_getStringByKey(bundle, "TZVersion", &len, &status);
     if (U_SUCCESS(status)) {
         vtz->icutzver.setTo(versionStr, len);
@@ -1124,14 +1164,14 @@ VTimeZone::write(UnicodeString& result, UErrorCode& status) const {
 }
 
 void
-VTimeZone::write(UDate start, UnicodeString& result, UErrorCode& status) /*const*/ {
+VTimeZone::write(UDate start, UnicodeString& result, UErrorCode& status) const {
     result.remove();
     VTZWriter writer(result);
     write(start, writer, status);
 }
 
 void
-VTimeZone::writeSimple(UDate time, UnicodeString& result, UErrorCode& status) /*const*/ {
+VTimeZone::writeSimple(UDate time, UnicodeString& result, UErrorCode& status) const {
     result.remove();
     VTZWriter writer(result);
     writeSimple(time, writer, status);
@@ -1187,30 +1227,30 @@ VTimeZone::hasSameRules(const TimeZone& other) const {
 }
 
 UBool
-VTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ {
+VTimeZone::getNextTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
     return tz->getNextTransition(base, inclusive, result);
 }
 
 UBool
-VTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) /*const*/ {
+VTimeZone::getPreviousTransition(UDate base, UBool inclusive, TimeZoneTransition& result) const {
     return tz->getPreviousTransition(base, inclusive, result);
 }
 
 int32_t
-VTimeZone::countTransitionRules(UErrorCode& status) /*const*/ {
+VTimeZone::countTransitionRules(UErrorCode& status) const {
     return tz->countTransitionRules(status);
 }
 
 void
 VTimeZone::getTimeZoneRules(const InitialTimeZoneRule*& initial,
                             const TimeZoneRule* trsrules[], int32_t& trscount,
-                            UErrorCode& status) /*const*/ {
+                            UErrorCode& status) const {
     tz->getTimeZoneRules(initial, trsrules, trscount, status);
 }
 
 void
 VTimeZone::load(VTZReader& reader, UErrorCode& status) {
-    vtzlines = new UVector(uhash_deleteUnicodeString, uhash_compareUnicodeString, DEFAULT_VTIMEZONE_LINES, status);
+    vtzlines = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, DEFAULT_VTIMEZONE_LINES, status);
     if (U_FAILURE(status)) {
         return;
     }
@@ -1223,7 +1263,7 @@ VTimeZone::load(VTZReader& reader, UErrorCode& status) {
         UChar ch = reader.read();
         if (ch == 0xFFFF) {
             // end of file
-            if (start && line.startsWith(ICAL_END_VTIMEZONE)) {
+            if (start && line.startsWith(ICAL_END_VTIMEZONE, -1)) {
                 vtzlines->addElement(new UnicodeString(line), status);
                 if (U_FAILURE(status)) {
                     goto cleanupVtzlines;
@@ -1258,7 +1298,7 @@ VTimeZone::load(VTZReader& reader, UErrorCode& status) {
                 // LF
                 eol = TRUE;
                 if (start) {
-                    if (line.startsWith(ICAL_END_VTIMEZONE)) {
+                    if (line.startsWith(ICAL_END_VTIMEZONE, -1)) {
                         vtzlines->addElement(new UnicodeString(line), status);
                         if (U_FAILURE(status)) {
                             goto cleanupVtzlines;
@@ -1267,7 +1307,7 @@ VTimeZone::load(VTZReader& reader, UErrorCode& status) {
                         break;
                     }
                 } else {
-                    if (line.startsWith(ICAL_BEGIN_VTIMEZONE)) {
+                    if (line.startsWith(ICAL_BEGIN_VTIMEZONE, -1)) {
                         vtzlines->addElement(new UnicodeString(line), status);
                         if (U_FAILURE(status)) {
                             goto cleanupVtzlines;
@@ -1324,7 +1364,7 @@ VTimeZone::parse(UErrorCode& status) {
     UBool dst = FALSE;      // current zone type
     UnicodeString from;     // current zone from offset
     UnicodeString to;       // current zone offset
-    UnicodeString tzname;   // current zone name
+    UnicodeString zonename;   // current zone name
     UnicodeString dtstart;  // current zone starts
     UBool isRRULE = FALSE;  // true if the rule is described by RRULE
     int32_t initialRawOffset = 0;   // initial offset
@@ -1346,7 +1386,7 @@ VTimeZone::parse(UErrorCode& status) {
      // Set the deleter to remove TimeZoneRule vectors to avoid memory leaks due to unowned TimeZoneRules.
     rules->setDeleter(deleteTimeZoneRule);
     
-    dates = new UVector(uhash_deleteUnicodeString, uhash_compareUnicodeString, status);
+    dates = new UVector(uprv_deleteUObject, uhash_compareUnicodeString, status);
     if (U_FAILURE(status)) {
         goto cleanupParse;
     }
@@ -1366,27 +1406,27 @@ VTimeZone::parse(UErrorCode& status) {
 
         switch (state) {
         case INI:
-            if (name.compare(ICAL_BEGIN) == 0
-                && value.compare(ICAL_VTIMEZONE) == 0) {
+            if (name.compare(ICAL_BEGIN, -1) == 0
+                && value.compare(ICAL_VTIMEZONE, -1) == 0) {
                 state = VTZ;
             }
             break;
 
         case VTZ:
-            if (name.compare(ICAL_TZID) == 0) {
+            if (name.compare(ICAL_TZID, -1) == 0) {
                 tzid = value;
-            } else if (name.compare(ICAL_TZURL) == 0) {
+            } else if (name.compare(ICAL_TZURL, -1) == 0) {
                 tzurl = value;
-            } else if (name.compare(ICAL_LASTMOD) == 0) {
+            } else if (name.compare(ICAL_LASTMOD, -1) == 0) {
                 // Always in 'Z' format, so the offset argument for the parse method
                 // can be any value.
                 lastmod = parseDateTimeString(value, 0, status);
                 if (U_FAILURE(status)) {
                     goto cleanupParse;
                 }
-            } else if (name.compare(ICAL_BEGIN) == 0) {
-                UBool isDST = (value.compare(ICAL_DAYLIGHT) == 0);
-                if (value.compare(ICAL_STANDARD) == 0 || isDST) {
+            } else if (name.compare(ICAL_BEGIN, -1) == 0) {
+                UBool isDST = (value.compare(ICAL_DAYLIGHT, -1) == 0);
+                if (value.compare(ICAL_STANDARD, -1) == 0 || isDST) {
                     // tzid must be ready at this point
                     if (tzid.length() == 0) {
                         goto cleanupParse;
@@ -1398,7 +1438,7 @@ VTimeZone::parse(UErrorCode& status) {
                     isRRULE = FALSE;
                     from.remove();
                     to.remove();
-                    tzname.remove();
+                    zonename.remove();
                     dst = isDST;
                     state = TZI;
                 } else {
@@ -1406,20 +1446,20 @@ VTimeZone::parse(UErrorCode& status) {
                     // must not be there.
                     goto cleanupParse;
                 }
-            } else if (name.compare(ICAL_END) == 0) {
+            } else if (name.compare(ICAL_END, -1) == 0) {
                 break;
             }
             break;
         case TZI:
-            if (name.compare(ICAL_DTSTART) == 0) {
+            if (name.compare(ICAL_DTSTART, -1) == 0) {
                 dtstart = value;
-            } else if (name.compare(ICAL_TZNAME) == 0) {
-                tzname = value;
-            } else if (name.compare(ICAL_TZOFFSETFROM) == 0) {
+            } else if (name.compare(ICAL_TZNAME, -1) == 0) {
+                zonename = value;
+            } else if (name.compare(ICAL_TZOFFSETFROM, -1) == 0) {
                 from = value;
-            } else if (name.compare(ICAL_TZOFFSETTO) == 0) {
+            } else if (name.compare(ICAL_TZOFFSETTO, -1) == 0) {
                 to = value;
-            } else if (name.compare(ICAL_RDATE) == 0) {
+            } else if (name.compare(ICAL_RDATE, -1) == 0) {
                 // RDATE mixed with RRULE is not supported
                 if (isRRULE) {
                     goto cleanupParse;
@@ -1443,7 +1483,7 @@ VTimeZone::parse(UErrorCode& status) {
                     }
                     dstart = dend + 1;
                 }
-            } else if (name.compare(ICAL_RRULE) == 0) {
+            } else if (name.compare(ICAL_RRULE, -1) == 0) {
                 // RRULE mixed with RDATE is not supported
                 if (!isRRULE && dates->size() != 0) {
                     goto cleanupParse;
@@ -1453,14 +1493,14 @@ VTimeZone::parse(UErrorCode& status) {
                 if (U_FAILURE(status)) {
                     goto cleanupParse;
                 }
-            } else if (name.compare(ICAL_END) == 0) {
+            } else if (name.compare(ICAL_END, -1) == 0) {
                 // Mandatory properties
                 if (dtstart.length() == 0 || from.length() == 0 || to.length() == 0) {
                     goto cleanupParse;
                 }
-                // if tzname is not available, create one from tzid
-                if (tzname.length() == 0) {
-                    getDefaultTZName(tzid, dst, tzname);
+                // if zonename is not available, create one from tzid
+                if (zonename.length() == 0) {
+                    getDefaultTZName(tzid, dst, zonename);
                 }
 
                 // create a time zone rule
@@ -1502,9 +1542,9 @@ VTimeZone::parse(UErrorCode& status) {
                 // Create the rule
                 UDate actualStart = MAX_MILLIS;
                 if (isRRULE) {
-                    rule = createRuleByRRULE(tzname, rawOffset, dstSavings, start, dates, fromOffset, status);
+                    rule = createRuleByRRULE(zonename, rawOffset, dstSavings, start, dates, fromOffset, status);
                 } else {
-                    rule = createRuleByRDATE(tzname, rawOffset, dstSavings, start, dates, fromOffset, status);
+                    rule = createRuleByRDATE(zonename, rawOffset, dstSavings, start, dates, fromOffset, status);
                 }
                 if (U_FAILURE(status) || rule == NULL) {
                     goto cleanupParse;
@@ -1545,8 +1585,8 @@ VTimeZone::parse(UErrorCode& status) {
     }
 
     // Create a initial rule
-    getDefaultTZName(tzid, FALSE, tzname);
-    initialRule = new InitialTimeZoneRule(tzname,
+    getDefaultTZName(tzid, FALSE, zonename);
+    initialRule = new InitialTimeZoneRule(zonename,
         initialRawOffset, initialDSTSavings);
     if (initialRule == NULL) {
         status = U_MEMORY_ALLOCATION_ERROR;
@@ -1563,8 +1603,9 @@ VTimeZone::parse(UErrorCode& status) {
 
     for (n = 0; n < rules->size(); n++) {
         TimeZoneRule *r = (TimeZoneRule*)rules->elementAt(n);
-        if (r->getDynamicClassID() == AnnualTimeZoneRule::getStaticClassID()) {
-            if (((AnnualTimeZoneRule*)r)->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) {
+        AnnualTimeZoneRule *atzrule = dynamic_cast<AnnualTimeZoneRule *>(r);
+        if (atzrule != NULL) {
+            if (atzrule->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) {
                 finalRuleCount++;
                 finalRuleIdx = n;
             }
@@ -1687,13 +1728,13 @@ VTimeZone::write(VTZWriter& writer, UErrorCode& status) const {
     if (vtzlines != NULL) {
         for (int32_t i = 0; i < vtzlines->size(); i++) {
             UnicodeString *line = (UnicodeString*)vtzlines->elementAt(i);
-            if (line->startsWith(ICAL_TZURL)
+            if (line->startsWith(ICAL_TZURL, -1)
                 && line->charAt(u_strlen(ICAL_TZURL)) == COLON) {
                 writer.write(ICAL_TZURL);
                 writer.write(COLON);
                 writer.write(tzurl);
                 writer.write(ICAL_NEWLINE);
-            } else if (line->startsWith(ICAL_LASTMOD)
+            } else if (line->startsWith(ICAL_LASTMOD, -1)
                 && line->charAt(u_strlen(ICAL_LASTMOD)) == COLON) {
                 UnicodeString utcString;
                 writer.write(ICAL_LASTMOD);
@@ -1706,37 +1747,27 @@ VTimeZone::write(VTZWriter& writer, UErrorCode& status) const {
             }
         }
     } else {
-        UVector *customProps = NULL;
+        UnicodeString icutzprop;
+        UVector customProps(nullptr, uhash_compareUnicodeString, status);
         if (olsonzid.length() > 0 && icutzver.length() > 0) {
-            customProps = new UVector(uhash_deleteUnicodeString, uhash_compareUnicodeString, status);
-            if (U_FAILURE(status)) {
-                return;
-            }
-            UnicodeString *icutzprop = new UnicodeString(ICU_TZINFO_PROP);
-            icutzprop->append(olsonzid);
-            icutzprop->append((UChar)0x005B/*'['*/);
-            icutzprop->append(icutzver);
-            icutzprop->append((UChar)0x005D/*']'*/);
-            customProps->addElement(icutzprop, status);
-            if (U_FAILURE(status)) {
-                delete icutzprop;
-                delete customProps;
-                return;
-            }
+            icutzprop.append(olsonzid);
+            icutzprop.append(u'[');
+            icutzprop.append(icutzver);
+            icutzprop.append(u']');
+            customProps.addElement(&icutzprop, status);
         }
-        writeZone(writer, *tz, customProps, status);
-        delete customProps;
+        writeZone(writer, *tz, &customProps, status);
     }
 }
 
 void
-VTimeZone::write(UDate start, VTZWriter& writer, UErrorCode& status) /*const*/ {
+VTimeZone::write(UDate start, VTZWriter& writer, UErrorCode& status) const {
     if (U_FAILURE(status)) {
         return;
     }
     InitialTimeZoneRule *initial = NULL;
     UVector *transitionRules = NULL;
-    UVector customProps(uhash_deleteUnicodeString, uhash_compareUnicodeString, status);
+    UVector customProps(uprv_deleteUObject, uhash_compareUnicodeString, status);
     UnicodeString tzid;
 
     // Extract rules applicable to dates after the start time
@@ -1769,7 +1800,7 @@ VTimeZone::write(UDate start, VTZWriter& writer, UErrorCode& status) /*const*/ {
         icutzprop->append(olsonzid);
         icutzprop->append((UChar)0x005B/*'['*/);
         icutzprop->append(icutzver);
-        icutzprop->append(ICU_TZINFO_PARTIAL);
+        icutzprop->append(ICU_TZINFO_PARTIAL, -1);
         appendMillis(start, *icutzprop);
         icutzprop->append((UChar)0x005D/*']'*/);
         customProps.addElement(icutzprop, status);
@@ -1795,12 +1826,12 @@ cleanupWritePartial:
 }
 
 void
-VTimeZone::writeSimple(UDate time, VTZWriter& writer, UErrorCode& status) /*const*/ {
+VTimeZone::writeSimple(UDate time, VTZWriter& writer, UErrorCode& status) const {
     if (U_FAILURE(status)) {
         return;
     }
 
-    UVector customProps(uhash_deleteUnicodeString, uhash_compareUnicodeString, status);
+    UVector customProps(uprv_deleteUObject, uhash_compareUnicodeString, status);
     UnicodeString tzid;
 
     // Extract simple rules
@@ -1824,7 +1855,7 @@ VTimeZone::writeSimple(UDate time, VTZWriter& writer, UErrorCode& status) /*cons
             icutzprop->append(olsonzid);
             icutzprop->append((UChar)0x005B/*'['*/);
             icutzprop->append(icutzver);
-            icutzprop->append(ICU_TZINFO_SIMPLE);
+            icutzprop->append(ICU_TZINFO_SIMPLE, -1);
             appendMillis(time, *icutzprop);
             icutzprop->append((UChar)0x005D/*']'*/);
             customProps.addElement(icutzprop, status);
@@ -1920,12 +1951,13 @@ VTimeZone::writeZone(VTZWriter& w, BasicTimeZone& basictz,
         Grego::timeToFields(tzt.getTime() + fromOffset, year, month, dom, dow, doy, mid);
         int32_t weekInMonth = Grego::dayOfWeekInMonth(year, month, dom);
         UBool sameRule = FALSE;
+        const AnnualTimeZoneRule *atzrule;
         if (isDst) {
             if (finalDstRule == NULL
-                && tzt.getTo()->getDynamicClassID() == AnnualTimeZoneRule::getStaticClassID()) {
-                if (((AnnualTimeZoneRule*)tzt.getTo())->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) {
-                    finalDstRule = (AnnualTimeZoneRule*)tzt.getTo()->clone();
-                }
+                && (atzrule = dynamic_cast<const AnnualTimeZoneRule *>(tzt.getTo())) != NULL
+                && atzrule->getEndYear() == AnnualTimeZoneRule::MAX_YEAR
+            ) {
+                finalDstRule = (AnnualTimeZoneRule*)tzt.getTo()->clone();
             }
             if (dstCount > 0) {
                 if (year == dstStartYear + dstCount
@@ -1973,10 +2005,10 @@ VTimeZone::writeZone(VTZWriter& w, BasicTimeZone& basictz,
             }
         } else {
             if (finalStdRule == NULL
-                && tzt.getTo()->getDynamicClassID() == AnnualTimeZoneRule::getStaticClassID()) {
-                    if (((AnnualTimeZoneRule*)tzt.getTo())->getEndYear() == AnnualTimeZoneRule::MAX_YEAR) {
-                    finalStdRule = (AnnualTimeZoneRule*)tzt.getTo()->clone();
-                }
+                && (atzrule = dynamic_cast<const AnnualTimeZoneRule *>(tzt.getTo())) != NULL
+                && atzrule->getEndYear() == AnnualTimeZoneRule::MAX_YEAR
+            ) {
+                finalStdRule = (AnnualTimeZoneRule*)tzt.getTo()->clone();
             }
             if (stdCount > 0) {
                 if (year == stdStartYear + stdCount
@@ -2070,8 +2102,13 @@ VTimeZone::writeZone(VTZWriter& w, BasicTimeZone& basictz,
                         if (U_FAILURE(status)) {
                             goto cleanupWriteZone;
                         }
-                        writeFinalRule(w, TRUE, finalDstRule,
-                                dstFromOffset - dstFromDSTSavings, dstFromDSTSavings, dstStartTime, status);
+                        UDate nextStart;
+                        UBool nextStartAvail = finalDstRule->getNextStart(dstUntilTime, dstFromOffset - dstFromDSTSavings, dstFromDSTSavings, false, nextStart);
+                        U_ASSERT(nextStartAvail);
+                        if (nextStartAvail) {
+                            writeFinalRule(w, TRUE, finalDstRule,
+                                    dstFromOffset - dstFromDSTSavings, dstFromDSTSavings, nextStart, status);
+                        }
                     }
                 }
                 if (U_FAILURE(status)) {
@@ -2099,7 +2136,7 @@ VTimeZone::writeZone(VTZWriter& w, BasicTimeZone& basictz,
                     // Use a single rule if possible
                     if (isEquivalentDateRule(stdMonth, stdWeekInMonth, stdDayOfWeek, finalStdRule->getRule())) {
                         writeZonePropsByDOW(w, FALSE, stdName, stdFromOffset, stdToOffset,
-                                stdMonth, stdWeekInMonth, stdDayOfWeek, stdStartTime, MAX_MILLIS, status);                            
+                                stdMonth, stdWeekInMonth, stdDayOfWeek, stdStartTime, MAX_MILLIS, status);
                     } else {
                         // Not equivalent rule - write out two different rules
                         writeZonePropsByDOW(w, FALSE, stdName, stdFromOffset, stdToOffset,
@@ -2107,8 +2144,13 @@ VTimeZone::writeZone(VTZWriter& w, BasicTimeZone& basictz,
                         if (U_FAILURE(status)) {
                             goto cleanupWriteZone;
                         }
-                        writeFinalRule(w, FALSE, finalStdRule,
-                                stdFromOffset - stdFromDSTSavings, stdFromDSTSavings, stdStartTime, status);
+                        UDate nextStart;
+                        UBool nextStartAvail = finalStdRule->getNextStart(stdUntilTime, stdFromOffset - stdFromDSTSavings, stdFromDSTSavings, false, nextStart);
+                        U_ASSERT(nextStartAvail);
+                        if (nextStartAvail) {
+                            writeFinalRule(w, FALSE, finalStdRule,
+                                    stdFromOffset - stdFromDSTSavings, stdFromDSTSavings, nextStart, status);
+                        }
                     }
                 }
                 if (U_FAILURE(status)) {
@@ -2178,13 +2220,13 @@ VTimeZone::writeFooter(VTZWriter& writer, UErrorCode& status) const {
  * Write a single start time
  */
 void
-VTimeZone::writeZonePropsByTime(VTZWriter& writer, UBool isDst, const UnicodeString& tzname,
+VTimeZone::writeZonePropsByTime(VTZWriter& writer, UBool isDst, const UnicodeString& zonename,
                                 int32_t fromOffset, int32_t toOffset, UDate time, UBool withRDATE,
                                 UErrorCode& status) const {
     if (U_FAILURE(status)) {
         return;
     }
-    beginZoneProps(writer, isDst, tzname, fromOffset, toOffset, time, status);
+    beginZoneProps(writer, isDst, zonename, fromOffset, toOffset, time, status);
     if (U_FAILURE(status)) {
         return;
     }
@@ -2205,14 +2247,14 @@ VTimeZone::writeZonePropsByTime(VTZWriter& writer, UBool isDst, const UnicodeStr
  * Write start times defined by a DOM rule using VTIMEZONE RRULE
  */
 void
-VTimeZone::writeZonePropsByDOM(VTZWriter& writer, UBool isDst, const UnicodeString& tzname,
+VTimeZone::writeZonePropsByDOM(VTZWriter& writer, UBool isDst, const UnicodeString& zonename,
                                int32_t fromOffset, int32_t toOffset,
                                int32_t month, int32_t dayOfMonth, UDate startTime, UDate untilTime,
                                UErrorCode& status) const {
     if (U_FAILURE(status)) {
         return;
     }
-    beginZoneProps(writer, isDst, tzname, fromOffset, toOffset, startTime, status);
+    beginZoneProps(writer, isDst, zonename, fromOffset, toOffset, startTime, status);
     if (U_FAILURE(status)) {
         return;
     }
@@ -2239,14 +2281,14 @@ VTimeZone::writeZonePropsByDOM(VTZWriter& writer, UBool isDst, const UnicodeStri
  * Write start times defined by a DOW rule using VTIMEZONE RRULE
  */
 void
-VTimeZone::writeZonePropsByDOW(VTZWriter& writer, UBool isDst, const UnicodeString& tzname,
+VTimeZone::writeZonePropsByDOW(VTZWriter& writer, UBool isDst, const UnicodeString& zonename,
                                int32_t fromOffset, int32_t toOffset,
                                int32_t month, int32_t weekInMonth, int32_t dayOfWeek,
                                UDate startTime, UDate untilTime, UErrorCode& status) const {
     if (U_FAILURE(status)) {
         return;
     }
-    beginZoneProps(writer, isDst, tzname, fromOffset, toOffset, startTime, status);
+    beginZoneProps(writer, isDst, zonename, fromOffset, toOffset, startTime, status);
     if (U_FAILURE(status)) {
         return;
     }
@@ -2275,7 +2317,7 @@ VTimeZone::writeZonePropsByDOW(VTZWriter& writer, UBool isDst, const UnicodeStri
  * Write start times defined by a DOW_GEQ_DOM rule using VTIMEZONE RRULE
  */
 void
-VTimeZone::writeZonePropsByDOW_GEQ_DOM(VTZWriter& writer, UBool isDst, const UnicodeString& tzname,
+VTimeZone::writeZonePropsByDOW_GEQ_DOM(VTZWriter& writer, UBool isDst, const UnicodeString& zonename,
                                        int32_t fromOffset, int32_t toOffset,
                                        int32_t month, int32_t dayOfMonth, int32_t dayOfWeek,
                                        UDate startTime, UDate untilTime, UErrorCode& status) const {
@@ -2285,21 +2327,21 @@ VTimeZone::writeZonePropsByDOW_GEQ_DOM(VTZWriter& writer, UBool isDst, const Uni
     // Check if this rule can be converted to DOW rule
     if (dayOfMonth%7 == 1) {
         // Can be represented by DOW rule
-        writeZonePropsByDOW(writer, isDst, tzname, fromOffset, toOffset,
+        writeZonePropsByDOW(writer, isDst, zonename, fromOffset, toOffset,
                 month, (dayOfMonth + 6)/7, dayOfWeek, startTime, untilTime, status);
         if (U_FAILURE(status)) {
             return;
         }
     } else if (month != UCAL_FEBRUARY && (MONTHLENGTH[month] - dayOfMonth)%7 == 6) {
         // Can be represented by DOW rule with negative week number
-        writeZonePropsByDOW(writer, isDst, tzname, fromOffset, toOffset,
+        writeZonePropsByDOW(writer, isDst, zonename, fromOffset, toOffset,
                 month, -1*((MONTHLENGTH[month] - dayOfMonth + 1)/7), dayOfWeek, startTime, untilTime, status);
         if (U_FAILURE(status)) {
             return;
         }
     } else {
         // Otherwise, use BYMONTHDAY to include all possible dates
-        beginZoneProps(writer, isDst, tzname, fromOffset, toOffset, startTime, status);
+        beginZoneProps(writer, isDst, zonename, fromOffset, toOffset, startTime, status);
         if (U_FAILURE(status)) {
             return;
         }
@@ -2399,7 +2441,7 @@ VTimeZone::writeZonePropsByDOW_GEQ_DOM_sub(VTZWriter& writer, int32_t month, int
  * Write start times defined by a DOW_LEQ_DOM rule using VTIMEZONE RRULE
  */
 void
-VTimeZone::writeZonePropsByDOW_LEQ_DOM(VTZWriter& writer, UBool isDst, const UnicodeString& tzname,
+VTimeZone::writeZonePropsByDOW_LEQ_DOM(VTZWriter& writer, UBool isDst, const UnicodeString& zonename,
                                        int32_t fromOffset, int32_t toOffset,
                                        int32_t month, int32_t dayOfMonth, int32_t dayOfWeek,
                                        UDate startTime, UDate untilTime, UErrorCode& status) const {
@@ -2409,19 +2451,19 @@ VTimeZone::writeZonePropsByDOW_LEQ_DOM(VTZWriter& writer, UBool isDst, const Uni
     // Check if this rule can be converted to DOW rule
     if (dayOfMonth%7 == 0) {
         // Can be represented by DOW rule
-        writeZonePropsByDOW(writer, isDst, tzname, fromOffset, toOffset,
+        writeZonePropsByDOW(writer, isDst, zonename, fromOffset, toOffset,
                 month, dayOfMonth/7, dayOfWeek, startTime, untilTime, status);
     } else if (month != UCAL_FEBRUARY && (MONTHLENGTH[month] - dayOfMonth)%7 == 0){
         // Can be represented by DOW rule with negative week number
-        writeZonePropsByDOW(writer, isDst, tzname, fromOffset, toOffset,
+        writeZonePropsByDOW(writer, isDst, zonename, fromOffset, toOffset,
                 month, -1*((MONTHLENGTH[month] - dayOfMonth)/7 + 1), dayOfWeek, startTime, untilTime, status);
     } else if (month == UCAL_FEBRUARY && dayOfMonth == 29) {
         // Specical case for February
-        writeZonePropsByDOW(writer, isDst, tzname, fromOffset, toOffset,
+        writeZonePropsByDOW(writer, isDst, zonename, fromOffset, toOffset,
                 UCAL_FEBRUARY, -1, dayOfWeek, startTime, untilTime, status);
     } else {
         // Otherwise, convert this to DOW_GEQ_DOM rule
-        writeZonePropsByDOW_GEQ_DOM(writer, isDst, tzname, fromOffset, toOffset,
+        writeZonePropsByDOW_GEQ_DOM(writer, isDst, zonename, fromOffset, toOffset,
                 month, dayOfMonth - 6, dayOfWeek, startTime, untilTime, status);
     }
 }
@@ -2442,6 +2484,18 @@ VTimeZone::writeFinalRule(VTZWriter& writer, UBool isDst, const AnnualTimeZoneRu
         modifiedRule = FALSE;
         dtrule = rule->getRule();
     }
+
+    // If the rule's mills in a day is out of range, adjust start time.
+    // Olson tzdata supports 24:00 of a day, but VTIMEZONE does not.
+    // See ticket#7008/#7518
+
+    int32_t timeInDay = dtrule->getRuleMillisInDay();
+    if (timeInDay < 0) {
+        startTime = startTime + (0 - timeInDay);
+    } else if (timeInDay >= U_MILLIS_PER_DAY) {
+        startTime = startTime - (timeInDay - (U_MILLIS_PER_DAY - 1));
+    }
+
     int32_t toOffset = rule->getRawOffset() + rule->getDSTSavings();
     UnicodeString name;
     rule->getName(name);
@@ -2472,7 +2526,7 @@ VTimeZone::writeFinalRule(VTZWriter& writer, UBool isDst, const AnnualTimeZoneRu
  * Write the opening section of zone properties
  */
 void
-VTimeZone::beginZoneProps(VTZWriter& writer, UBool isDst, const UnicodeString& tzname,
+VTimeZone::beginZoneProps(VTZWriter& writer, UBool isDst, const UnicodeString& zonename,
                           int32_t fromOffset, int32_t toOffset, UDate startTime, UErrorCode& status) const {
     if (U_FAILURE(status)) {
         return;
@@ -2505,7 +2559,7 @@ VTimeZone::beginZoneProps(VTZWriter& writer, UBool isDst, const UnicodeString& t
     // TZNAME
     writer.write(ICAL_TZNAME);
     writer.write(COLON);
-    writer.write(tzname);
+    writer.write(zonename);
     writer.write(ICAL_NEWLINE);
     
     // DTSTART
@@ -2577,4 +2631,3 @@ U_NAMESPACE_END
 #endif /* #if !UCONFIG_NO_FORMATTING */
 
 //eof
-