21 #include <config-kcalcore.h> 23 #include "icaltimezones.h" 26 #include "recurrence.h" 27 #include "recurrencerule.h" 31 #include <KSystemTimeZone> 33 #include <QtCore/QDateTime> 34 #include <QtCore/QFile> 35 #include <QtCore/QTextStream> 38 #include <libical/ical.h> 39 #include <icaltimezone.h> 42 #if defined(HAVE_UUID_UUID_H) 43 #include <uuid/uuid.h> 49 static const int minRuleCount = 5;
50 static const int minPhaseCount = 8;
53 static QDateTime toQDateTime(
const icaltimetype &t)
55 return QDateTime(QDate(t.year, t.month, t.day),
56 QTime(t.hour, t.minute, t.second),
57 (t.is_utc ? Qt::UTC : Qt::LocalTime));
63 static QDateTime MAX_DATE()
67 dt = QDateTime(QDate::currentDate().addYears(20), QTime(0, 0, 0));
72 static icaltimetype writeLocalICalDateTime(
const QDateTime &utc,
int offset)
74 const QDateTime local = utc.addSecs(offset);
75 icaltimetype t = icaltime_null_time();
76 t.year = local.date().year();
77 t.month = local.date().month();
78 t.day = local.date().day();
79 t.hour = local.time().hour();
80 t.minute = local.time().minute();
81 t.second = local.time().second();
93 class ICalTimeZonesPrivate
96 ICalTimeZonesPrivate() {}
97 ICalTimeZones::ZoneMap zones;
102 : d(new ICalTimeZonesPrivate)
107 : d(new ICalTimeZonesPrivate())
109 d->zones = rhs.d->
zones;
134 if (!zone.isValid()) {
137 if (d->zones.find(zone.name()) != d->zones.end()) {
141 d->zones.insert(zone.name(),
zone);
147 if (zone.isValid()) {
148 for (ZoneMap::Iterator it = d->zones.begin(), end = d->zones.end(); it != end; ++it) {
149 if (it.value() ==
zone) {
160 if (!name.isEmpty()) {
161 ZoneMap::Iterator it = d->zones.find(name);
162 if (it != d->zones.end()) {
178 return d->zones.count();
183 if (!name.isEmpty()) {
184 ZoneMap::ConstIterator it = d->zones.constFind(name);
185 if (it != d->zones.constEnd()) {
194 if (zone.isValid()) {
195 QMapIterator<QString, ICalTimeZone> it(d->zones);
196 while (it.hasNext()) {
199 const QList<KTimeZone::Transition> list1 = tz.transitions();
200 const QList<KTimeZone::Transition> list2 = zone.transitions();
201 if (list1.size() == list2.size()) {
204 for (; i < list1.size(); ++i) {
205 const KTimeZone::Transition t1 = list1[ i ];
206 const KTimeZone::Transition t2 = list2[ i ];
207 if ((t1.time() == t2.time()) &&
208 (t1.phase().utcOffset() == t2.phase().utcOffset()) &&
209 (t1.phase().isDst() == t2.phase().isDst())) {
231 const QString &countryCode,
232 float latitude,
float longitude,
233 const QString &comment)
234 : KTimeZoneBackend(source, name, countryCode, latitude, longitude, comment)
238 : KTimeZoneBackend(0, tz.name(), tz.countryCode(), tz.latitude(), tz.longitude(), tz.comment())
243 ICalTimeZoneBackend::~ICalTimeZoneBackend()
253 return "ICalTimeZone";
283 tz.latitude(), tz.longitude(),
286 const KTimeZoneData *data = tz.data(
true);
303 return dat ? dat->
city() : QString();
309 return dat ? dat->
url() : QByteArray();
321 return dat ? dat->
vtimezone() : QByteArray();
332 if (!updateBase(other)) {
336 KTimeZoneData *otherData = other.data() ? other.data()->clone() : 0;
337 setData(otherData, other.source());
344 if (!utcZone.isValid()) {
346 utcZone = tzs.
parse(icaltimezone_get_utc_timezone());
359 class ICalTimeZoneDataPrivate
362 ICalTimeZoneDataPrivate() : icalComponent(0) {}
364 ~ICalTimeZoneDataPrivate()
367 icalcomponent_free(icalComponent);
371 icalcomponent *component()
const {
372 return icalComponent;
374 void setComponent(icalcomponent *c)
377 icalcomponent_free(icalComponent);
387 icalcomponent *icalComponent;
392 : d(new ICalTimeZoneDataPrivate())
397 : KTimeZoneData(rhs),
398 d(new ICalTimeZoneDataPrivate())
400 d->location = rhs.d->location;
403 d->setComponent(icalcomponent_new_clone(rhs.d->component()));
407 const KTimeZone &tz,
const QDate &earliest)
408 : KTimeZoneData(rhs),
409 d(new ICalTimeZoneDataPrivate())
414 WEEKDAY_OF_MONTH = 0x02,
415 LAST_WEEKDAY_OF_MONTH = 0x04
418 if (tz.type() ==
"KSystemTimeZone") {
422 icalcomponent *c = 0;
423 const KTimeZone ktz = KSystemTimeZones::readZone(tz.name());
425 if (ktz.data(
true)) {
429 c = icalcomponent_new_clone(icaltimezone_get_component(itz));
430 icaltimezone_free(itz, 1);
436 icaltimezone *itz = icaltimezone_get_builtin_timezone(tz.name().toUtf8());
437 c = icalcomponent_new_clone(icaltimezone_get_component(itz));
443 icalproperty *prop = icalcomponent_get_first_property(c, ICAL_TZID_PROPERTY);
445 icalvalue *value = icalproperty_get_value(prop);
446 const char *tzid = icalvalue_get_text(value);
448 const int len = icalprefix.size();
449 if (!strncmp(icalprefix, tzid, len)) {
450 const char *s = strchr(tzid + len,
'/');
452 const QByteArray tzidShort(s + 1);
453 icalvalue_set_text(value, tzidShort);
456 prop = icalcomponent_get_first_property(c, ICAL_X_PROPERTY);
457 const char *xname = icalproperty_get_x_name(prop);
458 if (xname && !strcmp(xname,
"X-LIC-LOCATION")) {
459 icalcomponent_remove_property(c, prop);
460 icalproperty_free(prop);
469 icalcomponent *tzcomp = icalcomponent_new(ICAL_VTIMEZONE_COMPONENT);
470 icalcomponent_add_property(tzcomp, icalproperty_new_tzid(tz.name().toUtf8()));
475 QList<KTimeZone::Transition> transits = transitions();
476 if (transits.isEmpty()) {
480 if (transits.isEmpty()) {
481 kDebug() <<
"No transition information available VTIMEZONE will be invalid.";
484 if (earliest.isValid()) {
486 for (
int i = 0, end = transits.count(); i < end; ++i) {
487 if (transits.at(i).time().date() >= earliest) {
489 transits.erase(transits.begin(), transits.begin() + i);
495 int trcount = transits.count();
496 QVector<bool> transitionsDone(trcount);
497 transitionsDone.fill(
false);
501 icaldatetimeperiodtype dtperiod;
502 dtperiod.period = icalperiodtype_null_period();
505 for (; i < trcount && transitionsDone[i]; ++i) {
512 const int preOffset = (i > 0) ?
513 transits.at(i - 1).phase().utcOffset() :
514 rhs.previousUtcOffset();
515 const KTimeZone::Phase phase = transits.at(i).phase();
516 if (phase.utcOffset() == preOffset) {
517 transitionsDone[i] =
true;
518 while (++i < trcount) {
519 if (transitionsDone[i] ||
520 transits.at(i).phase() != phase ||
521 transits.at(i - 1).phase().utcOffset() != preOffset) {
524 transitionsDone[i] =
true;
528 icalcomponent *phaseComp =
529 icalcomponent_new(phase.isDst() ? ICAL_XDAYLIGHT_COMPONENT : ICAL_XSTANDARD_COMPONENT);
530 const QList<QByteArray> abbrevs = phase.abbreviations();
531 for (
int a = 0, aend = abbrevs.count(); a < aend; ++a) {
532 icalcomponent_add_property(phaseComp,
533 icalproperty_new_tzname(
534 static_cast<const char*>(abbrevs[a])));
536 if (!phase.comment().isEmpty()) {
537 icalcomponent_add_property(phaseComp,
538 icalproperty_new_comment(phase.comment().toUtf8()));
540 icalcomponent_add_property(phaseComp,
541 icalproperty_new_tzoffsetfrom(preOffset));
542 icalcomponent_add_property(phaseComp,
543 icalproperty_new_tzoffsetto(phase.utcOffset()));
545 icalcomponent *phaseComp1 = icalcomponent_new_clone(phaseComp);
546 icalcomponent_add_property(phaseComp1,
547 icalproperty_new_dtstart(
548 writeLocalICalDateTime(transits.at(i).time(),
550 bool useNewRRULE =
false;
556 int year = 0, month = 0, daysInMonth = 0, dayOfMonth = 0;
558 int nthFromStart = 0;
562 QList<QDateTime> rdates;
563 QList<QDateTime> times;
564 QDateTime qdt = transits.at(i).time();
566 transitionsDone[i] =
true;
570 rule = DAY_OF_MONTH | WEEKDAY_OF_MONTH | LAST_WEEKDAY_OF_MONTH;
574 month = date.month();
575 daysInMonth = date.daysInMonth();
576 dayOfWeek = date.dayOfWeek();
577 dayOfMonth = date.day();
578 nthFromStart = (dayOfMonth - 1) / 7 + 1;
579 nthFromEnd = (daysInMonth - dayOfMonth) / 7 + 1;
581 if (++i >= trcount) {
583 times += QDateTime();
585 if (transitionsDone[i] ||
586 transits.at(i).phase() != phase ||
587 transits.at(i - 1).phase().utcOffset() != preOffset) {
590 transitionsDone[i] =
true;
591 qdt = transits.at(i).time();
592 if (!qdt.isValid()) {
598 if (qdt.time() != time ||
599 date.month() != month ||
600 date.year() != ++year) {
603 const int day = date.day();
604 if ((newRule & DAY_OF_MONTH) && day != dayOfMonth) {
605 newRule &= ~DAY_OF_MONTH;
607 if (newRule & (WEEKDAY_OF_MONTH | LAST_WEEKDAY_OF_MONTH)) {
608 if (date.dayOfWeek() != dayOfWeek) {
609 newRule &= ~(WEEKDAY_OF_MONTH | LAST_WEEKDAY_OF_MONTH);
611 if ((newRule & WEEKDAY_OF_MONTH) &&
612 (day - 1) / 7 + 1 != nthFromStart) {
613 newRule &= ~WEEKDAY_OF_MONTH;
615 if ((newRule & LAST_WEEKDAY_OF_MONTH) &&
616 (daysInMonth - day) / 7 + 1 != nthFromEnd) {
617 newRule &= ~LAST_WEEKDAY_OF_MONTH;
627 int yr = times[0].date().year();
628 while (!rdates.isEmpty()) {
631 if (qdt.time() != time ||
632 date.month() != month ||
633 date.year() != --yr) {
636 const int day = date.day();
637 if (rule & DAY_OF_MONTH) {
638 if (day != dayOfMonth) {
642 if (date.dayOfWeek() != dayOfWeek ||
643 ((rule & WEEKDAY_OF_MONTH) &&
644 (day - 1) / 7 + 1 != nthFromStart) ||
645 ((rule & LAST_WEEKDAY_OF_MONTH) &&
646 (daysInMonth - day) / 7 + 1 != nthFromEnd)) {
653 if (times.count() > (useNewRRULE ? minPhaseCount : minRuleCount)) {
655 icalrecurrencetype r;
656 icalrecurrencetype_clear(&r);
657 r.freq = ICAL_YEARLY_RECURRENCE;
658 r.count = (year >= 2030) ? 0 : times.count() - 1;
659 r.by_month[0] = month;
660 if (rule & DAY_OF_MONTH) {
661 r.by_month_day[0] = dayOfMonth;
662 }
else if (rule & WEEKDAY_OF_MONTH) {
663 r.by_day[0] = (dayOfWeek % 7 + 1) + (nthFromStart * 8);
664 }
else if (rule & LAST_WEEKDAY_OF_MONTH) {
665 r.by_day[0] = -(dayOfWeek % 7 + 1) - (nthFromEnd * 8);
667 icalproperty *prop = icalproperty_new_rrule(r);
671 icalcomponent *c = icalcomponent_new_clone(phaseComp);
672 icalcomponent_add_property(
673 c, icalproperty_new_dtstart(writeLocalICalDateTime(times[0], preOffset)));
674 icalcomponent_add_property(c, prop);
675 icalcomponent_add_component(tzcomp, c);
677 icalcomponent_add_property(phaseComp1, prop);
681 for (
int t = 0, tend = times.count() - 1; t < tend; ++t) {
693 }
while (i < trcount);
696 for (
int rd = 0, rdend = rdates.count(); rd < rdend; ++rd) {
697 dtperiod.time = writeLocalICalDateTime(rdates[rd], preOffset);
698 icalcomponent_add_property(phaseComp1, icalproperty_new_rdate(dtperiod));
700 icalcomponent_add_component(tzcomp, phaseComp1);
701 icalcomponent_free(phaseComp);
704 d->setComponent(tzcomp);
720 KTimeZoneData::operator=(rhs);
721 d->location = rhs.d->location;
724 d->setComponent(icalcomponent_new_clone(rhs.d->component()));
745 return d->lastModified;
750 const QByteArray result(icalcomponent_as_ical_string(d->component()));
751 icalmemory_free_ring();
757 icaltimezone *icaltz = icaltimezone_new();
761 icalcomponent *c = icalcomponent_new_clone(d->component());
762 if (!icaltimezone_set_component(icaltz, c)) {
763 icalcomponent_free(c);
764 icaltimezone_free(icaltz, 1);
784 class ICalTimeZoneSourcePrivate
787 static QList<QDateTime> parsePhase(icalcomponent *,
bool daylight,
788 int &prevOffset, KTimeZone::Phase &);
789 static QByteArray icalTzidPrefix;
791 #if defined(HAVE_UUID_UUID_H) 792 static void parseTransitions(
const MSSystemTime &date,
const KTimeZone::Phase &phase,
793 int prevOffset, QList<KTimeZone::Transition> &transitions);
797 QByteArray ICalTimeZoneSourcePrivate::icalTzidPrefix;
801 : KTimeZoneSource(false),
813 QFile file(fileName);
814 if (!file.open(QIODevice::ReadOnly)) {
817 QTextStream ts(&file);
818 ts.setCodec(
"ISO 8859-1");
819 const QByteArray text = ts.readAll().trimmed().toLatin1();
823 icalcomponent *calendar = icalcomponent_new_from_string(text.data());
825 if (icalcomponent_isa(calendar) == ICAL_VCALENDAR_COMPONENT) {
826 result =
parse(calendar, zones);
828 icalcomponent_free(calendar);
835 for (icalcomponent *c = icalcomponent_get_first_component(calendar, ICAL_VTIMEZONE_COMPONENT);
836 c; c = icalcomponent_get_next_component(calendar, ICAL_VTIMEZONE_COMPONENT)) {
838 if (!zone.isValid()) {
842 if (oldzone.isValid()) {
846 }
else if (!zones.
add(zone)) {
860 icalproperty *p = icalcomponent_get_first_property(vtimezone, ICAL_ANY_PROPERTY);
862 icalproperty_kind kind = icalproperty_isa(p);
865 case ICAL_TZID_PROPERTY:
866 name = QString::fromUtf8(icalproperty_get_tzid(p));
869 case ICAL_TZURL_PROPERTY:
870 data->d->
url = icalproperty_get_tzurl(p);
873 case ICAL_LOCATION_PROPERTY:
875 data->d->location = QString::fromUtf8(icalproperty_get_location(p));
878 case ICAL_X_PROPERTY:
880 const char *xname = icalproperty_get_x_name(p);
881 if (xname && !strcmp(xname,
"X-LIC-LOCATION")) {
882 xlocation = QString::fromUtf8(icalproperty_get_x(p));
886 case ICAL_LASTMODIFIED_PROPERTY:
888 const icaltimetype t = icalproperty_get_lastmodified(p);
892 kDebug() <<
"LAST-MODIFIED not UTC";
899 p = icalcomponent_get_next_property(vtimezone, ICAL_ANY_PROPERTY);
902 if (name.isEmpty()) {
903 kDebug() <<
"TZID missing";
907 if (data->d->location.isEmpty() && !xlocation.isEmpty()) {
908 data->d->location = xlocation;
911 if (name.startsWith(prefix)) {
913 const int i = name.indexOf(QLatin1Char(
'/'), prefix.length());
915 name = name.mid(i + 1);
925 QList<KTimeZone::Transition> transitions;
927 QList<KTimeZone::Phase> phases;
928 for (icalcomponent *c = icalcomponent_get_first_component(vtimezone, ICAL_ANY_COMPONENT);
929 c; c = icalcomponent_get_next_component(vtimezone, ICAL_ANY_COMPONENT)) {
931 KTimeZone::Phase phase;
932 QList<QDateTime> times;
933 icalcomponent_kind kind = icalcomponent_isa(c);
936 case ICAL_XSTANDARD_COMPONENT:
938 times = ICalTimeZoneSourcePrivate::parsePhase(c,
false, prevoff, phase);
941 case ICAL_XDAYLIGHT_COMPONENT:
943 times = ICalTimeZoneSourcePrivate::parsePhase(c,
true, prevoff, phase);
947 kDebug() <<
"Unknown component:" << int(kind);
950 const int tcount = times.count();
953 for (
int t = 0; t < tcount; ++t) {
954 transitions += KTimeZone::Transition(times[t], phase);
956 if (!earliest.isValid() || times[0] < earliest) {
957 prevOffset = prevoff;
964 data->setPhases(phases, prevOffset);
968 for (
int t = 1, tend = transitions.count(); t < tend;) {
969 if (transitions[t].phase() == transitions[t - 1].phase()) {
970 transitions.removeAt(t);
976 data->setTransitions(transitions);
978 data->d->setComponent(icalcomponent_new_clone(vtimezone));
983 #if defined(HAVE_UUID_UUID_H) 987 if (!zone.isValid()) {
991 if (oldzone.isValid()) {
995 }
else if (zones.
add(zone)) {
1009 uuid_generate_random(uuid);
1010 uuid_unparse(uuid, suuid);
1011 QString name = QString::fromLatin1(suuid);
1014 QList<KTimeZone::Phase> phases;
1016 QList<QByteArray> standardAbbrevs;
1017 standardAbbrevs += tz->StandardName.toLatin1();
1018 const KTimeZone::Phase standardPhase(
1019 (tz->Bias + tz->StandardBias) * -60,
1020 standardAbbrevs,
false,
1021 QLatin1String(
"Microsoft TIME_ZONE_INFORMATION"));
1022 phases += standardPhase;
1024 QList<QByteArray> daylightAbbrevs;
1025 daylightAbbrevs += tz->DaylightName.toLatin1();
1026 const KTimeZone::Phase daylightPhase(
1027 (tz->Bias + tz->DaylightBias) * -60,
1028 daylightAbbrevs,
true,
1029 QLatin1String(
"Microsoft TIME_ZONE_INFORMATION"));
1030 phases += daylightPhase;
1034 const int prevOffset = tz->Bias * -60;
1035 kdata.setPhases(phases, prevOffset);
1038 QList<KTimeZone::Transition> transitions;
1039 ICalTimeZoneSourcePrivate::parseTransitions(
1040 tz->StandardDate, standardPhase, prevOffset, transitions);
1041 ICalTimeZoneSourcePrivate::parseTransitions(
1042 tz->DaylightDate, daylightPhase, prevOffset, transitions);
1045 kdata.setTransitions(transitions);
1051 #endif // HAVE_UUID_UUID_H 1057 if (!zone.isValid()) {
1063 if (oldzone.isValid()) {
1067 oldzone = zones.
zone(name);
1068 if (oldzone.isValid()) {
1072 }
else if (zones.
add(zone)) {
1082 QList<KTimeZone::Phase> phases;
1083 QList<KTimeZone::Transition> transitions;
1086 for (QStringList::ConstIterator it = tzList.begin(); it != tzList.end(); ++it) {
1087 QString value = *it;
1089 const QString tzName = value.mid(0, value.indexOf(QLatin1String(
";")));
1090 value = value.mid((value.indexOf(QLatin1String(
";")) + 1));
1091 const QString tzOffset = value.mid(0, value.indexOf(QLatin1String(
";")));
1092 value = value.mid((value.indexOf(QLatin1String(
";")) + 1));
1093 const QString tzDaylight = value.mid(0, value.indexOf(QLatin1String(
";")));
1094 const KDateTime tzDate = KDateTime::fromString(value.mid((value.lastIndexOf(QLatin1String(
";")) + 1)));
1095 if (tzDaylight == QLatin1String(
"true")) {
1099 const KTimeZone::Phase tzPhase(
1101 QByteArray(tzName.toLatin1()), daylight, QLatin1String(
"VCAL_TZ_INFORMATION"));
1103 transitions += KTimeZone::Transition(tzDate.dateTime(), tzPhase);
1106 kdata.setPhases(phases, 0);
1108 kdata.setTransitions(transitions);
1114 #if defined(HAVE_UUID_UUID_H) 1116 void ICalTimeZoneSourcePrivate::parseTransitions(
const MSSystemTime &date,
1117 const KTimeZone::Phase &phase,
int prevOffset,
1118 QList<KTimeZone::Transition> &transitions)
1122 const KDateTime klocalStart(QDateTime(QDate(2000, 1, 1), QTime(0, 0, 0)),
1123 KDateTime::Spec::ClockTime());
1124 const KDateTime maxTime(MAX_DATE(), KDateTime::Spec::ClockTime());
1128 if (date.wYear >= 1601 && date.wYear <= 30827 &&
1129 date.wMonth >= 1 && date.wMonth <= 12 &&
1130 date.wDay >= 1 && date.wDay <= 31) {
1131 const QDate dt(date.wYear, date.wMonth, date.wDay);
1132 const QTime tm(date.wHour, date.wMinute, date.wSecond, date.wMilliseconds);
1133 const QDateTime datetime(dt, tm);
1134 if (datetime.isValid()) {
1135 transitions += KTimeZone::Transition(datetime, phase);
1140 if (date.wDayOfWeek >= 0 && date.wDayOfWeek <= 6 &&
1141 date.wMonth >= 1 && date.wMonth <= 12 &&
1142 date.wDay >= 1 && date.wDay <= 5) {
1144 r.setRecurrenceType(RecurrenceRule::rYearly);
1148 lst.append(date.wMonth);
1150 QList<RecurrenceRule::WDayPos> wdlst;
1152 pos.setDay(date.wDayOfWeek ? date.wDayOfWeek : 7);
1153 pos.setPos(date.wDay < 5 ? date.wDay : -1);
1159 for (
int i = 0, end = dtl.count(); i < end; ++i) {
1160 QDateTime utc = dtl[i].dateTime();
1161 utc.setTimeSpec(Qt::UTC);
1162 transitions += KTimeZone::Transition(utc.addSecs(-prevOffset), phase);
1168 #endif // HAVE_UUID_UUID_H 1180 QList<QDateTime> ICalTimeZoneSourcePrivate::parsePhase(icalcomponent *c,
1183 KTimeZone::Phase &phase)
1185 QList<QDateTime> transitions;
1188 QList<QByteArray> abbrevs;
1192 bool recurs =
false;
1193 bool found_dtstart =
false;
1194 bool found_tzoffsetfrom =
false;
1195 bool found_tzoffsetto =
false;
1196 icaltimetype dtstart = icaltime_null_time();
1199 icalproperty *p = icalcomponent_get_first_property(c, ICAL_ANY_PROPERTY);
1201 icalproperty_kind kind = icalproperty_isa(p);
1204 case ICAL_TZNAME_PROPERTY:
1210 QByteArray tzname = icalproperty_get_tzname(p);
1213 if ((!daylight && tzname ==
"Standard Time") ||
1214 (daylight && tzname ==
"Daylight Time")) {
1217 if (!abbrevs.contains(tzname)) {
1222 case ICAL_DTSTART_PROPERTY:
1223 dtstart = icalproperty_get_dtstart(p);
1224 found_dtstart =
true;
1227 case ICAL_TZOFFSETFROM_PROPERTY:
1228 prevOffset = icalproperty_get_tzoffsetfrom(p);
1229 found_tzoffsetfrom =
true;
1232 case ICAL_TZOFFSETTO_PROPERTY:
1233 utcOffset = icalproperty_get_tzoffsetto(p);
1234 found_tzoffsetto =
true;
1237 case ICAL_COMMENT_PROPERTY:
1238 comment = QString::fromUtf8(icalproperty_get_comment(p));
1241 case ICAL_RDATE_PROPERTY:
1242 case ICAL_RRULE_PROPERTY:
1247 kDebug() <<
"Unknown property:" << int(kind);
1250 p = icalcomponent_get_next_property(c, ICAL_ANY_PROPERTY);
1254 if (!found_dtstart || !found_tzoffsetfrom || !found_tzoffsetto) {
1255 kDebug() <<
"DTSTART/TZOFFSETFROM/TZOFFSETTO missing";
1260 const QDateTime localStart = toQDateTime(dtstart);
1261 dtstart.second -= prevOffset;
1263 const QDateTime utcStart = toQDateTime(icaltime_normalize(dtstart));
1265 transitions += utcStart;
1272 const KDateTime klocalStart(localStart, KDateTime::Spec::ClockTime());
1273 const KDateTime maxTime(MAX_DATE(), KDateTime::Spec::ClockTime());
1275 icalproperty *p = icalcomponent_get_first_property(c, ICAL_ANY_PROPERTY);
1277 icalproperty_kind kind = icalproperty_isa(p);
1280 case ICAL_RDATE_PROPERTY:
1282 icaltimetype t = icalproperty_get_rdate(p).time;
1283 if (icaltime_is_date(t)) {
1285 t.hour = dtstart.hour;
1286 t.minute = dtstart.minute;
1287 t.second = dtstart.second;
1294 t.second -= prevOffset;
1296 t = icaltime_normalize(t);
1298 transitions += toQDateTime(t);
1301 case ICAL_RRULE_PROPERTY:
1306 impl.readRecurrence(icalproperty_get_rrule(p), &r);
1311 KDateTime end(r.
endDt());
1312 if (end.timeSpec() == KDateTime::Spec::UTC()) {
1313 end.setTimeSpec(KDateTime::Spec::ClockTime());
1314 r.
setEndDt(end.addSecs(prevOffset));
1318 for (
int i = 0, end = dts.count(); i < end; ++i) {
1319 QDateTime utc = dts[i].dateTime();
1320 utc.setTimeSpec(Qt::UTC);
1321 transitions += utc.addSecs(-prevOffset);
1328 p = icalcomponent_get_next_property(c, ICAL_ANY_PROPERTY);
1330 qSortUnique(transitions);
1333 phase = KTimeZone::Phase(utcOffset, abbrevs, daylight, comment);
1344 QString tzid = zone;
1346 if (zone.startsWith(prefix)) {
1347 const int i = zone.indexOf(QLatin1Char(
'/'), prefix.length());
1349 tzid = zone.mid(i + 1);
1352 const KTimeZone ktz = KSystemTimeZones::readZone(tzid);
1353 if (ktz.isValid()) {
1354 if (ktz.data(
true)) {
1363 const QByteArray zoneName = zone.toUtf8();
1364 icaltimezone *icaltz = icaltimezone_get_builtin_timezone(zoneName);
1367 icaltz = icaltimezone_get_builtin_timezone_from_tzid(zoneName);
1372 return parse(icaltz);
1377 if (ICalTimeZoneSourcePrivate::icalTzidPrefix.isEmpty()) {
1378 icaltimezone *icaltz = icaltimezone_get_builtin_timezone(
"Europe/London");
1379 const QByteArray tzid = icaltimezone_get_tzid(icaltz);
1380 if (tzid.right(13) ==
"Europe/London") {
1381 int i = tzid.indexOf(
'/', 1);
1383 ICalTimeZoneSourcePrivate::icalTzidPrefix = tzid.left(i + 1);
1384 return ICalTimeZoneSourcePrivate::icalTzidPrefix;
1387 kError() <<
"failed to get libical TZID prefix";
1389 return ICalTimeZoneSourcePrivate::icalTzidPrefix;
virtual ~ICalTimeZone()
Destructor.
void clear()
Clears the collection.
ICalTimeZone remove(const ICalTimeZone &zone)
Removes a time zone from the collection.
virtual void virtual_hook(int id, void *data)
void setFrequency(int freq)
Sets the recurrence frequency, in terms of the recurrence time period type.
ICalTimeZone()
Constructs a null time zone.
structure for describing the n-th weekday of the month/year.
virtual void virtual_hook(int id, void *data)
ICalTimeZone zone(const QString &name) const
Returns the time zone with the given name.
int duration() const
Returns -1 if the event recurs infinitely, 0 if the end date is set, otherwise the total number of re...
QDateTime lastModified() const
Returns the LAST-MODIFIED time of the VTIMEZONE, if any.
virtual void virtual_hook(int id, void *data)
ICalTimeZoneBackend()
Implements ICalTimeZone::ICalTimeZone().
QByteArray url() const
Returns the URL of the published VTIMEZONE definition, if any.
A class which reads and parses iCalendar VTIMEZONE components, and accesses libical time zone data...
void setDuration(int duration)
Sets the total number of times the event is to occur, including both the first and last...
ICalTimeZoneData()
Default constructor.
ICalTimeZoneSource()
Constructs an iCalendar time zone source.
virtual QByteArray type() const
Returns the class name of the data represented by this instance.
virtual bool hasTransitions(const KTimeZone *caller) const
Implements ICalTimeZone::hasTransitions().
ICalTimeZoneData & operator=(const ICalTimeZoneData &rhs)
Assignment operator.
QDateTime lastModified() const
Returns the LAST-MODIFIED time of the VTIMEZONE, if any.
ICalTimeZone standardZone(const QString &zone, bool icalBuiltIn=false)
Creates an ICalTimeZone instance for a standard time zone.
QByteArray vtimezone() const
Returns the VTIMEZONE string which represents this time zone.
KDateTime endDt(bool *result=0) const
Returns the date and time of the last recurrence.
~ICalTimeZones()
Destructor.
static ICalTimeZone utc()
Returns a standard UTC time zone, with name "UTC".
void setEndDt(const KDateTime &endDateTime)
Sets the date and time of the last recurrence.
QString city() const
Returns the name of the city for this time zone, if any.
virtual ~ICalTimeZoneSource()
Destructor.
bool add(const ICalTimeZone &zone)
Adds a time zone to the collection.
This class represents a recurrence rule for a calendar incidence.
const ZoneMap zones() const
Returns all the time zones defined in this collection.
A QList which can be sorted.
Parsed iCalendar VTIMEZONE data.
static QByteArray icalTzidPrefix()
Returns the prefix string used in the TZID field in built-in libical time zones.
QByteArray url() const
Returns the URL of the published VTIMEZONE definition, if any.
QString city() const
Returns the name of the city for this time zone, if any.
ICalTimeZone parse(icalcomponent *vtimezone)
Creates an ICalTimeZone instance containing the detailed information parsed from an iCalendar VTIMEZO...
int count()
Returns the number of zones kept in memory.
icaltimezone * icalTimezone() const
Returns the ICal timezone structure which represents this time zone.
bool update(const ICalTimeZone &other)
Update the definition of the time zone to be identical to another ICalTimeZone instance.
icaltimezone * icalTimezone() const
Returns the ICal timezone structure which represents this time zone.
QByteArray vtimezone() const
Returns the VTIMEZONE string which represents this time zone.
virtual ~ICalTimeZoneData()
Destructor.
Backend class for KICalTimeZone class.
ICalTimeZones()
Constructs an empty time zone collection.
virtual KTimeZoneBackend * clone() const
Creates a copy of this instance.
virtual KTimeZoneData * clone() const
Creates a new copy of this object.
The ICalTimeZones class represents a time zone database which consists of a collection of individual ...
DateTimeList timesInInterval(const KDateTime &start, const KDateTime &end) const
Returns a list of all the times at which the recurrence will occur between two specified times...
The ICalTimeZone class represents an iCalendar VTIMEZONE component.
void setStartDt(const KDateTime &start)
Sets the recurrence start date/time.
ICalTimeZones & operator=(const ICalTimeZones &rhs)
Assignment operator.
virtual void virtual_hook(int id, void *data)
virtual bool hasTransitions() const
Return whether daylight saving transitions are available for the time zone.
Placeholhers for Microsoft and ActiveSync timezone data.
This class represents a recurrence rule for a calendar incidence.