KDELibs4Support

ktimezone.cpp
1 /*
2  This file is part of the KDE libraries
3  Copyright (c) 2005-2008,2011 David Jarvie <[email protected]>
4  Copyright (c) 2005 S.R.Haque <[email protected]>.
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 "ktimezone.h"
23 
24 #include <config-date.h> // SIZEOF_TIME_T
25 
26 #if HAVE_SYS_TIME_H
27 #include <sys/time.h>
28 #endif
29 #if HAVE_TIME_H
30 #include <time.h>
31 #endif
32 #include <climits>
33 #include <cstdlib>
34 
35 #include <QDebug>
36 #include <QSet>
37 #include <QSharedData>
38 #include <QCoreApplication>
39 
40 int gmtoff(time_t t); // defined in ksystemtimezone.cpp
41 
42 /******************************************************************************/
43 
44 class KTimeZonesPrivate
45 {
46 public:
47  KTimeZonesPrivate() {}
48 
49  KTimeZones::ZoneMap zones;
50 };
51 
52 KTimeZones::KTimeZones()
53  : d(new KTimeZonesPrivate)
54 {
55 }
56 
57 KTimeZones::~KTimeZones()
58 {
59  delete d;
60 }
61 
63 {
64  return d->zones;
65 }
66 
67 bool KTimeZones::add(const KTimeZone &zone)
68 {
69  if (!zone.isValid()) {
70  return false;
71  }
72  if (d->zones.find(zone.name()) != d->zones.end()) {
73  return false; // name already exists
74  }
75  d->zones.insert(zone.name(), zone);
76  return true;
77 }
78 
80 {
81  if (zone.isValid()) {
82  for (ZoneMap::Iterator it = d->zones.begin(), end = d->zones.end(); it != end; ++it) {
83  if (it.value() == zone) {
84  d->zones.erase(it);
85  return zone;
86  }
87  }
88  }
89  return KTimeZone();
90 }
91 
93 {
94  if (!name.isEmpty()) {
95  ZoneMap::Iterator it = d->zones.find(name);
96  if (it != d->zones.end()) {
97  KTimeZone zone = it.value();
98  d->zones.erase(it);
99  return zone;
100  }
101  }
102  return KTimeZone();
103 }
104 
106 {
107  d->zones.clear();
108 }
109 
111 {
112  if (!name.isEmpty()) {
113  ZoneMap::ConstIterator it = d->zones.constFind(name);
114  if (it != d->zones.constEnd()) {
115  return it.value();
116  }
117  if (name == KTimeZone::utc().name()) {
118  return KTimeZone::utc();
119  }
120  }
121  return KTimeZone(); // error
122 }
123 
124 /******************************************************************************/
125 
126 class KTimeZonePhasePrivate : public QSharedData
127 {
128 public:
129  QByteArray abbreviations; // time zone abbreviations (zero-delimited)
130  QString comment; // optional comment
131  int utcOffset; // seconds to add to UTC
132  bool dst; // true if daylight savings time
133 
134  KDELIBS4SUPPORT_DEPRECATED explicit KTimeZonePhasePrivate(int offset = 0, bool ds = false)
135  : QSharedData(),
136  utcOffset(offset),
137  dst(ds)
138  {}
139  KTimeZonePhasePrivate(const KTimeZonePhasePrivate &rhs)
140  : QSharedData(rhs),
141  abbreviations(rhs.abbreviations),
142  comment(rhs.comment),
143  utcOffset(rhs.utcOffset),
144  dst(rhs.dst)
145  {}
146  bool operator==(const KTimeZonePhasePrivate &rhs) const
147  {
148  return abbreviations == rhs.abbreviations
149  && comment == rhs.comment
150  && utcOffset == rhs.utcOffset
151  && dst == rhs.dst;
152  }
153 };
154 
155 KTimeZone::Phase::Phase()
156  : d(new KTimeZonePhasePrivate)
157 {
158 }
159 
160 KTimeZone::Phase::Phase(int utcOffset, const QByteArray &abbrevs,
161  bool dst, const QString &cmt)
162  : d(new KTimeZonePhasePrivate(utcOffset, dst))
163 {
164  d->abbreviations = abbrevs;
165  d->comment = cmt;
166 }
167 
168 KTimeZone::Phase::Phase(int utcOffset, const QList<QByteArray> &abbrevs,
169  bool dst, const QString &cmt)
170  : d(new KTimeZonePhasePrivate(utcOffset, dst))
171 {
172  for (int i = 0, end = abbrevs.count(); i < end; ++i) {
173  if (i > 0) {
174  d->abbreviations += '\0';
175  }
176  d->abbreviations += abbrevs[i];
177  }
178  d->comment = cmt;
179 }
180 
181 KTimeZone::Phase::Phase(const KTimeZone::Phase &rhs)
182  : d(rhs.d)
183 {
184 }
185 
186 KTimeZone::Phase::~Phase()
187 {
188 }
189 
190 KTimeZone::Phase &KTimeZone::Phase::operator=(const KTimeZone::Phase &rhs)
191 {
192  d = rhs.d;
193  return *this;
194 }
195 
196 bool KTimeZone::Phase::operator==(const KTimeZone::Phase &rhs) const
197 {
198  return d == rhs.d || *d == *rhs.d;
199 }
200 
201 int KTimeZone::Phase::utcOffset() const
202 {
203  return d->utcOffset;
204 }
205 
206 QList<QByteArray> KTimeZone::Phase::abbreviations() const
207 {
208  return d->abbreviations.split('\0');
209 }
210 
211 bool KTimeZone::Phase::isDst() const
212 {
213  return d->dst;
214 }
215 
216 QString KTimeZone::Phase::comment() const
217 {
218  return d->comment;
219 }
220 
221 /******************************************************************************/
222 
223 class KTimeZoneTransitionPrivate
224 {
225 public:
226  QDateTime time;
227  KTimeZone::Phase phase;
228 };
229 
230 KTimeZone::Transition::Transition()
231  : d(new KTimeZoneTransitionPrivate)
232 {
233 }
234 
235 KTimeZone::Transition::Transition(const QDateTime &t, const KTimeZone::Phase &p)
236  : d(new KTimeZoneTransitionPrivate)
237 {
238  d->time = t;
239  d->phase = p;
240 }
241 
242 KTimeZone::Transition::Transition(const KTimeZone::Transition &t)
243  : d(new KTimeZoneTransitionPrivate)
244 {
245  d->time = t.d->time;
246  d->phase = t.d->phase;
247 }
248 
249 KTimeZone::Transition::~Transition()
250 {
251  delete d;
252 }
253 
254 KTimeZone::Transition &KTimeZone::Transition::operator=(const KTimeZone::Transition &t)
255 {
256  d->time = t.d->time;
257  d->phase = t.d->phase;
258  return *this;
259 }
260 
261 bool KTimeZone::Transition::operator<(const KTimeZone::Transition &rhs) const
262 {
263  return d->time < rhs.d->time;
264 }
265 
266 QDateTime KTimeZone::Transition::time() const
267 {
268  return d->time;
269 }
270 KTimeZone::Phase KTimeZone::Transition::phase() const
271 {
272  return d->phase;
273 }
274 
275 /******************************************************************************/
276 
277 class KTimeZoneDataPrivate
278 {
279 public:
281  QList<KTimeZone::Transition> transitions;
282  QList<KTimeZone::LeapSeconds> leapChanges;
283  QList<int> utcOffsets;
284  QList<QByteArray> abbreviations;
285  KTimeZone::Phase prePhase; // phase to use before the first transition
286 
287  KTimeZoneDataPrivate() {}
288  // Find the last transition before a specified UTC or local date/time.
289  int transitionIndex(const QDateTime &dt) const;
290  bool transitionIndexes(const QDateTime &start, const QDateTime &end, int &ixstart, int &ixend) const;
291  bool isSecondOccurrence(const QDateTime &utcLocalTime, int transitionIndex) const;
292 };
293 
294 /******************************************************************************/
295 
296 class KTimeZonePrivate : public QSharedData
297 {
298 public:
299  KTimeZonePrivate() : source(nullptr), data(nullptr), refCount(1), cachedTransitionIndex(-1) {}
300  KTimeZonePrivate(KTimeZoneSource *src, const QString &nam,
301  const QString &country, float lat, float lon, const QString &cmnt);
302  KTimeZonePrivate(const KTimeZonePrivate &);
303  ~KTimeZonePrivate()
304  {
305  delete data;
306  }
307  KTimeZonePrivate &operator=(const KTimeZonePrivate &);
308  static KTimeZoneSource *utcSource();
309  static void cleanup();
310 
312  QString name;
313  QString countryCode;
314  QString comment;
315  float latitude;
316  float longitude;
317  mutable KTimeZoneData *data;
318  int refCount; // holds the number of KTimeZoneBackend instances using the KTimeZonePrivate instance as a d-pointer.
319  int cachedTransitionIndex;
320  QDateTime cachedTransitionStartZoneTime;
321  QDateTime cachedTransitionEndZoneTime;
322  bool cachedTransitionTimesValid;
323 
324 private:
325  static KTimeZoneSource *mUtcSource;
326 };
327 
328 KTimeZoneSource *KTimeZonePrivate::mUtcSource = nullptr;
329 
330 KTimeZonePrivate::KTimeZonePrivate(KTimeZoneSource *src, const QString &nam,
331  const QString &country, float lat, float lon, const QString &cmnt)
332  : source(src),
333  name(nam),
334  countryCode(country.toUpper()),
335  comment(cmnt),
336  latitude(lat),
337  longitude(lon),
338  data(nullptr),
339  refCount(1),
340  cachedTransitionIndex(-1)
341 {
342  // Detect duff values.
343  if (latitude > 90 || latitude < -90) {
344  latitude = KTimeZone::UNKNOWN;
345  }
346  if (longitude > 180 || longitude < -180) {
347  longitude = KTimeZone::UNKNOWN;
348  }
349 }
350 
351 KTimeZonePrivate::KTimeZonePrivate(const KTimeZonePrivate &rhs)
352  : QSharedData(rhs),
353  source(rhs.source),
354  name(rhs.name),
355  countryCode(rhs.countryCode),
356  comment(rhs.comment),
357  latitude(rhs.latitude),
358  longitude(rhs.longitude),
359  refCount(1),
360  cachedTransitionIndex(rhs.cachedTransitionIndex),
361  cachedTransitionStartZoneTime(rhs.cachedTransitionStartZoneTime),
362  cachedTransitionEndZoneTime(rhs.cachedTransitionEndZoneTime),
363  cachedTransitionTimesValid(rhs.cachedTransitionTimesValid)
364 {
365  if (rhs.data) {
366  data = rhs.data->clone();
367  } else {
368  data = nullptr;
369  }
370 }
371 
372 KTimeZonePrivate &KTimeZonePrivate::operator=(const KTimeZonePrivate &rhs)
373 {
374  // Changing the contents of a KTimeZonePrivate instance by means of operator=() doesn't affect how
375  // many references to it are held.
376  source = rhs.source;
377  name = rhs.name;
378  countryCode = rhs.countryCode;
379  comment = rhs.comment;
380  latitude = rhs.latitude;
381  longitude = rhs.longitude;
382  cachedTransitionIndex = rhs.cachedTransitionIndex;
383  cachedTransitionStartZoneTime = rhs.cachedTransitionStartZoneTime;
384  cachedTransitionEndZoneTime = rhs.cachedTransitionEndZoneTime;
385  cachedTransitionTimesValid = rhs.cachedTransitionTimesValid;
386  delete data;
387  if (rhs.data) {
388  data = rhs.data->clone();
389  } else {
390  data = nullptr;
391  }
392  // refCount is unchanged
393  return *this;
394 }
395 
396 KTimeZoneSource *KTimeZonePrivate::utcSource()
397 {
398  if (!mUtcSource) {
399  mUtcSource = new KTimeZoneSource;
400  qAddPostRoutine(KTimeZonePrivate::cleanup);
401  }
402  return mUtcSource;
403 }
404 
405 void KTimeZonePrivate::cleanup()
406 {
407  delete mUtcSource;
408 }
409 
410 /******************************************************************************/
411 
412 Q_GLOBAL_STATIC(KTimeZonePrivate, s_emptyTimeZonePrivate)
413 
415  : d(s_emptyTimeZonePrivate())
416 {
417  ++d->refCount;
418 }
419 
421  : d(new KTimeZonePrivate(KTimeZonePrivate::utcSource(), name, QString(), KTimeZone::UNKNOWN, KTimeZone::UNKNOWN, QString()))
422 {}
423 
425  const QString &countryCode, float latitude, float longitude, const QString &comment)
426  : d(new KTimeZonePrivate(source, name, countryCode, latitude, longitude, comment))
427 {}
428 
430  : d(other.d)
431 {
432  ++d->refCount;
433 }
434 
435 KTimeZoneBackend::~KTimeZoneBackend()
436 {
437  if (d && --d->refCount == 0) {
438  delete d;
439  }
440  d = nullptr;
441 }
442 
443 KTimeZoneBackend &KTimeZoneBackend::operator=(const KTimeZoneBackend &other)
444 {
445  if (d != other.d) {
446  if (--d->refCount == 0) {
447  delete d;
448  }
449  d = other.d;
450  ++d->refCount;
451  }
452  return *this;
453 }
454 
456 {
457  return "KTimeZone";
458 }
459 
461 {
462  return new KTimeZoneBackend(*this);
463 }
464 
465 int KTimeZoneBackend::offsetAtZoneTime(const KTimeZone *caller, const QDateTime &zoneDateTime, int *secondOffset) const
466 {
467  if (!zoneDateTime.isValid() || zoneDateTime.timeSpec() != Qt::LocalTime) { // check for invalid time
468  if (secondOffset) {
469  *secondOffset = KTimeZone::InvalidOffset;
470  }
472  }
473  const QList<KTimeZone::Transition> transitions = caller->transitions();
474  int index = d->cachedTransitionIndex;
475  if (index >= 0 && index < transitions.count()) {
476  // There is a cached transition - check whether zoneDateTime uses it.
477  // Caching is used because this method has been found to consume
478  // significant CPU in real life applications.
479  if (!d->cachedTransitionTimesValid) {
480  const int offset = transitions[index].phase().utcOffset();
481  const int preoffset = (index > 0) ? transitions[index - 1].phase().utcOffset() : d->data ? d->data->previousUtcOffset() : KTimeZone::InvalidOffset;
482  d->cachedTransitionStartZoneTime = transitions[index].time().addSecs(qMax(offset, preoffset));
483  if (index + 1 < transitions.count()) {
484  const int postoffset = transitions[index + 1].phase().utcOffset();
485  d->cachedTransitionEndZoneTime = transitions[index + 1].time().addSecs(qMin(offset, postoffset));
486  }
487  d->cachedTransitionTimesValid = true;
488  }
489  QDateTime dtutc = zoneDateTime;
490  dtutc.setTimeSpec(Qt::UTC);
491  if (dtutc >= d->cachedTransitionStartZoneTime
492  && (index + 1 >= transitions.count() || dtutc < d->cachedTransitionEndZoneTime)) {
493  // The time falls within the cached transition limits, so return its UTC offset
494  const int offset = transitions[index].phase().utcOffset();
495  if (secondOffset) {
496  *secondOffset = offset;
497  }
498 #ifdef COMPILING_TESTS
499  // qDebug() << "-> Using cache"; // enable the debug area to see this in the tests
500 #endif
501  return offset;
502  }
503  }
504 
505  // The time doesn't fall within the cached transition, or there isn't a cached transition
506 #ifdef COMPILING_TESTS
507  // qDebug() << "-> No cache"; // enable the debug area to see this in the tests
508 #endif
509  bool validTime;
510  int secondIndex = -1;
511  index = caller->transitionIndex(zoneDateTime, (secondOffset ? &secondIndex : nullptr), &validTime);
512  const KTimeZone::Transition *tr = (index >= 0) ? &transitions[index] : nullptr;
513  const int offset = tr ? tr->phase().utcOffset()
514  : validTime ? (d->data ? d->data->previousUtcOffset() : KTimeZone::InvalidOffset)
516  if (secondOffset) {
517  *secondOffset = (secondIndex >= 0) ? transitions.at(secondIndex).phase().utcOffset() : offset;
518  }
519 
520  // Cache transition data for subsequent date/time values which occur after the same transition.
521  d->cachedTransitionIndex = index;
522  d->cachedTransitionTimesValid = false;
523  return offset;
524 }
525 
526 int KTimeZoneBackend::offsetAtUtc(const KTimeZone *caller, const QDateTime &utcDateTime) const
527 {
528  if (!utcDateTime.isValid() || utcDateTime.timeSpec() != Qt::UTC) { // check for invalid time
529  return 0;
530  }
531  const QList<KTimeZone::Transition> transitions = caller->transitions();
532  int index = d->cachedTransitionIndex;
533  if (index >= 0 && index < transitions.count()) {
534  // There is a cached transition - check whether utcDateTime uses it.
535  if (utcDateTime >= transitions[index].time()
536  && (index + 1 >= transitions.count()
537  || utcDateTime < transitions[index + 1].time())) {
538  // The time falls within the cached transition, so return its UTC offset
539 #ifdef COMPILING_TESTS
540  // qDebug() << "Using cache"; // enable the debug area to see this in the tests
541 #endif
542  return transitions[index].phase().utcOffset();
543  }
544  }
545 
546  // The time doesn't fall within the cached transition, or there isn't a cached transition
547 #ifdef COMPILING_TESTS
548  // qDebug() << "No cache"; // enable the debug area to see this in the tests
549 #endif
550  index = caller->transitionIndex(utcDateTime);
551  d->cachedTransitionIndex = index; // cache transition data
552  d->cachedTransitionTimesValid = false;
553  const KTimeZone::Transition *tr = (index >= 0) ? &transitions.at(index) : nullptr;
554  return tr ? tr->phase().utcOffset() : (d->data ? d->data->previousUtcOffset() : KTimeZone::InvalidOffset);
555 }
556 
557 int KTimeZoneBackend::offset(const KTimeZone *caller, time_t t) const
558 {
559  return offsetAtUtc(caller, KTimeZone::fromTime_t(t));
560 }
561 
562 bool KTimeZoneBackend::isDstAtUtc(const KTimeZone *caller, const QDateTime &utcDateTime) const
563 {
564  if (!utcDateTime.isValid() || utcDateTime.timeSpec() != Qt::UTC) { // check for invalid time
565  return false;
566  }
567  const KTimeZone::Transition *tr = caller->transition(utcDateTime);
568  if (!tr) {
569  return false;
570  }
571  return tr->phase().isDst();
572 }
573 
574 bool KTimeZoneBackend::isDst(const KTimeZone *caller, time_t t) const
575 {
576  return isDstAtUtc(caller, KTimeZone::fromTime_t(t));
577 }
578 
580 {
581  Q_UNUSED(caller);
582  return false;
583 }
584 
585 /******************************************************************************/
586 
587 #if SIZEOF_TIME_T == 8
588 const time_t KTimeZone::InvalidTime_t = 0x800000000000000LL;
589 #else
590 const time_t KTimeZone::InvalidTime_t = 0x80000000;
591 #endif
592 const int KTimeZone::InvalidOffset = 0x80000000;
593 const float KTimeZone::UNKNOWN = 1000.0;
594 
596  : d(new KTimeZoneBackend())
597 {}
598 
600  : d(new KTimeZoneBackend(name))
601 {}
602 
604  : d(tz.d->clone())
605 {}
606 
607 KTimeZone::~KTimeZone()
608 {
609  delete d;
610 }
611 
613  : d(impl)
614 {
615  // 'impl' should be a newly constructed object, with refCount = 1
616  Q_ASSERT(d->d->refCount == 1 || d->d == s_emptyTimeZonePrivate());
617 }
618 
619 KTimeZone &KTimeZone::operator=(const KTimeZone &tz)
620 {
621  if (d != tz.d) {
622  delete d;
623  d = tz.d->clone();
624  }
625  return *this;
626 }
627 
628 bool KTimeZone::operator==(const KTimeZone &rhs) const
629 {
630  return d->d == rhs.d->d;
631 }
632 
634 {
635  return d->type();
636 }
637 
638 bool KTimeZone::isValid() const
639 {
640  return !d->d->name.isEmpty();
641 }
642 
644 {
645  return d->d->countryCode;
646 }
647 
648 float KTimeZone::latitude() const
649 {
650  return d->d->latitude;
651 }
652 
653 float KTimeZone::longitude() const
654 {
655  return d->d->longitude;
656 }
657 
659 {
660  return d->d->comment;
661 }
662 
664 {
665  return d->d->name;
666 }
667 
669 {
670  if (!data(true)) {
671  return QList<QByteArray>();
672  }
673  return d->d->data->abbreviations();
674 }
675 
677 {
678  if (utcDateTime.timeSpec() != Qt::UTC || !data(true)) {
679  return QByteArray();
680  }
681  return d->d->data->abbreviation(utcDateTime);
682 }
683 
685 {
686  if (!data(true)) {
687  return QList<int>();
688  }
689  return d->d->data->utcOffsets();
690 }
691 
693 {
694  if (!data(true)) {
695  return QList<KTimeZone::Phase>();
696  }
697  return d->d->data->phases();
698 }
699 
701 {
702  return d->hasTransitions(this);
703 }
704 
706 {
707  if (!data(true)) {
709  }
710  return d->d->data->transitions(start, end);
711 }
712 
713 const KTimeZone::Transition *KTimeZone::transition(const QDateTime &dt, const Transition **secondTransition,
714  bool *validTime) const
715 {
716  if (!data(true)) {
717  if (validTime) {
718  *validTime = false;
719  }
720  return nullptr;
721  }
722  return d->d->data->transition(dt, secondTransition, validTime);
723 }
724 
725 int KTimeZone::transitionIndex(const QDateTime &dt, int *secondIndex, bool *validTime) const
726 {
727  if (!data(true)) {
728  if (validTime) {
729  *validTime = false;
730  }
731  return -1;
732  }
733  return d->d->data->transitionIndex(dt, secondIndex, validTime);
734 }
735 
736 QList<QDateTime> KTimeZone::transitionTimes(const Phase &phase, const QDateTime &start, const QDateTime &end) const
737 {
738  if (!data(true)) {
739  return QList<QDateTime>();
740  }
741  return d->d->data->transitionTimes(phase, start, end);
742 }
743 
745 {
746  if (!data(true)) {
748  }
749  return d->d->data->leapSecondChanges();
750 }
751 
753 {
754  return d->d->source;
755 }
756 
757 const KTimeZoneData *KTimeZone::data(bool create) const
758 {
759  if (!isValid()) {
760  return nullptr;
761  }
762  if (create && !d->d->data && d->d->source->useZoneParse()) {
763  d->d->data = d->d->source->parse(*this);
764  }
765  return d->d->data;
766 }
767 
769 {
770  if (!isValid()) {
771  return;
772  }
773  delete d->d->data;
774  d->d->data = data;
775  if (source) {
776  d->d->source = source;
777  }
778 }
779 
781 {
782  if (d->d->name.isEmpty() || d->d->name != other.d->d->name) {
783  return false;
784  }
785  d->d->countryCode = other.d->d->countryCode;
786  d->d->comment = other.d->d->comment;
787  d->d->latitude = other.d->d->latitude;
788  d->d->longitude = other.d->d->longitude;
789  return true;
790 }
791 
792 bool KTimeZone::parse() const
793 {
794  if (!isValid()) {
795  return false;
796  }
797  if (d->d->source->useZoneParse()) {
798  delete d->d->data;
799  d->d->data = d->d->source->parse(*this);
800  }
801  return d->d->data;
802 }
803 
804 QDateTime KTimeZone::toUtc(const QDateTime &zoneDateTime) const
805 {
806  if (!zoneDateTime.isValid() || zoneDateTime.timeSpec() != Qt::LocalTime) {
807  return QDateTime();
808  }
809  const int secs = offsetAtZoneTime(zoneDateTime);
810  if (secs == InvalidOffset) {
811  return QDateTime();
812  }
813  QDateTime dt = zoneDateTime;
814  dt.setTimeSpec(Qt::UTC);
815  return dt.addSecs(-secs);
816 }
817 
818 QDateTime KTimeZone::toZoneTime(const QDateTime &utcDateTime, bool *secondOccurrence) const
819 {
820  if (secondOccurrence) {
821  *secondOccurrence = false;
822  }
823  if (!utcDateTime.isValid() || utcDateTime.timeSpec() != Qt::UTC) { // check for invalid time
824  return QDateTime();
825  }
826 
827  // Convert UTC to local time
828  if (hasTransitions()) {
829  if (!data(true)) {
830  // No data - default to UTC
831  QDateTime dt = utcDateTime;
833  return dt;
834  }
835 
836  const KTimeZoneData *data = d->d->data;
837  const int index = data->transitionIndex(utcDateTime);
838  const int secs = (index >= 0) ? data->transitions().at(index).phase().utcOffset() : data->previousUtcOffset();
839  QDateTime dt = utcDateTime.addSecs(secs);
840  if (secondOccurrence) {
841  // Check whether the local time occurs twice around a daylight savings time
842  // shift, and if so, whether it's the first or second occurrence.
843  *secondOccurrence = data->d->isSecondOccurrence(dt, index);
844  }
846  return dt;
847  } else {
848  const int secs = offsetAtUtc(utcDateTime);
849  QDateTime dt = utcDateTime.addSecs(secs);
851  if (secondOccurrence) {
852  // Check whether the local time occurs twice around a daylight savings time
853  // shift, and if so, whether it's the first or second occurrence.
854  *secondOccurrence = (secs != offsetAtZoneTime(dt));
855  }
856  return dt;
857  }
858 }
859 
860 QDateTime KTimeZone::convert(const KTimeZone &newZone, const QDateTime &zoneDateTime) const
861 {
862  if (newZone == *this) {
863  if (zoneDateTime.timeSpec() != Qt::LocalTime) {
864  return QDateTime();
865  }
866  return zoneDateTime;
867  }
868  return newZone.toZoneTime(toUtc(zoneDateTime));
869 }
870 
871 int KTimeZone::offsetAtZoneTime(const QDateTime &zoneDateTime, int *secondOffset) const
872 {
873  return d->offsetAtZoneTime(this, zoneDateTime, secondOffset);
874 }
875 
876 int KTimeZone::offsetAtUtc(const QDateTime &utcDateTime) const
877 {
878  return d->offsetAtUtc(this, utcDateTime);
879 }
880 
881 int KTimeZone::offset(time_t t) const
882 {
883  return d->offset(this, t);
884 }
885 
887 {
888  // Get current offset of this time zone to UTC
889  const time_t now = time(nullptr);
890  const int secs = offset(now);
891 
892  switch (basis) {
893  case Qt::LocalTime:
894  // Return the current offset of this time zone to the local system time
895  return secs - gmtoff(now);
896  case Qt::UTC:
897  // Return the current offset of this time zone to UTC
898  return secs;
899 
900  default:
901  break;
902  }
903  return 0;
904 }
905 
906 bool KTimeZone::isDstAtUtc(const QDateTime &utcDateTime) const
907 {
908  return d->isDstAtUtc(this, utcDateTime);
909 }
910 
911 bool KTimeZone::isDst(time_t t) const
912 {
913  return d->isDst(this, t);
914 }
915 
917 {
918  static KTimeZone utcZone(QLatin1String("UTC"));
919  return utcZone;
920 }
921 
923 {
924  static const int secondsADay = 86400;
925  static const QDate epochDate(1970, 1, 1);
926  static const QTime epochTime(0, 0, 0);
927  int days = t / secondsADay;
928  int secs;
929  if (t >= 0) {
930  secs = t % secondsADay;
931  } else {
932  secs = secondsADay - (-t % secondsADay);
933  --days;
934  }
935  return QDateTime(epochDate.addDays(days), epochTime.addSecs(secs), Qt::UTC);
936 }
937 
938 time_t KTimeZone::toTime_t(const QDateTime &utcDateTime)
939 {
940  static const QDate epochDate(1970, 1, 1);
941  static const QTime epochTime(0, 0, 0);
942  if (utcDateTime.timeSpec() != Qt::UTC) {
943  return InvalidTime_t;
944  }
945  const qint64 days = epochDate.daysTo(utcDateTime.date());
946  const qint64 secs = epochTime.secsTo(utcDateTime.time());
947  const qint64 t64 = days * 86400 + secs;
948  const time_t t = static_cast<time_t>(t64);
949  if (static_cast<qint64>(t) != t64) {
950  return InvalidTime_t;
951  }
952  return t;
953 }
954 
955 /******************************************************************************/
956 
957 class KTimeZoneSourcePrivate
958 {
959 public:
960  bool mUseZoneParse;
961 };
962 
963 KTimeZoneSource::KTimeZoneSource()
964  : d(new KTimeZoneSourcePrivate)
965 {
966  d->mUseZoneParse = true;
967 }
968 
969 KTimeZoneSource::KTimeZoneSource(bool useZoneParse)
970  : d(new KTimeZoneSourcePrivate)
971 {
972  d->mUseZoneParse = useZoneParse;
973 }
974 
975 KTimeZoneSource::~KTimeZoneSource()
976 {
977  delete d;
978 }
979 
981 {
982  Q_ASSERT(d->mUseZoneParse); // method should never be called if it isn't usable
983  return new KTimeZoneData;
984 }
985 
987 {
988  return d->mUseZoneParse;
989 }
990 
991 /******************************************************************************/
992 
993 class KTimeZoneLeapSecondsPrivate
994 {
995 public:
996  QDateTime dt; // UTC time when this change occurred
997  QString comment; // optional comment
998  int seconds; // number of leap seconds
999 };
1000 
1001 KTimeZone::LeapSeconds::LeapSeconds()
1002  : d(new KTimeZoneLeapSecondsPrivate)
1003 {
1004 }
1005 
1006 KTimeZone::LeapSeconds::LeapSeconds(const QDateTime &utc, int leap, const QString &cmt)
1007  : d(new KTimeZoneLeapSecondsPrivate)
1008 {
1009  if (utc.timeSpec() == Qt::UTC) { // invalid if start time is not UTC
1010  d->dt = utc;
1011  d->comment = cmt;
1012  d->seconds = leap;
1013  }
1014 }
1015 
1016 KTimeZone::LeapSeconds::LeapSeconds(const KTimeZone::LeapSeconds &c)
1017  : d(new KTimeZoneLeapSecondsPrivate)
1018 {
1019  d->dt = c.d->dt;
1020  d->comment = c.d->comment;
1021  d->seconds = c.d->seconds;
1022 }
1023 
1024 KTimeZone::LeapSeconds::~LeapSeconds()
1025 {
1026  delete d;
1027 }
1028 
1029 KTimeZone::LeapSeconds &KTimeZone::LeapSeconds::operator=(const KTimeZone::LeapSeconds &c)
1030 {
1031  d->dt = c.d->dt;
1032  d->comment = c.d->comment;
1033  d->seconds = c.d->seconds;
1034  return *this;
1035 }
1036 
1037 bool KTimeZone::LeapSeconds::operator<(const KTimeZone::LeapSeconds &c) const
1038 {
1039  return d->dt < c.d->dt;
1040 }
1041 
1042 QDateTime KTimeZone::LeapSeconds::dateTime() const
1043 {
1044  return d->dt;
1045 }
1046 
1047 bool KTimeZone::LeapSeconds::isValid() const
1048 {
1049  return d->dt.isValid();
1050 }
1051 
1052 int KTimeZone::LeapSeconds::leapSeconds() const
1053 {
1054  return d->seconds;
1055 }
1056 
1057 QString KTimeZone::LeapSeconds::comment() const
1058 {
1059  return d->comment;
1060 }
1061 
1062 /******************************************************************************/
1063 
1064 int KTimeZoneDataPrivate::transitionIndex(const QDateTime &dt) const
1065 {
1066  // Do a binary search to find the last transition before this date/time
1067  int start = -1;
1068  int end = transitions.count();
1069  if (dt.timeSpec() == Qt::UTC) {
1070  while (end - start > 1) {
1071  int i = (start + end) / 2;
1072  if (dt < transitions[i].time()) {
1073  end = i;
1074  } else {
1075  start = i;
1076  }
1077  }
1078  } else {
1079  QDateTime dtutc = dt;
1080  dtutc.setTimeSpec(Qt::UTC);
1081  while (end - start > 1) {
1082  const int i = (start + end) / 2;
1083  if (dtutc.addSecs(-transitions[i].phase().utcOffset()) < transitions[i].time()) {
1084  end = i;
1085  } else {
1086  start = i;
1087  }
1088  }
1089  }
1090  return end ? start : -1;
1091 }
1092 
1093 // Find the indexes to the transitions at or after start, and before or at end.
1094 // start and end must be UTC.
1095 // Reply = false if none.
1096 bool KTimeZoneDataPrivate::transitionIndexes(const QDateTime &start, const QDateTime &end, int &ixstart, int &ixend) const
1097 {
1098  ixstart = 0;
1099  if (start.isValid() && start.timeSpec() == Qt::UTC) {
1100  ixstart = transitionIndex(start);
1101  if (ixstart < 0) {
1102  ixstart = 0;
1103  } else if (transitions[ixstart].time() < start) {
1104  if (++ixstart >= transitions.count()) {
1105  return false; // there are no transitions at/after 'start'
1106  }
1107  }
1108  }
1109  ixend = -1;
1110  if (end.isValid() && end.timeSpec() == Qt::UTC) {
1111  ixend = transitionIndex(end);
1112  if (ixend < 0) {
1113  return false; // there are no transitions at/before 'end'
1114  }
1115  }
1116  return true;
1117 }
1118 
1119 /* Check if it's a local time which occurs both before and after the specified
1120  * transition (for which it has to span a daylight saving to standard time change).
1121  * @param utcLocalTime local time set to Qt::UTC
1122  */
1123 bool KTimeZoneDataPrivate::isSecondOccurrence(const QDateTime &utcLocalTime, int transitionIndex) const
1124 {
1125  if (transitionIndex < 0) {
1126  return false;
1127  }
1128  const int offset = transitions[transitionIndex].phase().utcOffset();
1129  const int prevoffset = (transitionIndex > 0) ? transitions[transitionIndex - 1].phase().utcOffset() : prePhase.utcOffset();
1130  const int phaseDiff = prevoffset - offset;
1131  if (phaseDiff <= 0) {
1132  return false;
1133  }
1134  // Find how long after the start of the latest phase 'dt' is
1135  const qint64 afterStart = transitions[transitionIndex].time().msecsTo(utcLocalTime)/1000 - offset;
1136  return (afterStart < phaseDiff);
1137 }
1138 
1139 KTimeZoneData::KTimeZoneData()
1140  : d(new KTimeZoneDataPrivate)
1141 { }
1142 
1143 KTimeZoneData::KTimeZoneData(const KTimeZoneData &c)
1144  : d(new KTimeZoneDataPrivate)
1145 {
1146  d->phases = c.d->phases;
1147  d->transitions = c.d->transitions;
1148  d->leapChanges = c.d->leapChanges;
1149  d->utcOffsets = c.d->utcOffsets;
1150  d->abbreviations = c.d->abbreviations;
1151  d->prePhase = c.d->prePhase;
1152 }
1153 
1154 KTimeZoneData::~KTimeZoneData()
1155 {
1156  delete d;
1157 }
1158 
1159 KTimeZoneData &KTimeZoneData::operator=(const KTimeZoneData &c)
1160 {
1161  d->phases = c.d->phases;
1162  d->transitions = c.d->transitions;
1163  d->leapChanges = c.d->leapChanges;
1164  d->utcOffsets = c.d->utcOffsets;
1165  d->abbreviations = c.d->abbreviations;
1166  d->prePhase = c.d->prePhase;
1167  return *this;
1168 }
1169 
1171 {
1172  return new KTimeZoneData(*this);
1173 }
1174 
1176 {
1177  if (d->abbreviations.isEmpty()) {
1178  for (int i = 0, end = d->phases.count(); i < end; ++i) {
1179  const QList<QByteArray> abbrevs = d->phases[i].abbreviations();
1180  for (int j = 0, jend = abbrevs.count(); j < jend; ++j)
1181  if (!d->abbreviations.contains(abbrevs[j])) {
1182  d->abbreviations.append(abbrevs[j]);
1183  }
1184  }
1185  if (d->abbreviations.isEmpty()) {
1186  d->abbreviations += "UTC";
1187  }
1188  }
1189  return d->abbreviations;
1190 }
1191 
1193 {
1194  if (d->phases.isEmpty()) {
1195  return "UTC";
1196  }
1197  const KTimeZone::Transition *tr = transition(utcDateTime);
1198  const QList<QByteArray> abbrevs = tr ? tr->phase().abbreviations()
1199  : d->prePhase.abbreviations();
1200  if (abbrevs.isEmpty()) {
1201  return QByteArray();
1202  }
1203  return abbrevs[0];
1204 }
1205 
1207 {
1208  if (d->utcOffsets.isEmpty()) {
1209  for (int i = 0, end = d->phases.count(); i < end; ++i) {
1210  const int offset = d->phases[i].utcOffset();
1211  if (!d->utcOffsets.contains(offset)) {
1212  d->utcOffsets.append(offset);
1213  }
1214  }
1215  if (d->utcOffsets.isEmpty()) {
1216  d->utcOffsets += 0;
1217  } else {
1218  std::sort(d->utcOffsets.begin(), d->utcOffsets.end());
1219  }
1220  }
1221  return d->utcOffsets;
1222 }
1223 
1225 {
1226  return d->phases;
1227 }
1228 
1229 void KTimeZoneData::setPhases(const QList<KTimeZone::Phase> &phases, const KTimeZone::Phase &previousPhase)
1230 {
1231  d->phases = phases;
1232  d->prePhase = previousPhase;
1233 }
1234 
1235 void KTimeZoneData::setPhases(const QList<KTimeZone::Phase> &phases, int previousUtcOffset)
1236 {
1237  d->phases = phases;
1238  d->prePhase = KTimeZone::Phase(previousUtcOffset, QByteArray(), false);
1239 }
1240 
1242 {
1243  return false;
1244 }
1245 
1247 {
1248  int ixstart, ixend;
1249  if (!d->transitionIndexes(start, end, ixstart, ixend)) {
1250  return QList<KTimeZone::Transition>(); // there are no transitions within the time period
1251  }
1252  if (ixend >= 0) {
1253  return d->transitions.mid(ixstart, ixend - ixstart + 1);
1254  }
1255  if (ixstart > 0) {
1256  return d->transitions.mid(ixstart);
1257  }
1258  return d->transitions;
1259 }
1260 
1262 {
1263  d->transitions = transitions;
1264 }
1265 
1267 {
1268  return d->prePhase.utcOffset();
1269 }
1270 
1271 const KTimeZone::Transition *KTimeZoneData::transition(const QDateTime &dt, const KTimeZone::Transition **secondTransition,
1272  bool *validTime) const
1273 {
1274  int secondIndex;
1275  const int index = transitionIndex(dt, (secondTransition ? &secondIndex : nullptr), validTime);
1276  if (secondTransition) {
1277  *secondTransition = (secondIndex >= 0) ? &d->transitions[secondIndex] : nullptr;
1278  }
1279  return (index >= 0) ? &d->transitions[index] : nullptr;
1280 }
1281 
1282 int KTimeZoneData::transitionIndex(const QDateTime &dt, int *secondIndex, bool *validTime) const
1283 {
1284  if (validTime) {
1285  *validTime = true;
1286  }
1287 
1288  // Find the last transition before this date/time
1289  int index = d->transitionIndex(dt);
1290  if (dt.timeSpec() == Qt::UTC) {
1291  if (secondIndex) {
1292  *secondIndex = index;
1293  }
1294  return index;
1295  } else {
1296  /* Check whether the specified local time actually occurs.
1297  * Find the start of the next phase, and check if it falls in the gap
1298  * between the two phases.
1299  */
1300  QDateTime dtutc = dt;
1301  dtutc.setTimeSpec(Qt::UTC);
1302  const int count = d->transitions.count();
1303  const int next = (index >= 0) ? index + 1 : 0;
1304  if (next < count) {
1305  KTimeZone::Phase nextPhase = d->transitions.at(next).phase();
1306  const int offset = (index >= 0) ? d->transitions.at(index).phase().utcOffset() : d->prePhase.utcOffset();
1307  const int phaseDiff = nextPhase.utcOffset() - offset;
1308  if (phaseDiff > 0) {
1309  // Get UTC equivalent as if 'dt' was in the next phase
1310  if (dtutc.msecsTo(d->transitions.at(next).time())/1000 + nextPhase.utcOffset() <= phaseDiff) {
1311  // The time falls in the gap between the two phases,
1312  // so return an invalid value.
1313  if (validTime) {
1314  *validTime = false;
1315  }
1316  if (secondIndex) {
1317  *secondIndex = -1;
1318  }
1319  return -1;
1320  }
1321  }
1322  }
1323 
1324  if (index < 0) {
1325  // The specified time is before the first phase
1326  if (secondIndex) {
1327  *secondIndex = -1;
1328  }
1329  return -1;
1330  }
1331 
1332  /* Check if it's a local time which occurs both before and after the 'latest'
1333  * phase start time (for which it has to span a daylight saving to standard
1334  * time change).
1335  */
1336  bool duplicate = true;
1337  if (d->isSecondOccurrence(dtutc, index)) {
1338  // 'dt' occurs twice
1339  if (secondIndex) {
1340  *secondIndex = index;
1341  duplicate = false;
1342  }
1343  // Get the transition containing the first occurrence of 'dt'
1344  if (index <= 0) {
1345  return -1; // first occurrence of 'dt' is just before the first transition
1346  }
1347  --index;
1348  }
1349 
1350  if (secondIndex && duplicate) {
1351  *secondIndex = index;
1352  }
1353  return index;
1354  }
1355 }
1356 
1357 QList<QDateTime> KTimeZoneData::transitionTimes(const KTimeZone::Phase &phase, const QDateTime &start, const QDateTime &end) const
1358 {
1359  QList<QDateTime> times;
1360  int ixstart, ixend;
1361  if (d->transitionIndexes(start, end, ixstart, ixend)) {
1362  if (ixend < 0) {
1363  ixend = d->transitions.count() - 1;
1364  }
1365  while (ixstart <= ixend) {
1366  if (d->transitions[ixstart].phase() == phase) {
1367  times += d->transitions[ixstart].time();
1368  }
1369  }
1370  }
1371  return times;
1372 }
1373 
1375 {
1376  return d->leapChanges;
1377 }
1378 
1380 {
1381  d->leapChanges = adjusts;
1382 }
1383 
1384 KTimeZone::LeapSeconds KTimeZoneData::leapSecondChange(const QDateTime &utc) const
1385 {
1386  if (utc.timeSpec() != Qt::UTC) {
1387  qCritical() << "KTimeZoneData::leapSecondChange(): non-UTC time specified" << endl;
1388  } else {
1389  for (int i = d->leapChanges.count(); --i >= 0;) {
1390  if (d->leapChanges[i].dateTime() < utc) {
1391  return d->leapChanges[i];
1392  }
1393  }
1394  }
1395  return KTimeZone::LeapSeconds();
1396 }
qint64 daysTo(const QDate &d) const const
bool useZoneParse() const
Return whether the source database supports the ad hoc extraction of data for individual time zones u...
Definition: ktimezone.cpp:986
virtual int offsetAtUtc(const QDateTime &utcDateTime) const
Returns the offset of this time zone to UTC at the given UTC date/time.
Definition: ktimezone.cpp:876
const KTimeZone::Transition * transition(const QDateTime &dt, const KTimeZone::Transition **secondTransition=nullptr, bool *validTime=nullptr) const
Find the last daylight savings time transition at or before a given UTC or local time.
Definition: ktimezone.cpp:1271
int currentOffset(Qt::TimeSpec basis=Qt::UTC) const
Returns the current offset of this time zone to UTC or the local system time zone.
Definition: ktimezone.cpp:886
QString toUpper() const const
static QDateTime fromTime_t(time_t t)
Converts a UTC time, measured in seconds since 00:00:00 UTC 1st January 1970 (as returned by time(2))...
Definition: ktimezone.cpp:922
bool parse() const
Extracts time zone detail information for this time zone from the source database.
Definition: ktimezone.cpp:792
virtual bool hasTransitions(const KTimeZone *caller) const
Implements KTimeZone::hasTransitions().
Definition: ktimezone.cpp:579
virtual QByteArray type() const
Returns the class name of the data represented by this instance.
Definition: ktimezone.cpp:455
void setPhases(const QList< KTimeZone::Phase > &phases, const KTimeZone::Phase &previousPhase)
Initialise the daylight savings time phase list.
Definition: ktimezone.cpp:1229
Base class for the parsed data returned by a KTimeZoneSource class.
Definition: ktimezone.h:1302
void setData(KTimeZoneData *data, KTimeZoneSource *source=nullptr)
Sets the detailed parsed data for the time zone, and optionally a new time zone source object...
Definition: ktimezone.cpp:768
bool isValid() const
Checks whether the instance is valid.
Definition: ktimezone.cpp:638
virtual int offsetAtZoneTime(const KTimeZone *caller, const QDateTime &zoneDateTime, int *secondOffset) const
Implements KTimeZone::offsetAtZoneTime().
Definition: ktimezone.cpp:465
const T & at(int i) const const
void setLeapSecondChanges(const QList< KTimeZone::LeapSeconds > &adjusts)
Initialise the leap seconds adjustment list.
Definition: ktimezone.cpp:1379
QTime time() const const
virtual KTimeZoneData * parse(const KTimeZone &zone) const
Extracts detail information for one time zone from the source database.
Definition: ktimezone.cpp:980
void setTransitions(const QList< KTimeZone::Transition > &transitions)
Initialise the daylight savings time transition list.
Definition: ktimezone.cpp:1261
bool add(const KTimeZone &zone)
Adds a time zone to the collection.
Definition: ktimezone.cpp:67
KTimeZone remove(const KTimeZone &zone)
Removes a time zone from the collection.
Definition: ktimezone.cpp:79
virtual bool hasTransitions() const
Return whether daylight saving transitions are available for the time zone.
Definition: ktimezone.cpp:700
KTimeZone::LeapSeconds leapSecondChange(const QDateTime &utc) const
Find the leap second adjustment which is applicable at a given UTC time.
Definition: ktimezone.cpp:1384
QList< KTimeZone::Transition > transitions(const QDateTime &start=QDateTime(), const QDateTime &end=QDateTime()) const
Return all daylight saving transitions, in time order.
Definition: ktimezone.cpp:1246
LocalTime
KTimeZoneSource * source() const
Returns the source reader/parser for the time zone&#39;s source database.
Definition: ktimezone.cpp:752
void setTimeSpec(Qt::TimeSpec spec)
float latitude() const
Returns the latitude of the time zone.
Definition: ktimezone.cpp:648
virtual KTimeZoneData * clone() const
Creates a new copy of this object.
Definition: ktimezone.cpp:1170
int count(const T &value) const const
QString countryCode() const
Returns the two-letter country code of the time zone.
Definition: ktimezone.cpp:643
void append(const T &value)
const KTimeZoneData * data(bool create=false) const
Returns the detailed parsed data for the time zone.
Definition: ktimezone.cpp:757
static time_t toTime_t(const QDateTime &utcDateTime)
Converts a UTC QDateTime to a UTC time, measured in seconds since 00:00:00 UTC 1st January 1970 (as r...
Definition: ktimezone.cpp:938
QByteArray type() const
Returns the class name of the data represented by this instance.
Definition: ktimezone.cpp:633
QByteArray abbreviation(const QDateTime &utcDateTime) const
Returns the time zone abbreviation current at a specified time.
Definition: ktimezone.cpp:676
virtual KTimeZoneBackend * clone() const
Creates a copy of this instance.
Definition: ktimezone.cpp:460
QList< Phase > phases() const
Return all daylight savings time phases for the time zone.
Definition: ktimezone.cpp:692
static const float UNKNOWN
A representation for unknown locations; this is a float that does not represent a real latitude or lo...
Definition: ktimezone.h:1085
bool isEmpty() const const
bool isEmpty() const const
virtual QList< QByteArray > abbreviations() const
Returns the complete list of time zone abbreviations.
Definition: ktimezone.cpp:1175
static const time_t InvalidTime_t
Indicates an invalid time_t value.
Definition: ktimezone.h:1079
QTime addSecs(int s) const const
QList< QDateTime > transitionTimes(const KTimeZone::Phase &phase, const QDateTime &start=QDateTime(), const QDateTime &end=QDateTime()) const
Return the times of all daylight saving transitions to a given time zone phase, in time order...
Definition: ktimezone.cpp:1357
virtual bool isDst(const KTimeZone *caller, time_t t) const
Implements KTimeZone::isDst().
Definition: ktimezone.cpp:574
bool updateBase(const KTimeZone &other)
Update the definition of the time zone to be identical to another KTimeZone instance.
Definition: ktimezone.cpp:780
QList< KTimeZone::LeapSeconds > leapSecondChanges() const
Return all leap second adjustments, in time order.
Definition: ktimezone.cpp:1374
Time zone functions.
int transitionIndex(const QDateTime &dt, int *secondIndex=nullptr, bool *validTime=nullptr) const
Find the index to the last daylight savings time transition at or before a given UTC or local time...
Definition: ktimezone.cpp:725
static const int InvalidOffset
Indicates an invalid UTC offset.
Definition: ktimezone.h:1075
QDateTime toUtc(const QDateTime &zoneDateTime) const
Converts a date/time, which is interpreted as local time in this time zone, into UTC.
Definition: ktimezone.cpp:804
float longitude() const
Returns the latitude of the time zone.
Definition: ktimezone.cpp:653
Qt::TimeSpec timeSpec() const const
QUrl source() const const
const KTimeZone::Transition * transition(const QDateTime &dt, const Transition **secondTransition=nullptr, bool *validTime=nullptr) const
Find the last daylight savings time transition at or before a given UTC or local time.
Definition: ktimezone.cpp:713
Base class representing a time zone.
Definition: ktimezone.h:415
bool isValid() const const
virtual int offsetAtZoneTime(const QDateTime &zoneDateTime, int *secondOffset=nullptr) const
Returns the offset of this time zone to UTC at the given local date/time.
Definition: ktimezone.cpp:871
QList< LeapSeconds > leapSecondChanges() const
Return all leap second adjustments, in time order.
Definition: ktimezone.cpp:744
QDate date() const const
int previousUtcOffset() const
Returns the UTC offset to use before the start of data for the time zone.
Definition: ktimezone.cpp:1266
virtual bool isDst(time_t t) const
Returns whether daylight savings time is in operation at a specified UTC time.
Definition: ktimezone.cpp:911
QDateTime convert(const KTimeZone &newZone, const QDateTime &zoneDateTime) const
Converts a date/time, which is interpreted as being local time in this time zone, into local time in ...
Definition: ktimezone.cpp:860
void clear()
Clears the collection.
Definition: ktimezone.cpp:105
QList< QDateTime > transitionTimes(const Phase &phase, const QDateTime &start=QDateTime(), const QDateTime &end=QDateTime()) const
Return the times of all daylight saving transitions to a given time zone phase, in time order...
Definition: ktimezone.cpp:736
bool operator==(const KTimeZone &rhs) const
Checks whether this is the same instance as another one.
Definition: ktimezone.cpp:628
virtual bool isDstAtUtc(const QDateTime &utcDateTime) const
Returns whether daylight savings time is in operation at the given UTC date/time. ...
Definition: ktimezone.cpp:906
KTimeZone()
Constructs a null time zone.
Definition: ktimezone.cpp:595
QList< KTimeZone::Transition > transitions(const QDateTime &start=QDateTime(), const QDateTime &end=QDateTime()) const
Return all daylight saving transitions, in time order.
Definition: ktimezone.cpp:705
int transitionIndex(const QDateTime &dt, int *secondIndex=nullptr, bool *validTime=nullptr) const
Find the index to the last daylight savings time transition at or before a given UTC or local time...
Definition: ktimezone.cpp:1282
QList< KTimeZone::Phase > phases() const
Return all daylight savings time phases.
Definition: ktimezone.cpp:1224
QList< T > mid(int pos, int length) const const
virtual int offsetAtUtc(const KTimeZone *caller, const QDateTime &utcDateTime) const
Implements KTimeZone::offsetAtUtc().
Definition: ktimezone.cpp:526
virtual QList< int > utcOffsets() const
Returns the complete list of UTC offsets for the time zone, if the time zone&#39;s source makes such info...
Definition: ktimezone.cpp:1206
QDateTime toZoneTime(const QDateTime &utcDateTime, bool *secondOccurrence=nullptr) const
Converts a UTC date/time into local time in this time zone.
Definition: ktimezone.cpp:818
QString name() const
Returns the name of the time zone.
Definition: ktimezone.cpp:663
QDate addDays(qint64 ndays) const const
const ZoneMap zones() const
Returns all the time zones defined in this collection.
Definition: ktimezone.cpp:62
virtual int offset(time_t t) const
Returns the offset of this time zone to UTC at a specified UTC time.
Definition: ktimezone.cpp:881
QDateTime addSecs(qint64 s) const const
virtual int offset(const KTimeZone *caller, time_t t) const
Implements KTimeZone::offset().
Definition: ktimezone.cpp:557
Base class representing a source of time zone information.
Definition: ktimezone.h:1231
QList< int > utcOffsets() const
Returns the complete list of UTC offsets used by the time zone.
Definition: ktimezone.cpp:684
QList< QByteArray > abbreviations() const
Returns the list of time zone abbreviations used by the time zone.
Definition: ktimezone.cpp:668
QString comment() const
Returns any comment for the time zone.
Definition: ktimezone.cpp:658
virtual QByteArray abbreviation(const QDateTime &utcDateTime) const
Returns the time zone abbreviation current at a specified time.
Definition: ktimezone.cpp:1192
int secsTo(const QTime &t) const const
static KTimeZone utc()
Returns a standard UTC time zone, with name "UTC".
Definition: ktimezone.cpp:916
virtual bool isDstAtUtc(const KTimeZone *caller, const QDateTime &utcDateTime) const
Implements KTimeZone::isDstAtUtc().
Definition: ktimezone.cpp:562
KTimeZoneBackend()
Implements KTimeZone::KTimeZone().
Definition: ktimezone.cpp:414
KTimeZone zone(const QString &name) const
Returns the time zone with the given name.
Definition: ktimezone.cpp:110
qint64 msecsTo(const QDateTime &other) const const
virtual bool hasTransitions() const
Return whether daylight saving transitions are available for the time zone.
Definition: ktimezone.cpp:1241
Base backend class for KTimeZone classes.
Definition: ktimezone.h:1121
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Fri Aug 14 2020 22:58:21 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.