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)
49static const int minRuleCount = 5;
50static const int minPhaseCount = 8;
53static QDateTime toQDateTime(
const icaltimetype &t)
55 return QDateTime(QDate(t.year, t.month, t.day),
56 QTime(t.hour, t.minute, t.second),
57 (icaltime_is_utc( t ) ? Qt::UTC : Qt::LocalTime));
63static QDateTime MAX_DATE()
67 dt = QDateTime(QDate::currentDate().addYears(20), QTime(0, 0, 0));
72static 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();
92class ICalTimeZonesPrivate
95 ICalTimeZonesPrivate() {}
96 ICalTimeZones::ZoneMap zones;
101 : d(new ICalTimeZonesPrivate)
106 : d(new ICalTimeZonesPrivate())
108 d->zones = rhs.d->
zones;
133 if (!
zone.isValid()) {
136 if (d->zones.find(
zone.name()) != d->zones.end()) {
146 if (
zone.isValid()) {
147 for (ZoneMap::Iterator it = d->zones.begin(), end = d->zones.end(); it != end; ++it) {
148 if (it.value() ==
zone) {
159 if (!name.isEmpty()) {
160 ZoneMap::Iterator it = d->zones.find(name);
161 if (it != d->zones.end()) {
177 return d->zones.count();
182 if (!name.isEmpty()) {
183 ZoneMap::ConstIterator it = d->zones.constFind(name);
184 if (it != d->zones.constEnd()) {
193 if (
zone.isValid()) {
194 QMapIterator<QString, ICalTimeZone> it(d->zones);
195 while (it.hasNext()) {
198 const QList<KTimeZone::Transition> list1 = tz.transitions();
199 const QList<KTimeZone::Transition> list2 =
zone.transitions();
200 if (list1.size() == list2.size()) {
203 for (; i < list1.size(); ++i) {
204 const KTimeZone::Transition t1 = list1[ i ];
205 const KTimeZone::Transition t2 = list2[ i ];
206 if ((t1.time() == t2.time()) &&
207 (t1.phase().utcOffset() == t2.phase().utcOffset()) &&
208 (t1.phase().isDst() == t2.phase().isDst())) {
230 const QString &countryCode,
231 float latitude,
float longitude,
232 const QString &comment)
233 : KTimeZoneBackend(source, name, countryCode, latitude, longitude, comment)
237 : KTimeZoneBackend(0, tz.name(), tz.countryCode(), tz.latitude(), tz.longitude(), tz.comment())
242ICalTimeZoneBackend::~ICalTimeZoneBackend()
252 return "ICalTimeZone";
282 tz.latitude(), tz.longitude(),
285 const KTimeZoneData *data = tz.data(
true);
302 return dat ? dat->
city() : QString();
308 return dat ? dat->
url() : QByteArray();
320 return dat ? dat->
vtimezone() : QByteArray();
331 if (!updateBase(other)) {
335 KTimeZoneData *otherData = other.data() ? other.data()->clone() : 0;
336 setData(otherData, other.source());
343 if (!utcZone.isValid()) {
345 utcZone = tzs.
parse(icaltimezone_get_utc_timezone());
358class ICalTimeZoneDataPrivate
361 ICalTimeZoneDataPrivate() : icalComponent(0) {}
363 ~ICalTimeZoneDataPrivate()
366 icalcomponent_free(icalComponent);
370 icalcomponent *component()
const {
371 return icalComponent;
373 void setComponent(icalcomponent *c)
376 icalcomponent_free(icalComponent);
383 QDateTime lastModified;
386 icalcomponent *icalComponent;
391 : d(new ICalTimeZoneDataPrivate())
396 : KTimeZoneData(rhs),
397 d(new ICalTimeZoneDataPrivate())
399 d->location = rhs.d->location;
402 d->setComponent(icalcomponent_new_clone(rhs.d->component()));
406 const KTimeZone &tz,
const QDate &earliest)
407 : KTimeZoneData(rhs),
408 d(new ICalTimeZoneDataPrivate())
413 WEEKDAY_OF_MONTH = 0x02,
414 LAST_WEEKDAY_OF_MONTH = 0x04
417 if (tz.type() ==
"KSystemTimeZone") {
421 icalcomponent *c = 0;
422 const KTimeZone ktz = KSystemTimeZones::readZone(tz.name());
424 if (ktz.data(
true)) {
428 c = icalcomponent_new_clone(icaltimezone_get_component(itz));
429 icaltimezone_free(itz, 1);
435 icaltimezone *itz = icaltimezone_get_builtin_timezone(tz.name().toUtf8());
436 c = icalcomponent_new_clone(icaltimezone_get_component(itz));
442 icalproperty *prop = icalcomponent_get_first_property(c, ICAL_TZID_PROPERTY);
444 icalvalue *value = icalproperty_get_value(prop);
445 const char *tzid = icalvalue_get_text(value);
447 const int len = icalprefix.size();
448 if (!strncmp(icalprefix, tzid, len)) {
449 const char *s = strchr(tzid + len,
'/');
451 const QByteArray tzidShort(s + 1);
452 icalvalue_set_text(value, tzidShort);
455 prop = icalcomponent_get_first_property(c, ICAL_X_PROPERTY);
456 const char *xname = icalproperty_get_x_name(prop);
457 if (xname && !strcmp(xname,
"X-LIC-LOCATION")) {
458 icalcomponent_remove_property(c, prop);
459 icalproperty_free(prop);
468 icalcomponent *tzcomp = icalcomponent_new(ICAL_VTIMEZONE_COMPONENT);
469 icalcomponent_add_property(tzcomp, icalproperty_new_tzid(tz.name().toUtf8()));
474 QList<KTimeZone::Transition> transits = transitions();
475 if (transits.isEmpty()) {
479 if (transits.isEmpty()) {
480 kDebug() <<
"No transition information available VTIMEZONE will be invalid.";
483 if (earliest.isValid()) {
485 for (
int i = 0, end = transits.count(); i < end; ++i) {
486 if (transits.at(i).time().date() >= earliest) {
488 transits.erase(transits.begin(), transits.begin() + i);
494 int trcount = transits.count();
495 QVector<bool> transitionsDone(trcount);
496 transitionsDone.fill(
false);
500 icaldatetimeperiodtype dtperiod;
501 dtperiod.period = icalperiodtype_null_period();
504 for (; i < trcount && transitionsDone[i]; ++i) {
511 const int preOffset = (i > 0) ?
512 transits.at(i - 1).phase().utcOffset() :
513 rhs.previousUtcOffset();
514 const KTimeZone::Phase phase = transits.at(i).phase();
515 if (phase.utcOffset() == preOffset) {
516 transitionsDone[i] =
true;
517 while (++i < trcount) {
518 if (transitionsDone[i] ||
519 transits.at(i).phase() != phase ||
520 transits.at(i - 1).phase().utcOffset() != preOffset) {
523 transitionsDone[i] =
true;
527 icalcomponent *phaseComp =
528 icalcomponent_new(phase.isDst() ? ICAL_XDAYLIGHT_COMPONENT : ICAL_XSTANDARD_COMPONENT);
529 const QList<QByteArray> abbrevs = phase.abbreviations();
530 for (
int a = 0, aend = abbrevs.count(); a < aend; ++a) {
531 icalcomponent_add_property(phaseComp,
532 icalproperty_new_tzname(
533 static_cast<const char*
>(abbrevs[a])));
535 if (!phase.comment().isEmpty()) {
536 icalcomponent_add_property(phaseComp,
537 icalproperty_new_comment(phase.comment().toUtf8()));
539 icalcomponent_add_property(phaseComp,
540 icalproperty_new_tzoffsetfrom(preOffset));
541 icalcomponent_add_property(phaseComp,
542 icalproperty_new_tzoffsetto(phase.utcOffset()));
544 icalcomponent *phaseComp1 = icalcomponent_new_clone(phaseComp);
545 icalcomponent_add_property(phaseComp1,
546 icalproperty_new_dtstart(
547 writeLocalICalDateTime(transits.at(i).time(),
549 bool useNewRRULE =
false;
555 int year = 0, month = 0, daysInMonth = 0, dayOfMonth = 0;
557 int nthFromStart = 0;
561 QList<QDateTime> rdates;
562 QList<QDateTime> times;
563 QDateTime qdt = transits.at(i).time();
565 transitionsDone[i] =
true;
569 rule = DAY_OF_MONTH | WEEKDAY_OF_MONTH | LAST_WEEKDAY_OF_MONTH;
573 month = date.month();
574 daysInMonth = date.daysInMonth();
575 dayOfWeek = date.dayOfWeek();
576 dayOfMonth = date.day();
577 nthFromStart = (dayOfMonth - 1) / 7 + 1;
578 nthFromEnd = (daysInMonth - dayOfMonth) / 7 + 1;
580 if (++i >= trcount) {
582 times += QDateTime();
584 if (transitionsDone[i] ||
585 transits.at(i).phase() != phase ||
586 transits.at(i - 1).phase().utcOffset() != preOffset) {
589 transitionsDone[i] =
true;
590 qdt = transits.at(i).time();
591 if (!qdt.isValid()) {
597 if (qdt.time() != time ||
598 date.month() != month ||
599 date.year() != ++year) {
602 const int day = date.day();
603 if ((newRule & DAY_OF_MONTH) && day != dayOfMonth) {
604 newRule &= ~DAY_OF_MONTH;
606 if (newRule & (WEEKDAY_OF_MONTH | LAST_WEEKDAY_OF_MONTH)) {
607 if (date.dayOfWeek() != dayOfWeek) {
608 newRule &= ~(WEEKDAY_OF_MONTH | LAST_WEEKDAY_OF_MONTH);
610 if ((newRule & WEEKDAY_OF_MONTH) &&
611 (day - 1) / 7 + 1 != nthFromStart) {
612 newRule &= ~WEEKDAY_OF_MONTH;
614 if ((newRule & LAST_WEEKDAY_OF_MONTH) &&
615 (daysInMonth - day) / 7 + 1 != nthFromEnd) {
616 newRule &= ~LAST_WEEKDAY_OF_MONTH;
626 int yr = times[0].date().year();
627 while (!rdates.isEmpty()) {
630 if (qdt.time() != time ||
631 date.month() != month ||
632 date.year() != --yr) {
635 const int day = date.day();
636 if (rule & DAY_OF_MONTH) {
637 if (day != dayOfMonth) {
641 if (date.dayOfWeek() != dayOfWeek ||
642 ((rule & WEEKDAY_OF_MONTH) &&
643 (day - 1) / 7 + 1 != nthFromStart) ||
644 ((rule & LAST_WEEKDAY_OF_MONTH) &&
645 (daysInMonth - day) / 7 + 1 != nthFromEnd)) {
652 if (times.count() > (useNewRRULE ? minPhaseCount : minRuleCount)) {
654 icalrecurrencetype r;
655 icalrecurrencetype_clear(&r);
656 r.freq = ICAL_YEARLY_RECURRENCE;
657 r.count = (year >= 2030) ? 0 : times.count() - 1;
658 r.by_month[0] = month;
659 if (rule & DAY_OF_MONTH) {
660 r.by_month_day[0] = dayOfMonth;
661 }
else if (rule & WEEKDAY_OF_MONTH) {
662 r.by_day[0] = (dayOfWeek % 7 + 1) + (nthFromStart * 8);
663 }
else if (rule & LAST_WEEKDAY_OF_MONTH) {
664 r.by_day[0] = -(dayOfWeek % 7 + 1) - (nthFromEnd * 8);
666 icalproperty *prop = icalproperty_new_rrule(r);
670 icalcomponent *c = icalcomponent_new_clone(phaseComp);
671 icalcomponent_add_property(
672 c, icalproperty_new_dtstart(writeLocalICalDateTime(times[0], preOffset)));
673 icalcomponent_add_property(c, prop);
674 icalcomponent_add_component(tzcomp, c);
676 icalcomponent_add_property(phaseComp1, prop);
680 for (
int t = 0, tend = times.count() - 1; t < tend; ++t) {
692 }
while (i < trcount);
695 for (
int rd = 0, rdend = rdates.count(); rd < rdend; ++rd) {
696 dtperiod.time = writeLocalICalDateTime(rdates[rd], preOffset);
697 icalcomponent_add_property(phaseComp1, icalproperty_new_rdate(dtperiod));
699 icalcomponent_add_component(tzcomp, phaseComp1);
700 icalcomponent_free(phaseComp);
703 d->setComponent(tzcomp);
719 KTimeZoneData::operator=(rhs);
720 d->location = rhs.d->location;
723 d->setComponent(icalcomponent_new_clone(rhs.d->component()));
744 return d->lastModified;
749 const QByteArray result(icalcomponent_as_ical_string(d->component()));
750 icalmemory_free_ring();
756 icaltimezone *icaltz = icaltimezone_new();
760 icalcomponent *c = icalcomponent_new_clone(d->component());
761 if (!icaltimezone_set_component(icaltz, c)) {
762 icalcomponent_free(c);
763 icaltimezone_free(icaltz, 1);
783class ICalTimeZoneSourcePrivate
786 static QList<QDateTime> parsePhase(icalcomponent *,
bool daylight,
787 int &prevOffset, KTimeZone::Phase &);
788 static QByteArray icalTzidPrefix;
790#if defined(HAVE_UUID_UUID_H)
791 static void parseTransitions(
const MSSystemTime &date,
const KTimeZone::Phase &phase,
792 int prevOffset, QList<KTimeZone::Transition> &transitions);
796QByteArray ICalTimeZoneSourcePrivate::icalTzidPrefix;
800 : KTimeZoneSource(false),
812 QFile file(fileName);
813 if (!file.open(QIODevice::ReadOnly)) {
816 QTextStream ts(&file);
817 ts.setCodec(
"ISO 8859-1");
818 const QByteArray text = ts.readAll().trimmed().toLatin1();
822 icalcomponent *calendar = icalcomponent_new_from_string(text.data());
824 if (icalcomponent_isa(calendar) == ICAL_VCALENDAR_COMPONENT) {
825 result =
parse(calendar, zones);
827 icalcomponent_free(calendar);
834 for (icalcomponent *c = icalcomponent_get_first_component(calendar, ICAL_VTIMEZONE_COMPONENT);
835 c; c = icalcomponent_get_next_component(calendar, ICAL_VTIMEZONE_COMPONENT)) {
837 if (!zone.isValid()) {
841 if (oldzone.isValid()) {
845 }
else if (!zones.
add(zone)) {
859 icalproperty *p = icalcomponent_get_first_property(vtimezone, ICAL_ANY_PROPERTY);
861 icalproperty_kind kind = icalproperty_isa(p);
864 case ICAL_TZID_PROPERTY:
865 name = QString::fromUtf8(icalproperty_get_tzid(p));
868 case ICAL_TZURL_PROPERTY:
869 data->d->
url = icalproperty_get_tzurl(p);
872 case ICAL_LOCATION_PROPERTY:
874 data->d->location = QString::fromUtf8(icalproperty_get_location(p));
877 case ICAL_X_PROPERTY:
879 const char *xname = icalproperty_get_x_name(p);
880 if (xname && !strcmp(xname,
"X-LIC-LOCATION")) {
881 xlocation = QString::fromUtf8(icalproperty_get_x(p));
885 case ICAL_LASTMODIFIED_PROPERTY:
887 const icaltimetype t = icalproperty_get_lastmodified(p);
888 if (icaltime_is_utc( t )) {
891 kDebug() <<
"LAST-MODIFIED not UTC";
898 p = icalcomponent_get_next_property(vtimezone, ICAL_ANY_PROPERTY);
901 if (name.isEmpty()) {
902 kDebug() <<
"TZID missing";
906 if (data->d->location.isEmpty() && !xlocation.isEmpty()) {
907 data->d->location = xlocation;
910 if (name.startsWith(prefix)) {
912 const int i = name.indexOf(QLatin1Char(
'/'), prefix.length());
914 name = name.mid(i + 1);
924 QList<KTimeZone::Transition> transitions;
926 QList<KTimeZone::Phase> phases;
927 for (icalcomponent *c = icalcomponent_get_first_component(vtimezone, ICAL_ANY_COMPONENT);
928 c; c = icalcomponent_get_next_component(vtimezone, ICAL_ANY_COMPONENT)) {
930 KTimeZone::Phase phase;
931 QList<QDateTime> times;
932 icalcomponent_kind kind = icalcomponent_isa(c);
935 case ICAL_XSTANDARD_COMPONENT:
937 times = ICalTimeZoneSourcePrivate::parsePhase(c,
false, prevoff, phase);
940 case ICAL_XDAYLIGHT_COMPONENT:
942 times = ICalTimeZoneSourcePrivate::parsePhase(c,
true, prevoff, phase);
946 kDebug() <<
"Unknown component:" << int(kind);
949 const int tcount = times.count();
952 for (
int t = 0; t < tcount; ++t) {
953 transitions += KTimeZone::Transition(times[t], phase);
955 if (!earliest.isValid() || times[0] < earliest) {
956 prevOffset = prevoff;
963 data->setPhases(phases, prevOffset);
967 for (
int t = 1, tend = transitions.count(); t < tend;) {
968 if (transitions[t].phase() == transitions[t - 1].phase()) {
969 transitions.removeAt(t);
975 data->setTransitions(transitions);
977 data->d->setComponent(icalcomponent_new_clone(vtimezone));
982#if defined(HAVE_UUID_UUID_H)
986 if (!zone.isValid()) {
990 if (oldzone.isValid()) {
994 }
else if (zones.
add(zone)) {
1008 uuid_generate_random(uuid);
1009 uuid_unparse(uuid, suuid);
1010 QString name = QString::fromLatin1(suuid);
1013 QList<KTimeZone::Phase> phases;
1015 QList<QByteArray> standardAbbrevs;
1016 standardAbbrevs += tz->StandardName.toLatin1();
1017 const KTimeZone::Phase standardPhase(
1018 (tz->Bias + tz->StandardBias) * -60,
1019 standardAbbrevs,
false,
1020 QLatin1String(
"Microsoft TIME_ZONE_INFORMATION"));
1021 phases += standardPhase;
1023 QList<QByteArray> daylightAbbrevs;
1024 daylightAbbrevs += tz->DaylightName.toLatin1();
1025 const KTimeZone::Phase daylightPhase(
1026 (tz->Bias + tz->DaylightBias) * -60,
1027 daylightAbbrevs,
true,
1028 QLatin1String(
"Microsoft TIME_ZONE_INFORMATION"));
1029 phases += daylightPhase;
1033 const int prevOffset = tz->Bias * -60;
1034 kdata.setPhases(phases, prevOffset);
1037 QList<KTimeZone::Transition> transitions;
1038 ICalTimeZoneSourcePrivate::parseTransitions(
1039 tz->StandardDate, standardPhase, prevOffset, transitions);
1040 ICalTimeZoneSourcePrivate::parseTransitions(
1041 tz->DaylightDate, daylightPhase, prevOffset, transitions);
1044 kdata.setTransitions(transitions);
1056 if (!zone.isValid()) {
1062 if (oldzone.isValid()) {
1066 oldzone = zones.
zone(name);
1067 if (oldzone.isValid()) {
1071 }
else if (zones.
add(zone)) {
1081 QList<KTimeZone::Phase> phases;
1082 QList<KTimeZone::Transition> transitions;
1085 for (QStringList::ConstIterator it = tzList.begin(); it != tzList.end(); ++it) {
1086 QString value = *it;
1088 const QString tzName = value.mid(0, value.indexOf(QLatin1String(
";")));
1089 value = value.mid((value.indexOf(QLatin1String(
";")) + 1));
1090 const QString tzOffset = value.mid(0, value.indexOf(QLatin1String(
";")));
1091 value = value.mid((value.indexOf(QLatin1String(
";")) + 1));
1092 const QString tzDaylight = value.mid(0, value.indexOf(QLatin1String(
";")));
1093 const KDateTime tzDate = KDateTime::fromString(value.mid((value.lastIndexOf(QLatin1String(
";")) + 1)));
1094 if (tzDaylight == QLatin1String(
"true")) {
1098 const KTimeZone::Phase tzPhase(
1100 QByteArray(tzName.toLatin1()), daylight, QLatin1String(
"VCAL_TZ_INFORMATION"));
1102 transitions += KTimeZone::Transition(tzDate.dateTime(), tzPhase);
1105 kdata.setPhases(phases, 0);
1107 kdata.setTransitions(transitions);
1113#if defined(HAVE_UUID_UUID_H)
1115void ICalTimeZoneSourcePrivate::parseTransitions(
const MSSystemTime &date,
1116 const KTimeZone::Phase &phase,
int prevOffset,
1117 QList<KTimeZone::Transition> &transitions)
1121 const KDateTime klocalStart(QDateTime(QDate(2000, 1, 1), QTime(0, 0, 0)),
1122 KDateTime::Spec::ClockTime());
1123 const KDateTime maxTime(MAX_DATE(), KDateTime::Spec::ClockTime());
1127 if (date.wYear >= 1601 && date.wYear <= 30827 &&
1128 date.wMonth >= 1 && date.wMonth <= 12 &&
1129 date.wDay >= 1 && date.wDay <= 31) {
1130 const QDate dt(date.wYear, date.wMonth, date.wDay);
1131 const QTime tm(date.wHour, date.wMinute, date.wSecond, date.wMilliseconds);
1132 const QDateTime datetime(dt, tm);
1133 if (datetime.isValid()) {
1134 transitions += KTimeZone::Transition(datetime, phase);
1139 if (date.wDayOfWeek >= 0 && date.wDayOfWeek <= 6 &&
1140 date.wMonth >= 1 && date.wMonth <= 12 &&
1141 date.wDay >= 1 && date.wDay <= 5) {
1143 r.setRecurrenceType(RecurrenceRule::rYearly);
1147 lst.append(date.wMonth);
1149 QList<RecurrenceRule::WDayPos> wdlst;
1151 pos.setDay(date.wDayOfWeek ? date.wDayOfWeek : 7);
1152 pos.setPos(date.wDay < 5 ? date.wDay : -1);
1158 for (
int i = 0, end = dtl.count(); i < end; ++i) {
1159 QDateTime utc = dtl[i].dateTime();
1160 utc.setTimeSpec(Qt::UTC);
1161 transitions += KTimeZone::Transition(utc.addSecs(-prevOffset), phase);
1179QList<QDateTime> ICalTimeZoneSourcePrivate::parsePhase(icalcomponent *c,
1182 KTimeZone::Phase &phase)
1184 QList<QDateTime> transitions;
1187 QList<QByteArray> abbrevs;
1191 bool recurs =
false;
1192 bool found_dtstart =
false;
1193 bool found_tzoffsetfrom =
false;
1194 bool found_tzoffsetto =
false;
1195 icaltimetype dtstart = icaltime_null_time();
1198 icalproperty *p = icalcomponent_get_first_property(c, ICAL_ANY_PROPERTY);
1200 icalproperty_kind kind = icalproperty_isa(p);
1203 case ICAL_TZNAME_PROPERTY:
1209 QByteArray tzname = icalproperty_get_tzname(p);
1212 if ((!daylight && tzname ==
"Standard Time") ||
1213 (daylight && tzname ==
"Daylight Time")) {
1216 if (!abbrevs.contains(tzname)) {
1221 case ICAL_DTSTART_PROPERTY:
1222 dtstart = icalproperty_get_dtstart(p);
1223 found_dtstart =
true;
1226 case ICAL_TZOFFSETFROM_PROPERTY:
1227 prevOffset = icalproperty_get_tzoffsetfrom(p);
1228 found_tzoffsetfrom =
true;
1231 case ICAL_TZOFFSETTO_PROPERTY:
1232 utcOffset = icalproperty_get_tzoffsetto(p);
1233 found_tzoffsetto =
true;
1236 case ICAL_COMMENT_PROPERTY:
1237 comment = QString::fromUtf8(icalproperty_get_comment(p));
1240 case ICAL_RDATE_PROPERTY:
1241 case ICAL_RRULE_PROPERTY:
1246 kDebug() <<
"Unknown property:" << int(kind);
1249 p = icalcomponent_get_next_property(c, ICAL_ANY_PROPERTY);
1253 if (!found_dtstart || !found_tzoffsetfrom || !found_tzoffsetto) {
1254 kDebug() <<
"DTSTART/TZOFFSETFROM/TZOFFSETTO missing";
1259 const QDateTime localStart = toQDateTime(dtstart);
1260 dtstart.second -= prevOffset;
1261 dtstart.zone = icaltimezone_get_utc_timezone();
1262 const QDateTime utcStart = toQDateTime(icaltime_normalize(dtstart));
1264 transitions += utcStart;
1271 const KDateTime klocalStart(localStart, KDateTime::Spec::ClockTime());
1272 const KDateTime maxTime(MAX_DATE(), KDateTime::Spec::ClockTime());
1274 icalproperty *p = icalcomponent_get_first_property(c, ICAL_ANY_PROPERTY);
1276 icalproperty_kind kind = icalproperty_isa(p);
1279 case ICAL_RDATE_PROPERTY:
1281 icaltimetype t = icalproperty_get_rdate(p).time;
1282 if (icaltime_is_date(t)) {
1284 t.hour = dtstart.hour;
1285 t.minute = dtstart.minute;
1286 t.second = dtstart.second;
1292 if (!icaltime_is_utc( t )) {
1293 t.second -= prevOffset;
1294 t.zone = icaltimezone_get_utc_timezone();
1295 t = icaltime_normalize(t);
1297 transitions += toQDateTime(t);
1300 case ICAL_RRULE_PROPERTY:
1305 impl.readRecurrence(icalproperty_get_rrule(p), &r);
1310 KDateTime end(r.
endDt());
1311 if (end.timeSpec() == KDateTime::Spec::UTC()) {
1312 end.setTimeSpec(KDateTime::Spec::ClockTime());
1313 r.
setEndDt(end.addSecs(prevOffset));
1317 for (
int i = 0, end = dts.count(); i < end; ++i) {
1318 QDateTime utc = dts[i].dateTime();
1319 utc.setTimeSpec(Qt::UTC);
1320 transitions += utc.addSecs(-prevOffset);
1327 p = icalcomponent_get_next_property(c, ICAL_ANY_PROPERTY);
1329 qSortUnique(transitions);
1332 phase = KTimeZone::Phase(utcOffset, abbrevs, daylight, comment);
1343 QString tzid = zone;
1345 if (zone.startsWith(prefix)) {
1346 const int i = zone.indexOf(QLatin1Char(
'/'), prefix.length());
1348 tzid = zone.mid(i + 1);
1351 const KTimeZone ktz = KSystemTimeZones::readZone(tzid);
1352 if (ktz.isValid()) {
1353 if (ktz.data(
true)) {
1362 const QByteArray zoneName = zone.toUtf8();
1363 icaltimezone *icaltz = icaltimezone_get_builtin_timezone(zoneName);
1366 icaltz = icaltimezone_get_builtin_timezone_from_tzid(zoneName);
1371 return parse(icaltz);
1376 if (ICalTimeZoneSourcePrivate::icalTzidPrefix.isEmpty()) {
1377 icaltimezone *icaltz = icaltimezone_get_builtin_timezone(
"Europe/London");
1378 const QByteArray tzid = icaltimezone_get_tzid(icaltz);
1379 if (tzid.right(13) ==
"Europe/London") {
1380 int i = tzid.indexOf(
'/', 1);
1382 ICalTimeZoneSourcePrivate::icalTzidPrefix = tzid.left(i + 1);
1383 return ICalTimeZoneSourcePrivate::icalTzidPrefix;
1386 kError() <<
"failed to get libical TZID prefix";
1388 return ICalTimeZoneSourcePrivate::icalTzidPrefix;
Backend class for KICalTimeZone class.
ICalTimeZoneBackend()
Implements ICalTimeZone::ICalTimeZone().
virtual void virtual_hook(int id, void *data)
virtual KTimeZoneBackend * clone() const
Creates a copy of this instance.
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().
Parsed iCalendar VTIMEZONE data.
ICalTimeZoneData()
Default constructor.
icaltimezone * icalTimezone() const
Returns the ICal timezone structure which represents this time zone.
virtual KTimeZoneData * clone() const
Creates a new copy of this object.
virtual bool hasTransitions() const
Return whether daylight saving transitions are available for the time zone.
QByteArray url() const
Returns the URL of the published VTIMEZONE definition, if any.
QByteArray vtimezone() const
Returns the VTIMEZONE string which represents this time zone.
virtual void virtual_hook(int id, void *data)
virtual ~ICalTimeZoneData()
Destructor.
QDateTime lastModified() const
Returns the LAST-MODIFIED time of the VTIMEZONE, if any.
ICalTimeZoneData & operator=(const ICalTimeZoneData &rhs)
Assignment operator.
QString city() const
Returns the name of the city for this time zone, if any.
A class which reads and parses iCalendar VTIMEZONE components, and accesses libical time zone data.
static QByteArray icalTzidPrefix()
Returns the prefix string used in the TZID field in built-in libical time zones.
virtual void virtual_hook(int id, void *data)
ICalTimeZone standardZone(const QString &zone, bool icalBuiltIn=false)
Creates an ICalTimeZone instance for a standard time zone.
ICalTimeZone parse(icalcomponent *vtimezone)
Creates an ICalTimeZone instance containing the detailed information parsed from an iCalendar VTIMEZO...
ICalTimeZoneSource()
Constructs an iCalendar time zone source.
virtual ~ICalTimeZoneSource()
Destructor.
The ICalTimeZone class represents an iCalendar VTIMEZONE component.
QByteArray url() const
Returns the URL of the published VTIMEZONE definition, if any.
virtual ~ICalTimeZone()
Destructor.
QDateTime lastModified() const
Returns the LAST-MODIFIED time of the VTIMEZONE, if any.
QString city() const
Returns the name of the city for this time zone, if any.
ICalTimeZone()
Constructs a null time zone.
static ICalTimeZone utc()
Returns a standard UTC time zone, with name "UTC".
QByteArray vtimezone() const
Returns the VTIMEZONE string which represents this time zone.
icaltimezone * icalTimezone() const
Returns the ICal timezone structure which represents this time zone.
virtual void virtual_hook(int id, void *data)
bool update(const ICalTimeZone &other)
Update the definition of the time zone to be identical to another ICalTimeZone instance.
The ICalTimeZones class represents a time zone database which consists of a collection of individual ...
bool add(const ICalTimeZone &zone)
Adds a time zone to the collection.
ICalTimeZone zone(const QString &name) const
Returns the time zone with the given name.
void clear()
Clears the collection.
ICalTimeZones()
Constructs an empty time zone collection.
int count()
Returns the number of zones kept in memory.
ICalTimeZones & operator=(const ICalTimeZones &rhs)
Assignment operator.
~ICalTimeZones()
Destructor.
ICalTimeZone remove(const ICalTimeZone &zone)
Removes a time zone from the collection.
const ZoneMap zones() const
Returns all the time zones defined in this collection.
structure for describing the n-th weekday of the month/year.
This class represents a recurrence rule for a calendar incidence.
void setDuration(int duration)
Sets the total number of times the event is to occur, including both the first and last.
void setFrequency(int freq)
Sets the recurrence frequency, in terms of the recurrence time period type.
int duration() const
Returns -1 if the event recurs infinitely, 0 if the end date is set, otherwise the total number of re...
void setEndDt(const KDateTime &endDateTime)
Sets the date and time of the last recurrence.
KDateTime endDt(bool *result=0) const
Returns the date and time of the last recurrence.
void setStartDt(const KDateTime &start)
Sets the recurrence start date/time.
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.
This class represents a recurrence rule for a calendar incidence.
A QList which can be sorted.
Placeholhers for Microsoft and ActiveSync timezone data.