+// © 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
#include "cmemory.h"
#include "uvector.h"
#include "gregoimp.h"
-#include "uhash.h"
+#include "uassert.h"
U_NAMESPACE_BEGIN
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++) {
/*
* 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)");
}
}
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) {
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.
} 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
}
}
-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;
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);
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;
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;
/*
* 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;
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
return NULL;
}
}
- retVal = new TimeArrayTimeZoneRule(tzname, rawOffset, dstSavings,
+ retVal = new TimeArrayTimeZoneRule(zonename, rawOffset, dstSavings,
times, size, DateTimeRule::UTC_TIME);
uprv_free(times);
}
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;
out->append(ch);
}
+void
+VTZWriter::write(const UChar* str) {
+ out->append(str, -1);
+}
+
/*
void
VTZWriter::write(const UChar* str, int32_t length) {
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);
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);
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;
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);
}
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);
}
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;
}
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;
// 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;
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;
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
// 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;
}
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;
isRRULE = FALSE;
from.remove();
to.remove();
- tzname.remove();
+ zonename.remove();
dst = isDST;
state = TZI;
} else {
// 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;
}
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;
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
// 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;
}
// 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;
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;
}
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);
}
}
} 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
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);
}
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
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);
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
}
} 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
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)) {
// 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,
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)) {
* 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;
}
* 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;
}
* 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;
}
* 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 {
// 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;
}
* 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 {
// 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);
}
}
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);
* 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;
// TZNAME
writer.write(ICAL_TZNAME);
writer.write(COLON);
- writer.write(tzname);
+ writer.write(zonename);
writer.write(ICAL_NEWLINE);
// DTSTART
#endif /* #if !UCONFIG_NO_FORMATTING */
//eof
-