• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.14.3 API Reference
  • KDE Home
  • Contact Us
 

KCal Library

  • home
  • ichiro
  • data
  • ssd
  • Momonga
  • trunk
  • pkgs
  • kdepimlibs
  • BUILD
  • kdepimlibs-4.14.3
  • kcal
icaltimezones.cpp
1 /*
2  This file is part of the kcal library.
3 
4  Copyright (c) 2005-2007 David Jarvie <djarvie@kde.org>
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License as published by the Free Software Foundation; either
9  version 2 of the License, or (at your option) any later version.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Library General Public License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20 */
21 
22 #include "icaltimezones.h"
23 #include "icalformat.h"
24 #include "icalformat_p.h"
25 
26 extern "C" {
27  #include <libical/ical.h>
28  #include <libical/icaltimezone.h>
29 }
30 #include <ksystemtimezone.h>
31 #include <kdatetime.h>
32 #include <kdebug.h>
33 
34 #include <QtCore/QDateTime>
35 #include <QtCore/QString>
36 #include <QtCore/QList>
37 #include <QtCore/QVector>
38 #include <QtCore/QSet>
39 #include <QtCore/QFile>
40 #include <QtCore/QTextStream>
41 
42 using namespace KCal;
43 
44 // Minimum repetition counts for VTIMEZONE RRULEs
45 static const int minRuleCount = 5; // for any RRULE
46 static const int minPhaseCount = 8; // for separate STANDARD/DAYLIGHT component
47 
48 // Convert an ical time to QDateTime, preserving the UTC indicator
49 static QDateTime toQDateTime( const icaltimetype &t )
50 {
51  return QDateTime( QDate( t.year, t.month, t.day ),
52  QTime( t.hour, t.minute, t.second ),
53  ( icaltime_is_utc( t ) ? Qt::UTC : Qt::LocalTime ) );
54 }
55 
56 // Maximum date for time zone data.
57 // It's not sensible to try to predict them very far in advance, because
58 // they can easily change. Plus, it limits the processing required.
59 static QDateTime MAX_DATE()
60 {
61  static QDateTime dt;
62  if ( !dt.isValid() ) {
63  dt = QDateTime( QDate::currentDate().addYears( 20 ), QTime( 0, 0, 0 ) );
64  }
65  return dt;
66 }
67 
68 static icaltimetype writeLocalICalDateTime( const QDateTime &utc, int offset )
69 {
70  QDateTime local = utc.addSecs( offset );
71  icaltimetype t = icaltime_null_time();
72  t.year = local.date().year();
73  t.month = local.date().month();
74  t.day = local.date().day();
75  t.hour = local.time().hour();
76  t.minute = local.time().minute();
77  t.second = local.time().second();
78  t.is_date = 0;
79  t.zone = 0;
80  return t;
81 }
82 
83 namespace KCal {
84 
85 /******************************************************************************/
86 
87 //@cond PRIVATE
88 class ICalTimeZonesPrivate
89 {
90  public:
91  ICalTimeZonesPrivate() {}
92  ICalTimeZones::ZoneMap zones;
93 };
94 //@endcond
95 
96 ICalTimeZones::ICalTimeZones()
97  : d( new ICalTimeZonesPrivate )
98 {
99 }
100 
101 ICalTimeZones::~ICalTimeZones()
102 {
103  delete d;
104 }
105 
106 const ICalTimeZones::ZoneMap ICalTimeZones::zones() const
107 {
108  return d->zones;
109 }
110 
111 bool ICalTimeZones::add( const ICalTimeZone &zone )
112 {
113  if ( !zone.isValid() ) {
114  return false;
115  }
116  if ( d->zones.find( zone.name() ) != d->zones.end() ) {
117  return false; // name already exists
118  }
119 
120  d->zones.insert( zone.name(), zone );
121  return true;
122 }
123 
124 ICalTimeZone ICalTimeZones::remove( const ICalTimeZone &zone )
125 {
126  if ( zone.isValid() ) {
127  for ( ZoneMap::Iterator it = d->zones.begin(), end = d->zones.end(); it != end; ++it ) {
128  if ( it.value() == zone ) {
129  d->zones.erase( it );
130  return ( zone == ICalTimeZone::utc() ) ? ICalTimeZone() : zone;
131  }
132  }
133  }
134  return ICalTimeZone();
135 }
136 
137 ICalTimeZone ICalTimeZones::remove( const QString &name )
138 {
139  if ( !name.isEmpty() ) {
140  ZoneMap::Iterator it = d->zones.find( name );
141  if ( it != d->zones.end() ) {
142  ICalTimeZone zone = it.value();
143  d->zones.erase(it);
144  return ( zone == ICalTimeZone::utc() ) ? ICalTimeZone() : zone;
145  }
146  }
147  return ICalTimeZone();
148 }
149 
150 void ICalTimeZones::clear()
151 {
152  d->zones.clear();
153 }
154 
155 ICalTimeZone ICalTimeZones::zone( const QString &name ) const
156 {
157  if ( !name.isEmpty() ) {
158  ZoneMap::ConstIterator it = d->zones.constFind( name );
159  if ( it != d->zones.constEnd() ) {
160  return it.value();
161  }
162  }
163  return ICalTimeZone(); // error
164 }
165 
166 /******************************************************************************/
167 
168 ICalTimeZoneBackend::ICalTimeZoneBackend()
169  : KTimeZoneBackend()
170 {}
171 
172 ICalTimeZoneBackend::ICalTimeZoneBackend( ICalTimeZoneSource *source,
173  const QString &name,
174  const QString &countryCode,
175  float latitude, float longitude,
176  const QString &comment )
177  : KTimeZoneBackend( source, name, countryCode, latitude, longitude, comment )
178 {}
179 
180 ICalTimeZoneBackend::ICalTimeZoneBackend( const KTimeZone &tz, const QDate &earliest )
181  : KTimeZoneBackend( 0, tz.name(), tz.countryCode(), tz.latitude(), tz.longitude(), tz.comment() )
182 {
183  Q_UNUSED( earliest );
184 }
185 
186 ICalTimeZoneBackend::~ICalTimeZoneBackend()
187 {}
188 
189 KTimeZoneBackend *ICalTimeZoneBackend::clone() const
190 {
191  return new ICalTimeZoneBackend( *this );
192 }
193 
194 QByteArray ICalTimeZoneBackend::type() const
195 {
196  return "ICalTimeZone";
197 }
198 
199 bool ICalTimeZoneBackend::hasTransitions( const KTimeZone *caller ) const
200 {
201  Q_UNUSED( caller );
202  return true;
203 }
204 
205 /******************************************************************************/
206 
207 ICalTimeZone::ICalTimeZone()
208  : KTimeZone( new ICalTimeZoneBackend() )
209 {}
210 
211 ICalTimeZone::ICalTimeZone( ICalTimeZoneSource *source, const QString &name,
212  ICalTimeZoneData *data )
213  : KTimeZone( new ICalTimeZoneBackend( source, name ) )
214 {
215  setData( data );
216 }
217 
218 ICalTimeZone::ICalTimeZone( const KTimeZone &tz, const QDate &earliest )
219  : KTimeZone( new ICalTimeZoneBackend( 0, tz.name(), tz.countryCode(),
220  tz.latitude(), tz.longitude(),
221  tz.comment() ) )
222 {
223  const KTimeZoneData *data = tz.data( true );
224  if ( data ) {
225  const ICalTimeZoneData *icaldata = dynamic_cast<const ICalTimeZoneData*>( data );
226  if ( icaldata ) {
227  setData( new ICalTimeZoneData( *icaldata ) );
228  } else {
229  setData( new ICalTimeZoneData( *data, tz, earliest ) );
230  }
231  }
232 }
233 
234 ICalTimeZone::~ICalTimeZone()
235 {}
236 
237 QString ICalTimeZone::city() const
238 {
239  const ICalTimeZoneData *dat = static_cast<const ICalTimeZoneData*>( data() );
240  return dat ? dat->city() : QString();
241 }
242 
243 QByteArray ICalTimeZone::url() const
244 {
245  const ICalTimeZoneData *dat = static_cast<const ICalTimeZoneData*>( data() );
246  return dat ? dat->url() : QByteArray();
247 }
248 
249 QDateTime ICalTimeZone::lastModified() const
250 {
251  const ICalTimeZoneData *dat = static_cast<const ICalTimeZoneData*>( data() );
252  return dat ? dat->lastModified() : QDateTime();
253 }
254 
255 QByteArray ICalTimeZone::vtimezone() const
256 {
257  const ICalTimeZoneData *dat = static_cast<const ICalTimeZoneData*>( data() );
258  return dat ? dat->vtimezone() : QByteArray();
259 }
260 
261 icaltimezone *ICalTimeZone::icalTimezone() const
262 {
263  const ICalTimeZoneData *dat = static_cast<const ICalTimeZoneData*>( data() );
264  return dat ? dat->icalTimezone() : 0;
265 }
266 
267 bool ICalTimeZone::update( const ICalTimeZone &other )
268 {
269  if ( !updateBase( other ) ) {
270  return false;
271  }
272 
273  KTimeZoneData *otherData = other.data() ? other.data()->clone() : 0;
274  setData( otherData, other.source() );
275  return true;
276 }
277 
278 ICalTimeZone ICalTimeZone::utc()
279 {
280  static ICalTimeZone utcZone;
281  if ( !utcZone.isValid() ) {
282  ICalTimeZoneSource tzs;
283  utcZone = tzs.parse( icaltimezone_get_utc_timezone() );
284  }
285  return utcZone;
286 }
287 
288 /******************************************************************************/
289 
290 //@cond PRIVATE
291 class ICalTimeZoneDataPrivate
292 {
293  public:
294  ICalTimeZoneDataPrivate() : icalComponent(0) {}
295  ~ICalTimeZoneDataPrivate()
296  {
297  if ( icalComponent ) {
298  icalcomponent_free( icalComponent );
299  }
300  }
301  icalcomponent *component() const { return icalComponent; }
302  void setComponent( icalcomponent *c )
303  {
304  if ( icalComponent ) {
305  icalcomponent_free( icalComponent );
306  }
307  icalComponent = c;
308  }
309  QString location; // name of city for this time zone
310  QByteArray url; // URL of published VTIMEZONE definition (optional)
311  QDateTime lastModified; // time of last modification of the VTIMEZONE component (optional)
312  private:
313  icalcomponent *icalComponent; // ical component representing this time zone
314 };
315 //@endcond
316 
317 ICalTimeZoneData::ICalTimeZoneData()
318  : d ( new ICalTimeZoneDataPrivate() )
319 {
320 }
321 
322 ICalTimeZoneData::ICalTimeZoneData( const ICalTimeZoneData &rhs )
323  : KTimeZoneData( rhs ),
324  d( new ICalTimeZoneDataPrivate() )
325 {
326  d->location = rhs.d->location;
327  d->url = rhs.d->url;
328  d->lastModified = rhs.d->lastModified;
329  d->setComponent( icalcomponent_new_clone( rhs.d->component() ) );
330 }
331 
332 ICalTimeZoneData::ICalTimeZoneData( const KTimeZoneData &rhs,
333  const KTimeZone &tz, const QDate &earliest )
334  : KTimeZoneData( rhs ),
335  d( new ICalTimeZoneDataPrivate() )
336 {
337  // VTIMEZONE RRULE types
338  enum {
339  DAY_OF_MONTH = 0x01,
340  WEEKDAY_OF_MONTH = 0x02,
341  LAST_WEEKDAY_OF_MONTH = 0x04
342  };
343 
344  if ( tz.type() == "KSystemTimeZone" ) {
345  // Try to fetch a system time zone in preference, on the grounds
346  // that system time zones are more likely to be up to date than
347  // built-in libical ones.
348  icalcomponent *c = 0;
349  KTimeZone ktz = KSystemTimeZones::readZone( tz.name() );
350  if ( ktz.isValid() ) {
351  if ( ktz.data(true) ) {
352  ICalTimeZone icaltz( ktz, earliest );
353  icaltimezone *itz = icaltz.icalTimezone();
354  c = icalcomponent_new_clone( icaltimezone_get_component( itz ) );
355  icaltimezone_free( itz, 1 );
356  }
357  }
358  if ( !c ) {
359  // Try to fetch a built-in libical time zone.
360  icaltimezone *itz = icaltimezone_get_builtin_timezone( tz.name().toUtf8() );
361  c = icalcomponent_new_clone( icaltimezone_get_component( itz ) );
362  }
363  if ( c ) {
364  // TZID in built-in libical time zones has a standard prefix.
365  // To make the VTIMEZONE TZID match TZID references in incidences
366  // (as required by RFC2445), strip off the prefix.
367  icalproperty *prop = icalcomponent_get_first_property( c, ICAL_TZID_PROPERTY );
368  if ( prop ) {
369  icalvalue *value = icalproperty_get_value( prop );
370  const char *tzid = icalvalue_get_text( value );
371  QByteArray icalprefix = ICalTimeZoneSource::icalTzidPrefix();
372  int len = icalprefix.size();
373  if ( !strncmp( icalprefix, tzid, len ) ) {
374  const char *s = strchr( tzid + len, '/' ); // find third '/'
375  if ( s ) {
376  QByteArray tzidShort( s + 1 ); // deep copy of string (needed by icalvalue_set_text())
377  icalvalue_set_text( value, tzidShort );
378 
379  // Remove the X-LIC-LOCATION property, which is only used by libical
380  prop = icalcomponent_get_first_property( c, ICAL_X_PROPERTY );
381  const char *xname = icalproperty_get_x_name( prop );
382  if ( xname && !strcmp( xname, "X-LIC-LOCATION" ) ) {
383  icalcomponent_remove_property( c, prop );
384  }
385  }
386  }
387  }
388  }
389  d->setComponent( c );
390  } else {
391  // Write the time zone data into an iCal component
392  icalcomponent *tzcomp = icalcomponent_new(ICAL_VTIMEZONE_COMPONENT);
393  icalcomponent_add_property( tzcomp, icalproperty_new_tzid( tz.name().toUtf8() ) );
394 // icalcomponent_add_property(tzcomp, icalproperty_new_location( tz.name().toUtf8() ));
395 
396  // Compile an ordered list of transitions so that we can know the phases
397  // which occur before and after each transition.
398  QList<KTimeZone::Transition> transits = transitions();
399  if ( earliest.isValid() ) {
400  // Remove all transitions earlier than those we are interested in
401  for ( int i = 0, end = transits.count(); i < end; ++i ) {
402  if ( transits[i].time().date() >= earliest ) {
403  if ( i > 0 ) {
404  transits.erase( transits.begin(), transits.begin() + i );
405  }
406  break;
407  }
408  }
409  }
410  int trcount = transits.count();
411  QVector<bool> transitionsDone(trcount);
412  transitionsDone.fill(false);
413 
414  // Go through the list of transitions and create an iCal component for each
415  // distinct combination of phase after and UTC offset before the transition.
416  icaldatetimeperiodtype dtperiod;
417  dtperiod.period = icalperiodtype_null_period();
418  for ( ; ; ) {
419  int i = 0;
420  for ( ; i < trcount && transitionsDone[i]; ++i ) {
421  ;
422  }
423  if ( i >= trcount ) {
424  break;
425  }
426  // Found a phase combination which hasn't yet been processed
427  int preOffset = ( i > 0 ) ? transits[i - 1].phase().utcOffset() : rhs.previousUtcOffset();
428  KTimeZone::Phase phase = transits[i].phase();
429  if ( phase.utcOffset() == preOffset ) {
430  transitionsDone[i] = true;
431  while ( ++i < trcount ) {
432  if ( transitionsDone[i] ||
433  transits[i].phase() != phase ||
434  transits[i - 1].phase().utcOffset() != preOffset ) {
435  continue;
436  }
437  transitionsDone[i] = true;
438  }
439  continue;
440  }
441  icalcomponent *phaseComp =
442  icalcomponent_new( phase.isDst() ? ICAL_XDAYLIGHT_COMPONENT : ICAL_XSTANDARD_COMPONENT );
443  QList<QByteArray> abbrevs = phase.abbreviations();
444  for ( int a = 0, aend = abbrevs.count(); a < aend; ++a ) {
445  icalcomponent_add_property( phaseComp,
446  icalproperty_new_tzname(
447  static_cast<const char*>( abbrevs[a]) ) );
448  }
449  if ( !phase.comment().isEmpty() ) {
450  icalcomponent_add_property( phaseComp,
451  icalproperty_new_comment( phase.comment().toUtf8() ) );
452  }
453  icalcomponent_add_property( phaseComp,
454  icalproperty_new_tzoffsetfrom( preOffset ) );
455  icalcomponent_add_property( phaseComp,
456  icalproperty_new_tzoffsetto( phase.utcOffset() ) );
457  // Create a component to hold initial RRULE if any, plus all RDATEs
458  icalcomponent *phaseComp1 = icalcomponent_new_clone( phaseComp );
459  icalcomponent_add_property( phaseComp1,
460  icalproperty_new_dtstart(
461  writeLocalICalDateTime( transits[i].time(), preOffset ) ) );
462  bool useNewRRULE = false;
463 
464  // Compile the list of UTC transition dates/times, and check
465  // if the list can be reduced to an RRULE instead of multiple RDATEs.
466  QTime time;
467  QDate date;
468  int year = 0, month = 0, daysInMonth = 0, dayOfMonth = 0; // avoid compiler warnings
469  int dayOfWeek = 0; // Monday = 1
470  int nthFromStart = 0; // nth (weekday) of month
471  int nthFromEnd = 0; // nth last (weekday) of month
472  int newRule;
473  int rule = 0;
474  QList<QDateTime> rdates;// dates which (probably) need to be written as RDATEs
475  QList<QDateTime> times;
476  QDateTime qdt = transits[i].time(); // set 'qdt' for start of loop
477  times += qdt;
478  transitionsDone[i] = true;
479  do {
480  if ( !rule ) {
481  // Initialise data for detecting a new rule
482  rule = DAY_OF_MONTH | WEEKDAY_OF_MONTH | LAST_WEEKDAY_OF_MONTH;
483  time = qdt.time();
484  date = qdt.date();
485  year = date.year();
486  month = date.month();
487  daysInMonth = date.daysInMonth();
488  dayOfWeek = date.dayOfWeek(); // Monday = 1
489  dayOfMonth = date.day();
490  nthFromStart = ( dayOfMonth - 1 ) / 7 + 1; // nth (weekday) of month
491  nthFromEnd = ( daysInMonth - dayOfMonth ) / 7 + 1; // nth last (weekday) of month
492  }
493  if ( ++i >= trcount ) {
494  newRule = 0;
495  times += QDateTime(); // append a dummy value since last value in list is ignored
496  } else {
497  if ( transitionsDone[i] ||
498  transits[i].phase() != phase ||
499  transits[i - 1].phase().utcOffset() != preOffset ) {
500  continue;
501  }
502  transitionsDone[i] = true;
503  qdt = transits[i].time();
504  if ( !qdt.isValid() ) {
505  continue;
506  }
507  newRule = rule;
508  times += qdt;
509  date = qdt.date();
510  if ( qdt.time() != time ||
511  date.month() != month ||
512  date.year() != ++year ) {
513  newRule = 0;
514  } else {
515  int day = date.day();
516  if ( ( newRule & DAY_OF_MONTH ) && day != dayOfMonth ) {
517  newRule &= ~DAY_OF_MONTH;
518  }
519  if ( newRule & ( WEEKDAY_OF_MONTH | LAST_WEEKDAY_OF_MONTH ) ) {
520  if ( date.dayOfWeek() != dayOfWeek ) {
521  newRule &= ~( WEEKDAY_OF_MONTH | LAST_WEEKDAY_OF_MONTH );
522  } else {
523  if ( ( newRule & WEEKDAY_OF_MONTH ) &&
524  ( day - 1 ) / 7 + 1 != nthFromStart ) {
525  newRule &= ~WEEKDAY_OF_MONTH;
526  }
527  if ( ( newRule & LAST_WEEKDAY_OF_MONTH ) &&
528  ( daysInMonth - day ) / 7 + 1 != nthFromEnd ) {
529  newRule &= ~LAST_WEEKDAY_OF_MONTH;
530  }
531  }
532  }
533  }
534  }
535  if ( !newRule ) {
536  // The previous rule (if any) no longer applies.
537  // Write all the times up to but not including the current one.
538  // First check whether any of the last RDATE values fit this rule.
539  int yr = times[0].date().year();
540  while ( !rdates.isEmpty() ) {
541  qdt = rdates.last();
542  date = qdt.date();
543  if ( qdt.time() != time ||
544  date.month() != month ||
545  date.year() != --yr ) {
546  break;
547  }
548  int day = date.day();
549  if ( rule & DAY_OF_MONTH ) {
550  if ( day != dayOfMonth ) {
551  break;
552  }
553  } else {
554  if ( date.dayOfWeek() != dayOfWeek ||
555  ( ( rule & WEEKDAY_OF_MONTH ) &&
556  ( day - 1 ) / 7 + 1 != nthFromStart ) ||
557  ( ( rule & LAST_WEEKDAY_OF_MONTH ) &&
558  ( daysInMonth - day ) / 7 + 1 != nthFromEnd ) ) {
559  break;
560  }
561  }
562  times.prepend( qdt );
563  rdates.pop_back();
564  }
565  if ( times.count() > ( useNewRRULE ? minPhaseCount : minRuleCount ) ) {
566  // There are enough dates to combine into an RRULE
567  icalrecurrencetype r;
568  icalrecurrencetype_clear( &r );
569  r.freq = ICAL_YEARLY_RECURRENCE;
570  r.count = ( year >= 2030 ) ? 0 : times.count() - 1;
571  r.by_month[0] = month;
572  if ( rule & DAY_OF_MONTH ) {
573  r.by_month_day[0] = dayOfMonth;
574  } else if ( rule & WEEKDAY_OF_MONTH ) {
575  r.by_day[0] = ( dayOfWeek % 7 + 1 ) + ( nthFromStart * 8 ); // Sunday = 1
576  } else if ( rule & LAST_WEEKDAY_OF_MONTH ) {
577  r.by_day[0] = -( dayOfWeek % 7 + 1 ) - ( nthFromEnd * 8 ); // Sunday = 1
578  }
579  icalproperty *prop = icalproperty_new_rrule( r );
580  if ( useNewRRULE ) {
581  // This RRULE doesn't start from the phase start date, so set it into
582  // a new STANDARD/DAYLIGHT component in the VTIMEZONE.
583  icalcomponent *c = icalcomponent_new_clone( phaseComp );
584  icalcomponent_add_property(
585  c, icalproperty_new_dtstart( writeLocalICalDateTime( times[0], preOffset ) ) );
586  icalcomponent_add_property( c, prop );
587  icalcomponent_add_component( tzcomp, c );
588  } else {
589  icalcomponent_add_property( phaseComp1, prop );
590  }
591  } else {
592  // Save dates for writing as RDATEs
593  for ( int t = 0, tend = times.count() - 1; t < tend; ++t ) {
594  rdates += times[t];
595  }
596  }
597  useNewRRULE = true;
598  // All date/time values but the last have been added to the VTIMEZONE.
599  // Remove them from the list.
600  qdt = times.last(); // set 'qdt' for start of loop
601  times.clear();
602  times += qdt;
603  }
604  rule = newRule;
605  } while ( i < trcount );
606 
607  // Write remaining dates as RDATEs
608  for ( int rd = 0, rdend = rdates.count(); rd < rdend; ++rd ) {
609  dtperiod.time = writeLocalICalDateTime( rdates[rd], preOffset );
610  icalcomponent_add_property( phaseComp1, icalproperty_new_rdate( dtperiod ) );
611  }
612  icalcomponent_add_component( tzcomp, phaseComp1 );
613  icalcomponent_free( phaseComp );
614  }
615 
616  d->setComponent( tzcomp );
617  }
618 }
619 
620 ICalTimeZoneData::~ICalTimeZoneData()
621 {
622  delete d;
623 }
624 
625 ICalTimeZoneData &ICalTimeZoneData::operator=( const ICalTimeZoneData &rhs )
626 {
627  // check for self assignment
628  if ( &rhs == this ) {
629  return *this;
630  }
631 
632  KTimeZoneData::operator=( rhs );
633  d->location = rhs.d->location;
634  d->url = rhs.d->url;
635  d->lastModified = rhs.d->lastModified;
636  d->setComponent( icalcomponent_new_clone( rhs.d->component() ) );
637  return *this;
638 }
639 
640 KTimeZoneData *ICalTimeZoneData::clone() const
641 {
642  return new ICalTimeZoneData( *this );
643 }
644 
645 QString ICalTimeZoneData::city() const
646 {
647  return d->location;
648 }
649 
650 QByteArray ICalTimeZoneData::url() const
651 {
652  return d->url;
653 }
654 
655 QDateTime ICalTimeZoneData::lastModified() const
656 {
657  return d->lastModified;
658 }
659 
660 QByteArray ICalTimeZoneData::vtimezone() const
661 {
662  QByteArray result( icalcomponent_as_ical_string( d->component() ) );
663  icalmemory_free_ring();
664  return result;
665 }
666 
667 icaltimezone *ICalTimeZoneData::icalTimezone() const
668 {
669  icaltimezone *icaltz = icaltimezone_new();
670  if ( !icaltz ) {
671  return 0;
672  }
673  icalcomponent *c = icalcomponent_new_clone( d->component() );
674  if ( !icaltimezone_set_component( icaltz, c ) ) {
675  icalcomponent_free( c );
676  icaltimezone_free( icaltz, 1 );
677  return 0;
678  }
679  return icaltz;
680 }
681 
682 bool ICalTimeZoneData::hasTransitions() const
683 {
684  return true;
685 }
686 
687 /******************************************************************************/
688 
689 //@cond PRIVATE
690 class ICalTimeZoneSourcePrivate
691 {
692  public:
693  static QList<QDateTime> parsePhase( icalcomponent *, bool daylight,
694  int &prevOffset, KTimeZone::Phase & );
695  static QByteArray icalTzidPrefix;
696 };
697 
698 QByteArray ICalTimeZoneSourcePrivate::icalTzidPrefix;
699 //@endcond
700 
701 ICalTimeZoneSource::ICalTimeZoneSource()
702  : KTimeZoneSource( false ),
703  d( 0 )
704 {
705 }
706 
707 ICalTimeZoneSource::~ICalTimeZoneSource()
708 {
709 }
710 
711 bool ICalTimeZoneSource::parse( const QString &fileName, ICalTimeZones &zones )
712 {
713  QFile file( fileName );
714  if ( !file.open( QIODevice::ReadOnly ) ) {
715  return false;
716  }
717  QTextStream ts( &file );
718  ts.setCodec( "ISO 8859-1" );
719  QByteArray text = ts.readAll().trimmed().toLatin1();
720  file.close();
721 
722  bool result = false;
723  icalcomponent *calendar = icalcomponent_new_from_string( text.data() );
724  if ( calendar ) {
725  if ( icalcomponent_isa( calendar ) == ICAL_VCALENDAR_COMPONENT ) {
726  result = parse( calendar, zones );
727  }
728  icalcomponent_free( calendar );
729  }
730  return result;
731 }
732 
733 bool ICalTimeZoneSource::parse( icalcomponent *calendar, ICalTimeZones &zones )
734 {
735  for ( icalcomponent *c = icalcomponent_get_first_component( calendar, ICAL_VTIMEZONE_COMPONENT );
736  c; c = icalcomponent_get_next_component( calendar, ICAL_VTIMEZONE_COMPONENT ) ) {
737  ICalTimeZone zone = parse( c );
738  if ( !zone.isValid() ) {
739  return false;
740  }
741  ICalTimeZone oldzone = zones.zone( zone.name() );
742  if ( oldzone.isValid() ) {
743  // The zone already exists in the collection, so update the definition
744  // of the zone rather than using a newly created one.
745  oldzone.update( zone );
746  } else if ( !zones.add( zone ) ) {
747  return false;
748  }
749  }
750  return true;
751 }
752 
753 ICalTimeZone ICalTimeZoneSource::parse( icalcomponent *vtimezone )
754 {
755  QString name;
756  QString xlocation;
757  ICalTimeZoneData *data = new ICalTimeZoneData();
758 
759  // Read the fixed properties which can only appear once in VTIMEZONE
760  icalproperty *p = icalcomponent_get_first_property( vtimezone, ICAL_ANY_PROPERTY );
761  while ( p ) {
762  icalproperty_kind kind = icalproperty_isa( p );
763  switch ( kind ) {
764 
765  case ICAL_TZID_PROPERTY:
766  name = QString::fromUtf8( icalproperty_get_tzid( p ) );
767  break;
768 
769  case ICAL_TZURL_PROPERTY:
770  data->d->url = icalproperty_get_tzurl( p );
771  break;
772 
773  case ICAL_LOCATION_PROPERTY:
774  // This isn't mentioned in RFC2445, but libical reads it ...
775  data->d->location = QString::fromUtf8( icalproperty_get_location( p ) );
776  break;
777 
778  case ICAL_X_PROPERTY:
779  { // use X-LIC-LOCATION if LOCATION is missing
780  const char *xname = icalproperty_get_x_name( p );
781  if ( xname && !strcmp( xname, "X-LIC-LOCATION" ) ) {
782  xlocation = QString::fromUtf8( icalproperty_get_x( p ) );
783  }
784  break;
785  }
786  case ICAL_LASTMODIFIED_PROPERTY:
787  {
788  icaltimetype t = icalproperty_get_lastmodified(p);
789  if ( icaltime_is_utc( t ) ) {
790  data->d->lastModified = toQDateTime( t );
791  } else {
792  kDebug() << "LAST-MODIFIED not UTC";
793  }
794  break;
795  }
796  default:
797  break;
798  }
799  p = icalcomponent_get_next_property( vtimezone, ICAL_ANY_PROPERTY );
800  }
801 
802  if ( name.isEmpty() ) {
803  kDebug() << "TZID missing";
804  delete data;
805  return ICalTimeZone();
806  }
807  if ( data->d->location.isEmpty() && !xlocation.isEmpty() ) {
808  data->d->location = xlocation;
809  }
810  QString prefix = QString::fromUtf8( icalTzidPrefix() );
811  if ( name.startsWith( prefix ) ) {
812  // Remove the prefix from libical built in time zone TZID
813  int i = name.indexOf( '/', prefix.length() );
814  if ( i > 0 ) {
815  name = name.mid( i + 1 );
816  }
817  }
818  //kDebug() << "---zoneId: \"" << name << '"';
819 
820  /*
821  * Iterate through all time zone rules for this VTIMEZONE,
822  * and create a Phase object containing details for each one.
823  */
824  int prevOffset = 0;
825  QList<KTimeZone::Transition> transitions;
826  QDateTime earliest;
827  QList<KTimeZone::Phase> phases;
828  for ( icalcomponent *c = icalcomponent_get_first_component( vtimezone, ICAL_ANY_COMPONENT );
829  c; c = icalcomponent_get_next_component( vtimezone, ICAL_ANY_COMPONENT ) )
830  {
831  int prevoff = 0;
832  KTimeZone::Phase phase;
833  QList<QDateTime> times;
834  icalcomponent_kind kind = icalcomponent_isa( c );
835  switch ( kind ) {
836 
837  case ICAL_XSTANDARD_COMPONENT:
838  //kDebug() << "---standard phase: found";
839  times = ICalTimeZoneSourcePrivate::parsePhase( c, false, prevoff, phase );
840  break;
841 
842  case ICAL_XDAYLIGHT_COMPONENT:
843  //kDebug() << "---daylight phase: found";
844  times = ICalTimeZoneSourcePrivate::parsePhase( c, true, prevoff, phase );
845  break;
846 
847  default:
848  kDebug() << "Unknown component:" << kind;
849  break;
850  }
851  int tcount = times.count();
852  if ( tcount ) {
853  phases += phase;
854  for ( int t = 0; t < tcount; ++t ) {
855  transitions += KTimeZone::Transition( times[t], phase );
856  }
857  if ( !earliest.isValid() || times[0] < earliest ) {
858  prevOffset = prevoff;
859  earliest = times[0];
860  }
861  }
862  }
863  data->setPhases( phases, prevOffset );
864  // Remove any "duplicate" transitions, i.e. those where two consecutive
865  // transitions have the same phase.
866  qSort( transitions );
867  for ( int t = 1, tend = transitions.count(); t < tend; ) {
868  if ( transitions[t].phase() == transitions[t - 1].phase() ) {
869  transitions.removeAt( t );
870  --tend;
871  } else {
872  ++t;
873  }
874  }
875  data->setTransitions( transitions );
876 
877  data->d->setComponent( icalcomponent_new_clone( vtimezone ) );
878  kDebug() << "VTIMEZONE" << name;
879  return ICalTimeZone( this, name, data );
880 }
881 
882 ICalTimeZone ICalTimeZoneSource::parse( icaltimezone *tz )
883 {
884  /* Parse the VTIMEZONE component stored in the icaltimezone structure.
885  * This is both easier and provides more complete information than
886  * extracting already parsed data from icaltimezone.
887  */
888  return tz ? parse( icaltimezone_get_component( tz ) ) : ICalTimeZone();
889 }
890 
891 //@cond PRIVATE
892 QList<QDateTime> ICalTimeZoneSourcePrivate::parsePhase( icalcomponent *c,
893  bool daylight,
894  int &prevOffset,
895  KTimeZone::Phase &phase )
896 {
897  QList<QDateTime> transitions;
898 
899  // Read the observance data for this standard/daylight savings phase
900  QList<QByteArray> abbrevs;
901  QString comment;
902  prevOffset = 0;
903  int utcOffset = 0;
904  bool recurs = false;
905  bool found_dtstart = false;
906  bool found_tzoffsetfrom = false;
907  bool found_tzoffsetto = false;
908  icaltimetype dtstart = icaltime_null_time();
909 
910  // Now do the ical reading.
911  icalproperty *p = icalcomponent_get_first_property( c, ICAL_ANY_PROPERTY );
912  while ( p ) {
913  icalproperty_kind kind = icalproperty_isa( p );
914  switch ( kind ) {
915 
916  case ICAL_TZNAME_PROPERTY: // abbreviated name for this time offset
917  {
918  // TZNAME can appear multiple times in order to provide language
919  // translations of the time zone offset name.
920 
921  // TODO: Does this cope with multiple language specifications?
922  QByteArray tzname = icalproperty_get_tzname( p );
923  // Outlook (2000) places "Standard Time" and "Daylight Time" in the TZNAME
924  // strings, which is totally useless. So ignore those.
925  if ( ( !daylight && tzname == "Standard Time" ) ||
926  ( daylight && tzname == "Daylight Time" ) ) {
927  break;
928  }
929  if ( !abbrevs.contains( tzname ) ) {
930  abbrevs += tzname;
931  }
932  break;
933  }
934  case ICAL_DTSTART_PROPERTY: // local time at which phase starts
935  dtstart = icalproperty_get_dtstart( p );
936  found_dtstart = true;
937  break;
938 
939  case ICAL_TZOFFSETFROM_PROPERTY: // UTC offset immediately before start of phase
940  prevOffset = icalproperty_get_tzoffsetfrom( p );
941  found_tzoffsetfrom = true;
942  break;
943 
944  case ICAL_TZOFFSETTO_PROPERTY:
945  utcOffset = icalproperty_get_tzoffsetto( p );
946  found_tzoffsetto = true;
947  break;
948 
949  case ICAL_COMMENT_PROPERTY:
950  comment = QString::fromUtf8( icalproperty_get_comment( p ) );
951  break;
952 
953  case ICAL_RDATE_PROPERTY:
954  case ICAL_RRULE_PROPERTY:
955  recurs = true;
956  break;
957 
958  default:
959  kDebug() << "Unknown property:" << kind;
960  break;
961  }
962  p = icalcomponent_get_next_property( c, ICAL_ANY_PROPERTY );
963  }
964 
965  // Validate the phase data
966  if ( !found_dtstart || !found_tzoffsetfrom || !found_tzoffsetto ) {
967  kDebug() << "DTSTART/TZOFFSETFROM/TZOFFSETTO missing";
968  return transitions;
969  }
970 
971  // Convert DTSTART to QDateTime, and from local time to UTC
972  QDateTime localStart = toQDateTime( dtstart ); // local time
973  dtstart.second -= prevOffset;
974  dtstart.zone = icaltimezone_get_utc_timezone();
975  QDateTime utcStart = toQDateTime( icaltime_normalize( dtstart ) ); // UTC
976 
977  transitions += utcStart;
978  if ( recurs ) {
979  /* RDATE or RRULE is specified. There should only be one or the other, but
980  * it doesn't really matter - the code can cope with both.
981  * Note that we had to get DTSTART, TZOFFSETFROM, TZOFFSETTO before reading
982  * recurrences.
983  */
984  KDateTime klocalStart( localStart, KDateTime::Spec::ClockTime() );
985  KDateTime maxTime( MAX_DATE(), KDateTime::Spec::ClockTime() );
986  Recurrence recur;
987  icalproperty *p = icalcomponent_get_first_property( c, ICAL_ANY_PROPERTY );
988  while ( p ) {
989  icalproperty_kind kind = icalproperty_isa( p );
990  switch ( kind ) {
991 
992  case ICAL_RDATE_PROPERTY:
993  {
994  icaltimetype t = icalproperty_get_rdate(p).time;
995  if ( icaltime_is_date( t ) ) {
996  // RDATE with a DATE value inherits the (local) time from DTSTART
997  t.hour = dtstart.hour;
998  t.minute = dtstart.minute;
999  t.second = dtstart.second;
1000  t.is_date = 0;
1001  t.zone = 0; // dtstart is in local time
1002  }
1003  // RFC2445 states that RDATE must be in local time,
1004  // but we support UTC as well to be safe.
1005  if ( !icaltime_is_utc( t ) ) {
1006  t.second -= prevOffset; // convert to UTC
1007  t.zone = icaltimezone_get_utc_timezone();
1008  t = icaltime_normalize( t );
1009  }
1010  transitions += toQDateTime( t );
1011  break;
1012  }
1013  case ICAL_RRULE_PROPERTY:
1014  {
1015  RecurrenceRule r;
1016  ICalFormat icf;
1017  ICalFormatImpl impl( &icf );
1018  impl.readRecurrence( icalproperty_get_rrule( p ), &r );
1019  r.setStartDt( klocalStart );
1020  // The end date time specified in an RRULE should be in UTC.
1021  // Convert to local time to avoid timesInInterval() getting things wrong.
1022  if ( r.duration() == 0 ) {
1023  KDateTime end( r.endDt() );
1024  if ( end.timeSpec() == KDateTime::Spec::UTC() ) {
1025  end.setTimeSpec( KDateTime::Spec::ClockTime() );
1026  r.setEndDt( end.addSecs( prevOffset ) );
1027  }
1028  }
1029  DateTimeList dts = r.timesInInterval( klocalStart, maxTime );
1030  for ( int i = 0, end = dts.count(); i < end; ++i ) {
1031  QDateTime utc = dts[i].dateTime();
1032  utc.setTimeSpec( Qt::UTC );
1033  transitions += utc.addSecs( -prevOffset );
1034  }
1035  break;
1036  }
1037  default:
1038  break;
1039  }
1040  p = icalcomponent_get_next_property( c, ICAL_ANY_PROPERTY );
1041  }
1042  qSortUnique( transitions );
1043  }
1044 
1045  phase = KTimeZone::Phase( utcOffset, abbrevs, daylight, comment );
1046  return transitions;
1047 }
1048 //@endcond
1049 
1050 ICalTimeZone ICalTimeZoneSource::standardZone( const QString &zone, bool icalBuiltIn )
1051 {
1052  if ( !icalBuiltIn ) {
1053  // Try to fetch a system time zone in preference, on the grounds
1054  // that system time zones are more likely to be up to date than
1055  // built-in libical ones.
1056  QString tzid = zone;
1057  QString prefix = QString::fromUtf8( icalTzidPrefix() );
1058  if ( zone.startsWith( prefix ) ) {
1059  int i = zone.indexOf( '/', prefix.length() );
1060  if ( i > 0 ) {
1061  tzid = zone.mid( i + 1 ); // strip off the libical prefix
1062  }
1063  }
1064  KTimeZone ktz = KSystemTimeZones::readZone( tzid );
1065  if ( ktz.isValid() ) {
1066  if ( ktz.data( true ) ) {
1067  ICalTimeZone icaltz( ktz );
1068  //kDebug() << zone << " read from system database";
1069  return icaltz;
1070  }
1071  }
1072  }
1073  // Try to fetch a built-in libical time zone.
1074  // First try to look it up as a geographical location (e.g. Europe/London)
1075  QByteArray zoneName = zone.toUtf8();
1076  icaltimezone *icaltz = icaltimezone_get_builtin_timezone( zoneName );
1077  if ( !icaltz ) {
1078  // This will find it if it includes the libical prefix
1079  icaltz = icaltimezone_get_builtin_timezone_from_tzid( zoneName );
1080  if ( !icaltz ) {
1081  return ICalTimeZone();
1082  }
1083  }
1084  return parse( icaltz );
1085 }
1086 
1087 QByteArray ICalTimeZoneSource::icalTzidPrefix()
1088 {
1089  if ( ICalTimeZoneSourcePrivate::icalTzidPrefix.isEmpty() ) {
1090  icaltimezone *icaltz = icaltimezone_get_builtin_timezone( "Europe/London" );
1091  QByteArray tzid = icaltimezone_get_tzid( icaltz );
1092  if ( tzid.right( 13 ) == "Europe/London" ) {
1093  int i = tzid.indexOf( '/', 1 );
1094  if ( i > 0 ) {
1095  ICalTimeZoneSourcePrivate::icalTzidPrefix = tzid.left( i + 1 );
1096  return ICalTimeZoneSourcePrivate::icalTzidPrefix;
1097  }
1098  }
1099  kError() << "failed to get libical TZID prefix";
1100  }
1101  return ICalTimeZoneSourcePrivate::icalTzidPrefix;
1102 }
1103 
1104 } // namespace KCal
KCal::RecurrenceRule::endDt
KDateTime endDt(bool *result=0) const
Returns the date and time of the last recurrence.
Definition: recurrencerule.cpp:937
KCal::ICalTimeZoneData::~ICalTimeZoneData
virtual ~ICalTimeZoneData()
Destructor.
Definition: icaltimezones.cpp:620
KCal::ICalTimeZone::ICalTimeZone
ICalTimeZone()
Constructs a null time zone.
Definition: icaltimezones.cpp:207
KCal::ICalTimeZoneData::vtimezone
QByteArray vtimezone() const
Returns the VTIMEZONE string which represents this time zone.
Definition: icaltimezones.cpp:660
KCal::ICalTimeZoneBackend::ICalTimeZoneBackend
ICalTimeZoneBackend()
Implements ICalTimeZone::ICalTimeZone().
Definition: icaltimezones.cpp:168
KCal::ICalTimeZoneSource::parse
ICalTimeZone parse(icalcomponent *vtimezone)
Creates an ICalTimeZone instance containing the detailed information parsed from a VTIMEZONE componen...
Definition: icaltimezones.cpp:753
KCal::ICalTimeZone::update
bool update(const ICalTimeZone &other)
Update the definition of the time zone to be identical to another ICalTimeZone instance.
Definition: icaltimezones.cpp:267
KCal::ICalTimeZoneData::city
QString city() const
Returns the name of the city for this time zone, if any.
Definition: icaltimezones.cpp:645
KCal::ICalTimeZoneSource::icalTzidPrefix
static QByteArray icalTzidPrefix()
Returns the prefix string used in the TZID field in built-in libical time zones.
Definition: icaltimezones.cpp:1087
KCal::RecurrenceRule::timesInInterval
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...
Definition: recurrencerule.cpp:1717
KCal::ICalTimeZoneSource::ICalTimeZoneSource
ICalTimeZoneSource()
Constructs an iCalendar time zone source.
Definition: icaltimezones.cpp:701
KCal::ICalTimeZones::zone
ICalTimeZone zone(const QString &name) const
Returns the time zone with the given name.
Definition: icaltimezones.cpp:155
icalformat_p.h
This file is part of the API for handling calendar data and defines the internal ICalFormatImpl class...
KCal::ICalTimeZone::~ICalTimeZone
virtual ~ICalTimeZone()
Destructor.
Definition: icaltimezones.cpp:234
KCal::ICalTimeZone::url
QByteArray url() const
Returns the URL of the published VTIMEZONE definition, if any.
Definition: icaltimezones.cpp:243
KCal::ICalFormatImpl
This class provides the libical dependent functions for ICalFormat.
Definition: icalformat_p.h:67
KCal::ICalTimeZoneBackend::hasTransitions
virtual bool hasTransitions(const KTimeZone *caller) const
Implements ICalTimeZone::hasTransitions().
Definition: icaltimezones.cpp:199
KCal::ICalTimeZone::vtimezone
QByteArray vtimezone() const
Returns the VTIMEZONE string which represents this time zone.
Definition: icaltimezones.cpp:255
KCal::ICalTimeZoneData::url
QByteArray url() const
Returns the URL of the published VTIMEZONE definition, if any.
Definition: icaltimezones.cpp:650
KCal::ICalTimeZones::~ICalTimeZones
~ICalTimeZones()
Destructor.
Definition: icaltimezones.cpp:101
KCal::ICalFormat
iCalendar format implementation.
Definition: icalformat.h:52
KCal::ICalTimeZone::icalTimezone
icaltimezone * icalTimezone() const
Returns the ICal timezone structure which represents this time zone.
Definition: icaltimezones.cpp:261
KCal::ICalTimeZones::add
bool add(const ICalTimeZone &zone)
Adds a time zone to the collection.
Definition: icaltimezones.cpp:111
KCal::ICalTimeZones::clear
void clear()
Clears the collection.
Definition: icaltimezones.cpp:150
KCal::ICalTimeZones::ICalTimeZones
ICalTimeZones()
Constructs an empty time zone collection.
Definition: icaltimezones.cpp:96
KCal::ICalTimeZone::city
QString city() const
Returns the name of the city for this time zone, if any.
Definition: icaltimezones.cpp:237
KCal::ICalTimeZoneBackend
Backend class for KICalTimeZone class.
Definition: icaltimezones.h:258
KCal::ICalTimeZoneSource::~ICalTimeZoneSource
virtual ~ICalTimeZoneSource()
Destructor.
Definition: icaltimezones.cpp:707
KCal::RecurrenceRule::duration
int duration() const
Returns -1 if the event recurs infinitely, 0 if the end date is set, otherwise the total number of re...
Definition: recurrencerule.cpp:2124
KCal::ICalTimeZoneData::hasTransitions
virtual bool hasTransitions() const
Return whether daylight saving transitions are available for the time zone.
Definition: icaltimezones.cpp:682
KCal::ICalTimeZones
The ICalTimeZones class represents a time zone database which consists of a collection of individual ...
Definition: icaltimezones.h:64
KCal::ICalTimeZones::remove
ICalTimeZone remove(const ICalTimeZone &zone)
Removes a time zone from the collection.
Definition: icaltimezones.cpp:124
KCal::ICalTimeZoneData::lastModified
QDateTime lastModified() const
Returns the LAST-MODIFIED time of the VTIMEZONE, if any.
Definition: icaltimezones.cpp:655
KCal
Definition: alarm.h:52
KCal::ICalTimeZoneData::ICalTimeZoneData
ICalTimeZoneData()
Default constructor.
Definition: icaltimezones.cpp:317
KCal::SortableList
A QList which can be sorted.
Definition: sortablelist.h:86
KCal::ICalTimeZoneData::icalTimezone
icaltimezone * icalTimezone() const
Returns the ICal timezone structure which represents this time zone.
Definition: icaltimezones.cpp:667
KCal::ICalTimeZoneSource
A class which reads and parses iCalendar VTIMEZONE components, and accesses libical time zone data...
Definition: icaltimezones.h:328
KCal::ICalTimeZoneData::operator=
ICalTimeZoneData & operator=(const ICalTimeZoneData &rhs)
Assignment operator.
Definition: icaltimezones.cpp:625
KCal::ICalTimeZoneData::clone
virtual KTimeZoneData * clone() const
Creates a new copy of this object.
Definition: icaltimezones.cpp:640
KCal::ICalTimeZoneData
Parsed iCalendar VTIMEZONE data.
Definition: icaltimezones.h:434
KCal::ICalTimeZones::zones
const ZoneMap zones() const
Returns all the time zones defined in this collection.
Definition: icaltimezones.cpp:106
KCal::ICalTimeZoneBackend::clone
virtual KTimeZoneBackend * clone() const
Creates a copy of this instance.
Definition: icaltimezones.cpp:189
KCal::RecurrenceRule::setEndDt
void setEndDt(const KDateTime &endDateTime)
Sets the date and time of the last recurrence.
Definition: recurrencerule.cpp:968
KCal::ICalTimeZone::utc
static ICalTimeZone utc()
Returns a standard UTC time zone, with name "UTC".
Definition: icaltimezones.cpp:278
KCal::ICalTimeZoneBackend::type
virtual QByteArray type() const
Returns the class name of the data represented by this instance.
Definition: icaltimezones.cpp:194
KCal::ICalTimeZone::lastModified
QDateTime lastModified() const
Returns the LAST-MODIFIED time of the VTIMEZONE, if any.
Definition: icaltimezones.cpp:249
icalformat.h
This file is part of the API for handling calendar data and defines the ICalFormat class...
KCal::Recurrence
This class represents a recurrence rule for a calendar incidence.
Definition: recurrence.h:91
KCal::ICalTimeZoneSource::standardZone
ICalTimeZone standardZone(const QString &zone, bool icalBuiltIn=false)
Creates an ICalTimeZone instance for a standard time zone.
Definition: icaltimezones.cpp:1050
KCal::ICalTimeZone
The ICalTimeZone class represents an iCalendar VTIMEZONE component.
Definition: icaltimezones.h:142
KCal::RecurrenceRule::setStartDt
void setStartDt(const KDateTime &start)
Sets the recurrence start date/time.
Definition: recurrencerule.cpp:1006
KCal::RecurrenceRule
This class represents a recurrence rule for a calendar incidence.
Definition: recurrencerule.h:46
This file is part of the KDE documentation.
Documentation copyright © 1996-2018 The KDE developers.
Generated on Fri Oct 19 2018 17:57:41 by doxygen 1.8.13 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KCal Library

Skip menu "KCal Library"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdepimlibs-4.14.3 API Reference

Skip menu "kdepimlibs-4.14.3 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal