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
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();
374 KTimeZonePrivate &KTimeZonePrivate::operator=(
const KTimeZonePrivate &rhs)
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 kDebug(161) <<
"-> Using cache";
511 #ifdef COMPILING_TESTS
512 kDebug(161) <<
"-> 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 kDebug(161) <<
"Using cache";
547 return transitions[index].phase().utcOffset();
552 #ifdef COMPILING_TESTS
553 kDebug(161) <<
"No cache";
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;
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();
699 return d->d->data->phases();
711 return d->d->data->transitions(start, end);
715 bool *validTime)
const
722 return d->d->data->transition(dt, secondTransition, validTime);
732 return d->d->data->transitionIndex(dt, secondIndex, validTime);
739 return d->d->data->transitionTimes(phase, start, end);
746 return d->d->data->leapSecondChanges();
758 if (create && !d->d->data && d->d->source->useZoneParse())
759 d->d->data = d->d->source->parse(*
this);
775 if (d->d->name.isEmpty() || d->d->name != other.d->d->name)
777 d->d->countryCode = other.d->d->countryCode;
778 d->d->comment = other.d->d->comment;
779 d->d->latitude = other.d->d->latitude;
780 d->d->longitude = other.d->d->longitude;
788 if (d->d->source->useZoneParse())
791 d->d->data = d->d->source->parse(*
this);
798 if (!zoneDateTime.isValid() || zoneDateTime.timeSpec() != Qt::LocalTime)
804 dt.setTimeSpec(Qt::UTC);
805 return dt.addSecs(-secs);
810 if (secondOccurrence)
811 *secondOccurrence =
false;
812 if (!utcDateTime.isValid() || utcDateTime.timeSpec() != Qt::UTC)
822 dt.setTimeSpec(Qt::LocalTime);
829 QDateTime dt = utcDateTime.addSecs(secs);
830 if (secondOccurrence)
834 *secondOccurrence = data->d->isSecondOccurrence(dt, index);
836 dt.setTimeSpec(Qt::LocalTime);
842 QDateTime dt = utcDateTime.addSecs(secs);
843 dt.setTimeSpec(Qt::LocalTime);
844 if (secondOccurrence)
856 if (newZone == *
this)
858 if (zoneDateTime.timeSpec() != Qt::LocalTime)
877 return d->
offset(
this, t);
883 const time_t now = time(0);
884 const int secs =
offset(now);
890 return secs -
gmtoff(now);
908 return d->
isDst(
this, t);
913 static KTimeZone utcZone(QLatin1String(
"UTC"));
919 static const int secondsADay = 86400;
920 static const QDate epochDate(1970,1,1);
921 static const QTime epochTime(0,0,0);
922 int days = t / secondsADay;
925 secs = t % secondsADay;
928 secs = secondsADay - (-t % secondsADay);
931 return QDateTime(epochDate.addDays(days), epochTime.addSecs(secs), Qt::UTC);
936 static const QDate epochDate(1970,1,1);
937 static const QTime epochTime(0,0,0);
938 if (utcDateTime.timeSpec() != Qt::UTC)
940 const qint64 days = epochDate.daysTo(utcDateTime.date());
941 const qint64 secs = epochTime.secsTo(utcDateTime.time());
942 const qint64 t64 = days * 86400 + secs;
943 const time_t t =
static_cast<time_t
>(t64);
944 if (static_cast<qint64>(t) != t64)
952 class KTimeZoneSourcePrivate
960 : d(new KTimeZoneSourcePrivate)
962 d->mUseZoneParse =
true;
966 : d(new KTimeZoneSourcePrivate)
978 Q_ASSERT(d->mUseZoneParse);
984 return d->mUseZoneParse;
990 class KTimeZoneLeapSecondsPrivate
1000 : d(new KTimeZoneLeapSecondsPrivate)
1005 : d(new KTimeZoneLeapSecondsPrivate)
1007 if (utc.timeSpec() == Qt::UTC)
1016 : d(new KTimeZoneLeapSecondsPrivate)
1019 d->comment = c.d->comment;
1020 d->seconds = c.d->seconds;
1031 d->comment = c.d->comment;
1032 d->seconds = c.d->seconds;
1038 return d->dt < c.d->dt;
1048 return d->dt.isValid();
1065 int KTimeZoneDataPrivate::transitionIndex(
const QDateTime &dt)
const
1070 if (dt.timeSpec() == Qt::UTC)
1072 while (end - start > 1)
1074 int i = (start + end) / 2;
1084 dtutc.setTimeSpec(Qt::UTC);
1085 while (end - start > 1)
1087 const int i = (start + end) / 2;
1094 return end ? start : -1;
1100 bool KTimeZoneDataPrivate::transitionIndexes(
const QDateTime &start,
const QDateTime &end,
int &ixstart,
int &ixend)
const
1103 if (start.isValid() && start.timeSpec() == Qt::UTC)
1115 if (end.isValid() && end.timeSpec() == Qt::UTC)
1130 if (transitionIndex < 0)
1133 const int prevoffset = (transitionIndex > 0) ?
transitions[transitionIndex-1].phase().utcOffset() : prePhase.utcOffset();
1134 const int phaseDiff = prevoffset -
offset;
1139 return (afterStart < phaseDiff);
1145 : d(new KTimeZoneDataPrivate)
1149 : d(new KTimeZoneDataPrivate)
1151 d->phases = c.d->phases;
1152 d->transitions = c.d->transitions;
1153 d->leapChanges = c.d->leapChanges;
1154 d->utcOffsets = c.d->utcOffsets;
1155 d->abbreviations = c.d->abbreviations;
1156 d->prePhase = c.d->prePhase;
1166 d->phases = c.d->phases;
1167 d->transitions = c.d->transitions;
1168 d->leapChanges = c.d->leapChanges;
1169 d->utcOffsets = c.d->utcOffsets;
1170 d->abbreviations = c.d->abbreviations;
1171 d->prePhase = c.d->prePhase;
1182 if (d->abbreviations.isEmpty())
1184 for (
int i = 0, end = d->phases.count(); i < end; ++i)
1187 for (
int j = 0, jend = abbrevs.count(); j < jend; ++j)
1188 if (!d->abbreviations.contains(abbrevs[j]))
1189 d->abbreviations.append(abbrevs[j]);
1191 if (d->abbreviations.isEmpty())
1192 d->abbreviations +=
"UTC";
1194 return d->abbreviations;
1199 if (d->phases.isEmpty())
1203 : d->prePhase.abbreviations();
1204 if (abbrevs.isEmpty())
1205 return QByteArray();
1211 if (d->utcOffsets.isEmpty())
1213 for (
int i = 0, end = d->phases.count(); i < end; ++i)
1215 const int offset = d->phases[i].utcOffset();
1216 if (!d->utcOffsets.contains(offset))
1217 d->utcOffsets.append(offset);
1219 if (d->utcOffsets.isEmpty())
1222 qSort(d->utcOffsets);
1224 return d->utcOffsets;
1235 d->prePhase = previousPhase;
1252 if (!d->transitionIndexes(start, end, ixstart, ixend))
1255 return d->transitions.mid(ixstart, ixend - ixstart + 1);
1257 return d->transitions.mid(ixstart);
1258 return d->transitions;
1268 return d->prePhase.utcOffset();
1272 bool *validTime)
const
1275 const int index =
transitionIndex(dt, (secondTransition ? &secondIndex : 0), validTime);
1276 if (secondTransition)
1277 *secondTransition = (secondIndex >= 0) ? &d->transitions[secondIndex] : 0;
1278 return (index >= 0) ? &d->transitions[index] : 0;
1287 int index = d->transitionIndex(dt);
1288 if (dt.timeSpec() == Qt::UTC)
1291 *secondIndex = index;
1301 dtutc.setTimeSpec(Qt::UTC);
1302 const int count = d->transitions.count();
1303 const int next = (index >= 0) ? index + 1 : 0;
1307 const int offset = (index >= 0) ? d->transitions[index].phase().utcOffset() : d->prePhase.utcOffset();
1308 const int phaseDiff = nextPhase.
utcOffset() - offset;
1312 if (dtutc.secsTo(d->transitions[next].time()) + nextPhase.
utcOffset() < phaseDiff)
1337 bool duplicate =
true;
1338 if (d->isSecondOccurrence(dtutc, index))
1343 *secondIndex = index;
1352 if (secondIndex && duplicate)
1353 *secondIndex = index;
1362 if (d->transitionIndexes(start, end, ixstart, ixend))
1365 ixend = d->transitions.count() - 1;
1366 while (ixstart <= ixend)
1368 if (d->transitions[ixstart].phase() == phase)
1369 times += d->transitions[ixstart].time();
1377 return d->leapChanges;
1382 d->leapChanges = adjusts;
1387 if (utc.timeSpec() != Qt::UTC)
1388 kError() <<
"KTimeZoneData::leapSecondChange(): non-UTC time specified" << endl;
1391 for (
int i = d->leapChanges.count(); --i >= 0; )
1393 if (d->leapChanges[i].dateTime() < utc)
1394 return d->leapChanges[i];