25 #include <config-date.h>
27 #ifdef HAVE_SYS_TIME_H
36 #include <QtCore/QSet>
37 #include <QtCore/QSharedData>
38 #include <QtCore/QCoreApplication>
48 class KTimeZonesPrivate
51 KTimeZonesPrivate() {}
58 : d(new KTimeZonesPrivate)
76 if (d->zones.find(zone.
name()) != d->zones.end())
86 for (ZoneMap::Iterator it = d->zones.begin(), end = d->zones.end(); it != end; ++it)
88 if (it.value() ==
zone)
102 ZoneMap::Iterator it = d->zones.find(name);
103 if (it != d->zones.end())
122 ZoneMap::ConstIterator it = d->zones.constFind(name);
123 if (it != d->zones.constEnd())
137 QByteArray abbreviations;
142 explicit KTimeZonePhasePrivate(
int offset = 0,
bool ds =
false)
147 KTimeZonePhasePrivate(
const KTimeZonePhasePrivate& rhs)
149 abbreviations(rhs.abbreviations),
150 comment(rhs.comment),
151 utcOffset(rhs.utcOffset),
154 bool operator==(
const KTimeZonePhasePrivate &rhs)
const
156 return abbreviations == rhs.abbreviations
157 && comment == rhs.comment
158 && utcOffset == rhs.utcOffset
165 : d(new KTimeZonePhasePrivate)
171 : d(new KTimeZonePhasePrivate(utcOffset, dst))
173 d->abbreviations = abbrevs;
179 : d(new KTimeZonePhasePrivate(utcOffset, dst))
181 for (
int i = 0, end = abbrevs.count(); i < end; ++i)
184 d->abbreviations +=
'\0';
185 d->abbreviations += abbrevs[i];
207 return d == rhs.d || *d == *rhs.d;
217 return d->abbreviations.split(
'\0');
233 class KTimeZoneTransitionPrivate
242 : d(new KTimeZoneTransitionPrivate)
247 : d(new KTimeZoneTransitionPrivate)
254 : d(new KTimeZoneTransitionPrivate)
257 d->phase = t.d->phase;
268 d->phase = t.d->phase;
274 return d->time < rhs.d->time;
283 class KTimeZoneDataPrivate
286 QList<KTimeZone::Phase>
phases;
288 QList<KTimeZone::LeapSeconds> leapChanges;
293 KTimeZoneDataPrivate() {}
296 bool transitionIndexes(
const QDateTime &start,
const QDateTime &end,
int &ixstart,
int &ixend)
const;
306 KTimeZonePrivate() :
source(0),
data(0), refCount(1), cachedTransitionIndex(-1) {}
308 const QString &country,
float lat,
float lon,
const QString &cmnt);
309 KTimeZonePrivate(
const KTimeZonePrivate &);
310 ~KTimeZonePrivate() {
delete data; }
311 KTimeZonePrivate &
operator=(
const KTimeZonePrivate &);
313 static void cleanup();
323 int cachedTransitionIndex;
326 bool cachedTransitionTimesValid;
336 const QString &country,
float lat,
float lon,
const QString &cmnt)
345 cachedTransitionIndex(-1)
354 KTimeZonePrivate::KTimeZonePrivate(
const KTimeZonePrivate &rhs)
363 cachedTransitionIndex(rhs.cachedTransitionIndex),
364 cachedTransitionStartZoneTime(rhs.cachedTransitionStartZoneTime),
365 cachedTransitionEndZoneTime(rhs.cachedTransitionEndZoneTime),
366 cachedTransitionTimesValid(rhs.cachedTransitionTimesValid)
369 data = rhs.data->clone();
384 cachedTransitionIndex = rhs.cachedTransitionIndex;
385 cachedTransitionStartZoneTime = rhs.cachedTransitionStartZoneTime;
386 cachedTransitionEndZoneTime = rhs.cachedTransitionEndZoneTime;
387 cachedTransitionTimesValid = rhs.cachedTransitionTimesValid;
390 data = rhs.data->clone();
402 qAddPostRoutine(KTimeZonePrivate::cleanup);
407 void KTimeZonePrivate::cleanup()
418 : d(&*s_emptyTimeZonePrivate)
428 const QString &countryCode,
float latitude,
float longitude,
const QString &comment)
429 : d(new KTimeZonePrivate(source, name, countryCode, latitude, longitude, comment))
440 if (d && --d->refCount == 0)
449 if (--d->refCount == 0)
469 if (!zoneDateTime.isValid() || zoneDateTime.timeSpec() != Qt::LocalTime)
476 int index = d->cachedTransitionIndex;
477 if (index >= 0 && index < transitions.count())
482 if (!d->cachedTransitionTimesValid)
484 const int offset = transitions[index].phase().utcOffset();
485 const int preoffset = (index > 0) ? transitions[index - 1].phase().utcOffset() : d->data ? d->data->previousUtcOffset() : 0;
486 d->cachedTransitionStartZoneTime = transitions[index].time().addSecs(qMax(offset, preoffset));
487 if (index + 1 < transitions.count())
489 const int postoffset = transitions[index + 1].phase().utcOffset();
490 d->cachedTransitionEndZoneTime = transitions[index + 1].time().addSecs(qMin(offset, postoffset));
492 d->cachedTransitionTimesValid =
true;
495 dtutc.setTimeSpec(Qt::UTC);
496 if (dtutc >= d->cachedTransitionStartZoneTime
497 && (index + 1 >= transitions.count() || dtutc < d->cachedTransitionEndZoneTime))
500 const int offset = transitions[index].phase().utcOffset();
503 #ifdef COMPILING_TESTS
504 qDebug(
"-> Using cache");
511 #ifdef COMPILING_TESTS
512 qDebug(
"-> No cache");
515 int secondIndex = -1;
516 index = caller->
transitionIndex(zoneDateTime, (secondOffset ? &secondIndex : 0), &validTime);
519 : validTime ? (d->data ? d->data->previousUtcOffset() : 0)
522 *secondOffset = (secondIndex >= 0) ? transitions.at(secondIndex).phase().utcOffset() :
offset;
525 d->cachedTransitionIndex = index;
526 d->cachedTransitionTimesValid =
false;
532 if (!utcDateTime.isValid() || utcDateTime.timeSpec() != Qt::UTC)
535 int index = d->cachedTransitionIndex;
536 if (index >= 0 && index < transitions.count())
539 if (utcDateTime >= transitions[index].time()
540 && (index + 1 >= transitions.count()
541 || utcDateTime < transitions[index + 1].time()))
544 #ifdef COMPILING_TESTS
545 qDebug(
"Using cache");
547 return transitions[index].phase().utcOffset();
552 #ifdef COMPILING_TESTS
556 d->cachedTransitionIndex = index;
557 d->cachedTransitionTimesValid =
false;
559 return tr ? tr->
phase().
utcOffset() : (d->data ? d->data->previousUtcOffset() : 0);
569 if (!utcDateTime.isValid() || utcDateTime.timeSpec() != Qt::UTC)
591 #if SIZEOF_TIME_T == 8
594 const time_t KTimeZone::InvalidTime_t = 0x80000000;
621 Q_ASSERT(d->d->refCount == 1 || d->d == &*s_emptyTimeZonePrivate);
636 return d->d == rhs.d->d;
646 return !d->d->name.isEmpty();
651 return d->d->countryCode;
656 return d->d->latitude;
661 return d->d->longitude;
666 return d->d->comment;
677 return QList<QByteArray>();
678 return d->d->data->abbreviations();
683 if (utcDateTime.timeSpec() != Qt::UTC || !
data(
true))
685 return d->d->data->abbreviation(utcDateTime);
692 return d->d->data->utcOffsets();
698 return QList<KTimeZone::Phase>();
699 return d->d->data->phases();
710 return QList<KTimeZone::Transition>();
711 return d->d->data->transitions(start, end);
715 bool *validTime)
const
719 return d->d->data->transition(dt, secondTransition, validTime);
726 return d->d->data->transitionIndex(dt, secondIndex, validTime);
732 return QList<QDateTime>();
733 return d->d->data->transitionTimes(phase, start, end);
739 return QList<KTimeZone::LeapSeconds>();
740 return d->d->data->leapSecondChanges();
752 if (create && !d->d->data && d->d->source->useZoneParse())
753 d->d->data = d->d->source->parse(*
this);
769 if (d->d->name.isEmpty() || d->d->name != other.d->d->name)
771 d->d->countryCode = other.d->d->countryCode;
772 d->d->comment = other.d->d->comment;
773 d->d->latitude = other.d->d->latitude;
774 d->d->longitude = other.d->d->longitude;
782 if (d->d->source->useZoneParse())
785 d->d->data = d->d->source->parse(*
this);
792 if (!zoneDateTime.isValid() || zoneDateTime.timeSpec() != Qt::LocalTime)
798 dt.setTimeSpec(Qt::UTC);
799 return dt.addSecs(-secs);
804 if (secondOccurrence)
805 *secondOccurrence =
false;
806 if (!utcDateTime.isValid() || utcDateTime.timeSpec() != Qt::UTC)
816 dt.setTimeSpec(Qt::LocalTime);
823 QDateTime dt = utcDateTime.addSecs(secs);
824 if (secondOccurrence)
828 *secondOccurrence = data->d->isSecondOccurrence(dt, index);
830 dt.setTimeSpec(Qt::LocalTime);
836 QDateTime dt = utcDateTime.addSecs(secs);
837 dt.setTimeSpec(Qt::LocalTime);
838 if (secondOccurrence)
850 if (newZone == *
this)
852 if (zoneDateTime.timeSpec() != Qt::LocalTime)
871 return d->
offset(
this, t);
877 const time_t now = time(0);
878 const int secs =
offset(now);
884 return secs -
gmtoff(now);
902 return d->
isDst(
this, t);
907 static KTimeZone utcZone(QLatin1String(
"UTC"));
913 static const int secondsADay = 86400;
914 static const QDate epochDate(1970,1,1);
915 static const QTime epochTime(0,0,0);
916 int days = t / secondsADay;
919 secs = t % secondsADay;
922 secs = secondsADay - (-t % secondsADay);
925 return QDateTime(epochDate.addDays(days), epochTime.addSecs(secs), Qt::UTC);
930 static const QDate epochDate(1970,1,1);
931 static const QTime epochTime(0,0,0);
932 if (utcDateTime.timeSpec() != Qt::UTC)
934 const qint64 days = epochDate.daysTo(utcDateTime.date());
935 const qint64 secs = epochTime.secsTo(utcDateTime.time());
936 const qint64 t64 = days * 86400 + secs;
937 const time_t t =
static_cast<time_t
>(t64);
938 if (static_cast<qint64>(t) != t64)
946 class KTimeZoneSourcePrivate
954 : d(new KTimeZoneSourcePrivate)
956 d->mUseZoneParse =
true;
960 : d(new KTimeZoneSourcePrivate)
972 Q_ASSERT(d->mUseZoneParse);
978 return d->mUseZoneParse;
984 class KTimeZoneLeapSecondsPrivate
994 : d(new KTimeZoneLeapSecondsPrivate)
999 : d(new KTimeZoneLeapSecondsPrivate)
1001 if (utc.timeSpec() == Qt::UTC)
1010 : d(new KTimeZoneLeapSecondsPrivate)
1013 d->comment = c.d->comment;
1014 d->seconds = c.d->seconds;
1025 d->comment = c.d->comment;
1026 d->seconds = c.d->seconds;
1032 return d->dt < c.d->dt;
1042 return d->dt.isValid();
1064 if (dt.timeSpec() == Qt::UTC)
1066 while (end - start > 1)
1068 int i = (start + end) / 2;
1078 dtutc.setTimeSpec(Qt::UTC);
1079 while (end - start > 1)
1081 const int i = (start + end) / 2;
1088 return end ? start : -1;
1094 bool KTimeZoneDataPrivate::transitionIndexes(
const QDateTime &start,
const QDateTime &end,
int &ixstart,
int &ixend)
const
1097 if (start.isValid() && start.timeSpec() == Qt::UTC)
1109 if (end.isValid() && end.timeSpec() == Qt::UTC)
1124 if (transitionIndex < 0)
1127 const int prevoffset = (transitionIndex > 0) ?
transitions[transitionIndex-1].phase().utcOffset() : prePhase.utcOffset();
1128 const int phaseDiff = prevoffset -
offset;
1133 return (afterStart < phaseDiff);
1139 : d(new KTimeZoneDataPrivate)
1143 : d(new KTimeZoneDataPrivate)
1145 d->phases = c.d->phases;
1146 d->transitions = c.d->transitions;
1147 d->leapChanges = c.d->leapChanges;
1148 d->utcOffsets = c.d->utcOffsets;
1149 d->abbreviations = c.d->abbreviations;
1150 d->prePhase = c.d->prePhase;
1160 d->phases = c.d->phases;
1161 d->transitions = c.d->transitions;
1162 d->leapChanges = c.d->leapChanges;
1163 d->utcOffsets = c.d->utcOffsets;
1164 d->abbreviations = c.d->abbreviations;
1165 d->prePhase = c.d->prePhase;
1176 if (d->abbreviations.isEmpty())
1178 for (
int i = 0, end = d->phases.count(); i < end; ++i)
1180 const QList<QByteArray> abbrevs = d->phases[i].abbreviations();
1181 for (
int j = 0, jend = abbrevs.count(); j < jend; ++j)
1182 if (!d->abbreviations.contains(abbrevs[j]))
1183 d->abbreviations.append(abbrevs[j]);
1185 if (d->abbreviations.isEmpty())
1186 d->abbreviations +=
"UTC";
1188 return d->abbreviations;
1193 if (d->phases.isEmpty())
1197 : d->prePhase.abbreviations();
1198 if (abbrevs.isEmpty())
1199 return QByteArray();
1205 if (d->utcOffsets.isEmpty())
1207 for (
int i = 0, end = d->phases.count(); i < end; ++i)
1209 const int offset = d->phases[i].utcOffset();
1210 if (!d->utcOffsets.contains(offset))
1211 d->utcOffsets.append(offset);
1213 if (d->utcOffsets.isEmpty())
1216 qSort(d->utcOffsets);
1218 return d->utcOffsets;
1229 d->prePhase = previousPhase;
1246 if (!d->transitionIndexes(start, end, ixstart, ixend))
1247 return QList<KTimeZone::Transition>();
1249 return d->transitions.mid(ixstart, ixend - ixstart + 1);
1251 return d->transitions.mid(ixstart);
1252 return d->transitions;
1262 return d->prePhase.utcOffset();
1266 bool *validTime)
const
1269 const int index =
transitionIndex(dt, (secondTransition ? &secondIndex : 0), validTime);
1270 if (secondTransition)
1271 *secondTransition = (secondIndex >= 0) ? &d->transitions[secondIndex] : 0;
1272 return (index >= 0) ? &d->transitions[index] : 0;
1281 int index = d->transitionIndex(dt);
1282 if (dt.timeSpec() == Qt::UTC)
1285 *secondIndex = index;
1295 dtutc.setTimeSpec(Qt::UTC);
1296 const int count = d->transitions.count();
1297 const int next = (index >= 0) ? index + 1 : 0;
1301 const int offset = (index >= 0) ? d->transitions[index].phase().utcOffset() : d->prePhase.utcOffset();
1302 const int phaseDiff = nextPhase.
utcOffset() - offset;
1306 if (dtutc.secsTo(d->transitions[next].time()) + nextPhase.
utcOffset() < phaseDiff)
1331 bool duplicate =
true;
1332 if (d->isSecondOccurrence(dtutc, index))
1337 *secondIndex = index;
1346 if (secondIndex && duplicate)
1347 *secondIndex = index;
1354 QList<QDateTime> times;
1356 if (d->transitionIndexes(start, end, ixstart, ixend))
1359 ixend = d->transitions.count() - 1;
1360 while (ixstart <= ixend)
1362 if (d->transitions[ixstart].phase() == phase)
1363 times += d->transitions[ixstart].time();
1371 return d->leapChanges;
1376 d->leapChanges = adjusts;
1381 if (utc.timeSpec() != Qt::UTC)
1382 kError() <<
"KTimeZoneData::leapSecondChange(): non-UTC time specified" << endl;
1385 for (
int i = d->leapChanges.count(); --i >= 0; )
1387 if (d->leapChanges[i].dateTime() < utc)
1388 return d->leapChanges[i];