• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KDECore

ktimezone.cpp

Go to the documentation of this file.
00001 /*
00002    This file is part of the KDE libraries
00003    Copyright (c) 2005-2008 David Jarvie <djarvie@kde.org>
00004    Copyright (c) 2005 S.R.Haque <srhaque@iee.org>.
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License as published by the Free Software Foundation; either
00009    version 2 of the License, or (at your option) any later version.
00010 
00011    This library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this library; see the file COPYING.LIB.  If not, write to
00018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019    Boston, MA 02110-1301, USA.
00020 */
00021 
00022 // This file requires HAVE_STRUCT_TM_TM_ZONE to be defined if struct tm member tm_zone is available.
00023 // This file requires HAVE_TM_GMTOFF to be defined if struct tm member tm_gmtoff is available.
00024 
00025 #include "ktimezone.h"
00026 
00027 #include <config.h>
00028 
00029 #ifdef HAVE_SYS_TIME_H
00030 #include <sys/time.h>
00031 #endif
00032 #ifdef HAVE_TIME_H
00033 #include <time.h>
00034 #endif
00035 #include <climits>
00036 #include <cstdlib>
00037 
00038 #include <QtCore/QSet>
00039 #include <QtCore/QSharedData>
00040 #include <QtCore/QCoreApplication>
00041 
00042 #include <kdebug.h>
00043 
00044 int gmtoff(time_t t);   // defined in ksystemtimezone.cpp
00045 
00046 
00047 /******************************************************************************/
00048 
00049 class KTimeZonesPrivate
00050 {
00051 public:
00052     KTimeZonesPrivate() {}
00053 
00054     KTimeZones::ZoneMap zones;
00055 };
00056 
00057 
00058 KTimeZones::KTimeZones()
00059   : d(new KTimeZonesPrivate)
00060 {
00061 }
00062 
00063 KTimeZones::~KTimeZones()
00064 {
00065     delete d;
00066 }
00067 
00068 const KTimeZones::ZoneMap KTimeZones::zones() const
00069 {
00070     return d->zones;
00071 }
00072 
00073 bool KTimeZones::add(const KTimeZone &zone)
00074 {
00075     if (!zone.isValid())
00076         return false;
00077     if (d->zones.find(zone.name()) != d->zones.end())
00078         return false;    // name already exists
00079     d->zones.insert(zone.name(), zone);
00080     return true;
00081 }
00082 
00083 KTimeZone KTimeZones::remove(const KTimeZone &zone)
00084 {
00085     if (zone.isValid())
00086     {
00087         for (ZoneMap::Iterator it = d->zones.begin(), end = d->zones.end();  it != end;  ++it)
00088         {
00089             if (it.value() == zone)
00090             {
00091                 d->zones.erase(it);
00092                 return zone;
00093             }
00094         }
00095     }
00096     return KTimeZone();
00097 }
00098 
00099 KTimeZone KTimeZones::remove(const QString &name)
00100 {
00101     if (!name.isEmpty())
00102     {
00103         ZoneMap::Iterator it = d->zones.find(name);
00104         if (it != d->zones.end())
00105         {
00106             KTimeZone zone = it.value();
00107             d->zones.erase(it);
00108             return zone;
00109         }
00110     }
00111     return KTimeZone();
00112 }
00113 
00114 void KTimeZones::clear()
00115 {
00116   d->zones.clear();
00117 }
00118 
00119 KTimeZone KTimeZones::zone(const QString &name) const
00120 {
00121 #ifdef Q_WS_WIN
00122     // return always the utc for now
00123     return KTimeZone::utc();
00124 #else
00125     if (!name.isEmpty())
00126     {
00127         ZoneMap::ConstIterator it = d->zones.find(name);
00128         if (it != d->zones.end())
00129             return it.value();
00130         if (name == KTimeZone::utc().name())
00131             return KTimeZone::utc();
00132     }
00133     return KTimeZone();    // error
00134 #endif
00135 }
00136 
00137 
00138 /******************************************************************************/
00139 
00140 class KTimeZonePhasePrivate : public QSharedData
00141 {
00142     public:
00143         QByteArray       abbreviations;  // time zone abbreviations (zero-delimited)
00144         QString          comment;        // optional comment
00145         int              utcOffset;      // seconds to add to UTC
00146         bool             dst;            // true if daylight savings time
00147 
00148         explicit KTimeZonePhasePrivate(int offset = 0, bool ds = false)
00149         : QSharedData(),
00150           utcOffset(offset),
00151           dst(ds)
00152         {}
00153         KTimeZonePhasePrivate(const KTimeZonePhasePrivate& rhs)
00154         : QSharedData(rhs),
00155           abbreviations(rhs.abbreviations),
00156           comment(rhs.comment),
00157           utcOffset(rhs.utcOffset),
00158           dst(rhs.dst)
00159         {}
00160         bool operator==(const KTimeZonePhasePrivate &rhs) const
00161         {
00162             return abbreviations == rhs.abbreviations
00163                &&  comment       == rhs.comment
00164                &&  utcOffset     == rhs.utcOffset
00165                &&  dst           == rhs.dst;
00166         }
00167 };
00168 
00169 
00170 KTimeZone::Phase::Phase()
00171   : d(new KTimeZonePhasePrivate)
00172 {
00173 }
00174 
00175 KTimeZone::Phase::Phase(int utcOffset, const QByteArray &abbrevs,
00176                         bool dst, const QString &cmt)
00177   : d(new KTimeZonePhasePrivate(utcOffset, dst))
00178 {
00179     d->abbreviations = abbrevs;
00180     d->comment       = cmt;
00181 }
00182 
00183 KTimeZone::Phase::Phase(int utcOffset, const QList<QByteArray> &abbrevs,
00184                         bool dst, const QString &cmt)
00185   : d(new KTimeZonePhasePrivate(utcOffset, dst))
00186 {
00187     for (int i = 0, end = abbrevs.count();  i < end;  ++i)
00188     {
00189         if (i > 0)
00190             d->abbreviations += '\0';
00191         d->abbreviations += abbrevs[i];
00192     }
00193     d->comment = cmt;
00194 }
00195 
00196 KTimeZone::Phase::Phase(const KTimeZone::Phase &rhs)
00197   : d(rhs.d)
00198 {
00199 }
00200 
00201 KTimeZone::Phase::~Phase()
00202 {
00203 }
00204 
00205 KTimeZone::Phase &KTimeZone::Phase::operator=(const KTimeZone::Phase &rhs)
00206 {
00207     d = rhs.d;
00208     return *this;
00209 }
00210 
00211 bool KTimeZone::Phase::operator==(const KTimeZone::Phase &rhs) const
00212 {
00213     return d == rhs.d  ||  *d == *rhs.d;
00214 }
00215 
00216 int KTimeZone::Phase::utcOffset() const
00217 {
00218     return d->utcOffset;
00219 }
00220 
00221 QList<QByteArray> KTimeZone::Phase::abbreviations() const
00222 {
00223     return d->abbreviations.split('\0');
00224 }
00225 
00226 bool KTimeZone::Phase::isDst() const
00227 {
00228     return d->dst;
00229 }
00230 
00231 QString KTimeZone::Phase::comment() const
00232 {
00233     return d->comment;
00234 }
00235 
00236 
00237 /******************************************************************************/
00238 
00239 class KTimeZoneTransitionPrivate
00240 {
00241 public:
00242     QDateTime time;
00243     KTimeZone::Phase phase;
00244 };
00245 
00246 
00247 KTimeZone::Transition::Transition()
00248     : d(new KTimeZoneTransitionPrivate)
00249 {
00250 }
00251 
00252 KTimeZone::Transition::Transition(const QDateTime &t, const KTimeZone::Phase &p) 
00253     : d(new KTimeZoneTransitionPrivate)
00254 {
00255     d->time  = t;
00256     d->phase = p;
00257 }
00258 
00259 KTimeZone::Transition::Transition(const KTimeZone::Transition &t)
00260     : d(new KTimeZoneTransitionPrivate)
00261 {
00262     d->time  = t.d->time;
00263     d->phase = t.d->phase;
00264 }
00265 
00266 KTimeZone::Transition::~Transition()
00267 {
00268     delete d;
00269 }
00270 
00271 KTimeZone::Transition &KTimeZone::Transition::operator=(const KTimeZone::Transition &t)
00272 {
00273     d->time  = t.d->time;
00274     d->phase = t.d->phase;
00275     return *this;
00276 }
00277 
00278 bool KTimeZone::Transition::operator<(const KTimeZone::Transition &rhs) const
00279 {
00280     return d->time < rhs.d->time;
00281 }
00282 
00283 QDateTime        KTimeZone::Transition::time() const   { return d->time; }
00284 KTimeZone::Phase KTimeZone::Transition::phase() const  { return d->phase; }
00285 
00286 
00287 /******************************************************************************/
00288 
00289 class KTimeZoneDataPrivate
00290 {
00291     public:
00292         QList<KTimeZone::Phase>       phases;
00293         QList<KTimeZone::Transition>  transitions;
00294         QList<KTimeZone::LeapSeconds> leapChanges;
00295         QList<int>                    utcOffsets;
00296         QList<QByteArray>             abbreviations;
00297         int preUtcOffset;    // UTC offset to use before the first phase
00298 
00299         KTimeZoneDataPrivate() : preUtcOffset(0) {}
00300         // Find the last transition before a specified UTC or local date/time.
00301         int transitionIndex(const QDateTime &dt) const;
00302         bool transitionIndexes(const QDateTime &start, const QDateTime &end, int &ixstart, int &ixend) const;
00303         bool isSecondOccurrence(const QDateTime &utcLocalTime, int transitionIndex) const;
00304 };
00305 
00306 
00307 /******************************************************************************/
00308 
00309 class KTimeZonePrivate : public QSharedData
00310 {
00311 public:
00312     KTimeZonePrivate() : source(0), data(0), refCount(1) {}
00313     KTimeZonePrivate(KTimeZoneSource *src, const QString& nam,
00314                      const QString &country, float lat, float lon, const QString &cmnt);
00315     KTimeZonePrivate(const KTimeZonePrivate &);
00316     ~KTimeZonePrivate()  { delete data; }
00317     KTimeZonePrivate &operator=(const KTimeZonePrivate &);
00318     static KTimeZoneSource *utcSource();
00319     static void cleanup();
00320 
00321     KTimeZoneSource *source;
00322     QString name;
00323     QString countryCode;
00324     QString comment;
00325     float   latitude;
00326     float   longitude;
00327     mutable KTimeZoneData *data;
00328     int refCount;
00329 
00330 private:
00331     static KTimeZoneSource *mUtcSource;
00332 };
00333 
00334 KTimeZoneSource *KTimeZonePrivate::mUtcSource = 0;
00335 
00336 
00337 KTimeZonePrivate::KTimeZonePrivate(KTimeZoneSource *src, const QString& nam,
00338                  const QString &country, float lat, float lon, const QString &cmnt)
00339   : source(src),
00340     name(nam),
00341     countryCode(country.toUpper()),
00342     comment(cmnt),
00343     latitude(lat),
00344     longitude(lon),
00345     data(0),
00346     refCount(1)
00347 {
00348     // Detect duff values.
00349     if ( latitude > 90 || latitude < -90 )
00350         latitude = KTimeZone::UNKNOWN;
00351     if ( longitude > 180 || longitude < -180 )
00352         longitude = KTimeZone::UNKNOWN;
00353 }
00354 
00355 KTimeZonePrivate::KTimeZonePrivate(const KTimeZonePrivate &rhs)
00356     : QSharedData(rhs),
00357       source(rhs.source),
00358       name(rhs.name),
00359       countryCode(rhs.countryCode),
00360       comment(rhs.comment),
00361       latitude(rhs.latitude),
00362       longitude(rhs.longitude)
00363 {
00364     if (rhs.data)
00365         data = rhs.data->clone();
00366     else
00367         data = 0;
00368 }
00369 
00370 KTimeZonePrivate &KTimeZonePrivate::operator=(const KTimeZonePrivate &rhs)
00371 {
00372     source      = rhs.source;
00373     name        = rhs.name;
00374     countryCode = rhs.countryCode;
00375     comment     = rhs.comment;
00376     latitude    = rhs.latitude;
00377     longitude   = rhs.longitude;
00378     delete data;
00379     if (rhs.data)
00380         data = rhs.data->clone();
00381     else
00382         data = 0;
00383     return *this;
00384 }
00385 
00386 KTimeZoneSource *KTimeZonePrivate::utcSource()
00387 {
00388     if (!mUtcSource)
00389     {
00390         mUtcSource = new KTimeZoneSource;
00391         qAddPostRoutine(KTimeZonePrivate::cleanup);
00392     }
00393     return mUtcSource;
00394 }
00395 
00396 void KTimeZonePrivate::cleanup()
00397 {
00398     delete mUtcSource;
00399 }
00400 
00401 
00402 /******************************************************************************/
00403 
00404 KTimeZoneBackend::KTimeZoneBackend()
00405   : d(new KTimeZonePrivate)
00406 {}
00407 
00408 KTimeZoneBackend::KTimeZoneBackend(const QString &name)
00409   : d(new KTimeZonePrivate(KTimeZonePrivate::utcSource(), name, QString(), KTimeZone::UNKNOWN, KTimeZone::UNKNOWN, QString()))
00410 {}
00411 
00412 KTimeZoneBackend::KTimeZoneBackend(KTimeZoneSource *source, const QString &name,
00413         const QString &countryCode, float latitude, float longitude, const QString &comment)
00414   : d(new KTimeZonePrivate(source, name, countryCode, latitude, longitude, comment))
00415 {}
00416 
00417 KTimeZoneBackend::KTimeZoneBackend(const KTimeZoneBackend &other)
00418   : d(other.d)
00419 {
00420     ++d->refCount;
00421 }
00422   
00423 KTimeZoneBackend::~KTimeZoneBackend()
00424 {
00425     if (d && --d->refCount == 0)
00426         delete d;
00427     d = 0;
00428 }
00429 
00430 KTimeZoneBackend &KTimeZoneBackend::operator=(const KTimeZoneBackend &other)
00431 {
00432     if (d != other.d)
00433     {
00434         if (--d->refCount == 0)
00435             delete d;
00436         d = other.d;
00437         ++d->refCount;
00438     }
00439     return *this;
00440 }
00441 
00442 QByteArray KTimeZoneBackend::type() const
00443 {
00444     return "KTimeZone";
00445 }
00446 
00447 KTimeZoneBackend *KTimeZoneBackend::clone() const
00448 {
00449     return new KTimeZoneBackend(*this);
00450 }
00451 
00452 int KTimeZoneBackend::offsetAtZoneTime(const KTimeZone* caller, const QDateTime &zoneDateTime, int *secondOffset) const
00453 {
00454     if (!zoneDateTime.isValid()  ||  zoneDateTime.timeSpec() != Qt::LocalTime)    // check for invalid time
00455     {
00456         if (secondOffset)
00457             *secondOffset = 0;
00458         return 0;
00459     }
00460     bool validTime;
00461     if (secondOffset)
00462     {
00463         const KTimeZone::Transition *tr2;
00464         const KTimeZone::Transition *tr = caller->transition(zoneDateTime, &tr2, &validTime);
00465         if (!tr)
00466         {
00467             if (!validTime)
00468                 *secondOffset = KTimeZone::InvalidOffset;
00469             else
00470                 *secondOffset = d->data ? d->data->previousUtcOffset() : 0;
00471             return *secondOffset;
00472         }
00473         int offset = tr->phase().utcOffset();
00474         *secondOffset = tr2 ? tr2->phase().utcOffset() : offset;
00475         return offset;
00476     }
00477     else
00478     {
00479         const KTimeZone::Transition *tr = caller->transition(zoneDateTime, 0, &validTime);
00480         if (!tr)
00481         {
00482             if (!validTime)
00483                 return KTimeZone::InvalidOffset;
00484             return d->data ? d->data->previousUtcOffset() : 0;
00485         }
00486         return tr->phase().utcOffset();
00487     }
00488 }
00489 
00490 int KTimeZoneBackend::offsetAtUtc(const KTimeZone* caller, const QDateTime &utcDateTime) const
00491 {
00492     if (!utcDateTime.isValid()  ||  utcDateTime.timeSpec() != Qt::UTC)    // check for invalid time
00493         return 0;
00494     const KTimeZone::Transition *tr = caller->transition(utcDateTime);
00495     if (!tr)
00496         return d->data ? d->data->previousUtcOffset() : 0;
00497     return tr->phase().utcOffset();
00498 }
00499 
00500 int KTimeZoneBackend::offset(const KTimeZone* caller, time_t t) const
00501 {
00502     return offsetAtUtc(caller, KTimeZone::fromTime_t(t));
00503 }
00504 
00505 bool KTimeZoneBackend::isDstAtUtc(const KTimeZone* caller, const QDateTime &utcDateTime) const
00506 {
00507     if (!utcDateTime.isValid()  ||  utcDateTime.timeSpec() != Qt::UTC)    // check for invalid time
00508         return false;
00509     const KTimeZone::Transition *tr = caller->transition(utcDateTime);
00510     if (!tr)
00511         return false;
00512     return tr->phase().isDst();
00513 }
00514 
00515 bool KTimeZoneBackend::isDst(const KTimeZone* caller, time_t t) const
00516 {
00517     return isDstAtUtc(caller, KTimeZone::fromTime_t(t));
00518 }
00519 
00520 bool KTimeZoneBackend::hasTransitions(const KTimeZone* caller) const
00521 {
00522     Q_UNUSED(caller);
00523     return false;
00524 }
00525 
00526 
00527 /******************************************************************************/
00528 
00529 #if SIZEOF_TIME_T == 8
00530 const time_t KTimeZone::InvalidTime_t = 0x800000000000000LL;
00531 #else
00532 const time_t KTimeZone::InvalidTime_t = 0x80000000;
00533 #endif
00534 const int    KTimeZone::InvalidOffset = 0x80000000;
00535 const float  KTimeZone::UNKNOWN = 1000.0;
00536 
00537 
00538 KTimeZone::KTimeZone()
00539   : d(new KTimeZoneBackend())
00540 {}
00541 
00542 KTimeZone::KTimeZone(const QString &name)
00543   : d(new KTimeZoneBackend(name))
00544 {}
00545 
00546 KTimeZone::KTimeZone(const KTimeZone &tz)
00547   : d(tz.d->clone())
00548 {}
00549 
00550 KTimeZone::~KTimeZone()
00551 {
00552     delete d;
00553 }
00554 
00555 KTimeZone::KTimeZone(KTimeZoneBackend *impl)
00556   : d(impl)
00557 {
00558     // 'impl' should be a newly constructed object, with refCount = 1
00559     Q_ASSERT(d->d->refCount == 1);
00560 }
00561 
00562 KTimeZone &KTimeZone::operator=(const KTimeZone &tz)
00563 {
00564     if (d != tz.d)
00565     {
00566         delete d;
00567         d = tz.d->clone();
00568     }
00569     return *this;
00570 }
00571 
00572 bool KTimeZone::operator==(const KTimeZone &rhs) const
00573 {
00574     return d->d == rhs.d->d;
00575 }
00576 
00577 QByteArray KTimeZone::type() const
00578 {
00579     return d->type();
00580 }
00581 
00582 bool KTimeZone::isValid() const
00583 {
00584     return !d->d->name.isEmpty();
00585 }
00586 
00587 QString KTimeZone::countryCode() const
00588 {
00589     return d->d->countryCode;
00590 }
00591 
00592 float KTimeZone::latitude() const
00593 {
00594     return d->d->latitude;
00595 }
00596 
00597 float KTimeZone::longitude() const
00598 {
00599     return d->d->longitude;
00600 }
00601 
00602 QString KTimeZone::comment() const
00603 {
00604     return d->d->comment;
00605 }
00606 
00607 QString KTimeZone::name() const
00608 {
00609     return d->d->name;
00610 }
00611 
00612 QList<QByteArray> KTimeZone::abbreviations() const
00613 {
00614     if (!data(true))
00615         return QList<QByteArray>();
00616     return d->d->data->abbreviations();
00617 }
00618 
00619 QByteArray KTimeZone::abbreviation(const QDateTime &utcDateTime) const
00620 {
00621     if (utcDateTime.timeSpec() != Qt::UTC  ||  !data(true))
00622         return QByteArray();
00623     return d->d->data->abbreviation(utcDateTime);
00624 }
00625 
00626 QList<int> KTimeZone::utcOffsets() const
00627 {
00628     if (!data(true))
00629         return QList<int>();
00630     return d->d->data->utcOffsets();
00631 }
00632 
00633 QList<KTimeZone::Phase> KTimeZone::phases() const
00634 {
00635     if (!data(true))
00636         return QList<KTimeZone::Phase>();
00637     return d->d->data->phases();
00638 }
00639 
00640 bool KTimeZone::hasTransitions() const
00641 {
00642     return d->hasTransitions(this);
00643 }
00644 
00645 QList<KTimeZone::Transition> KTimeZone::transitions(const QDateTime &start, const QDateTime &end) const
00646 {
00647     if (!data(true))
00648         return QList<KTimeZone::Transition>();
00649     return d->d->data->transitions(start, end);
00650 }
00651 
00652 const KTimeZone::Transition *KTimeZone::transition(const QDateTime &dt, const Transition **secondTransition,
00653                                                    bool *validTime ) const
00654 {
00655     if (!data(true))
00656         return 0;
00657     return d->d->data->transition(dt, secondTransition, validTime);
00658 }
00659 
00660 int KTimeZone::transitionIndex(const QDateTime &dt, int *secondIndex, bool *validTime) const
00661 {
00662     if (!data(true))
00663         return -1;
00664     return d->d->data->transitionIndex(dt, secondIndex, validTime);
00665 }
00666 
00667 QList<QDateTime> KTimeZone::transitionTimes(const Phase &phase, const QDateTime &start, const QDateTime &end) const
00668 {
00669     if (!data(true))
00670         return QList<QDateTime>();
00671     return d->d->data->transitionTimes(phase, start, end);
00672 }
00673 
00674 QList<KTimeZone::LeapSeconds> KTimeZone::leapSecondChanges() const
00675 {
00676     if (!data(true))
00677         return QList<KTimeZone::LeapSeconds>();
00678     return d->d->data->leapSecondChanges();
00679 }
00680 
00681 KTimeZoneSource *KTimeZone::source() const
00682 {
00683     return d->d->source;
00684 }
00685 
00686 const KTimeZoneData *KTimeZone::data(bool create) const
00687 {
00688     if (!isValid())
00689         return 0;
00690     if (create && !d->d->data && d->d->source->useZoneParse())
00691         d->d->data = d->d->source->parse(*this);
00692     return d->d->data;
00693 }
00694 
00695 void KTimeZone::setData(KTimeZoneData *data, KTimeZoneSource *source)
00696 {
00697     if (!isValid())
00698         return;
00699     if (d->d->data)
00700         delete d->d->data;
00701     d->d->data = data;
00702     if (source)
00703         d->d->source = source;
00704 }
00705 
00706 bool KTimeZone::updateBase(const KTimeZone &other)
00707 {
00708     if (d->d->name.isEmpty() || d->d->name != other.d->d->name)
00709         return false;
00710     d->d->countryCode = other.d->d->countryCode;
00711     d->d->comment     = other.d->d->comment;
00712     d->d->latitude    = other.d->d->latitude;
00713     d->d->longitude   = other.d->d->longitude;
00714     return true;
00715 }
00716 
00717 bool KTimeZone::parse() const
00718 {
00719     if (!isValid())
00720         return false;
00721     if (d->d->source->useZoneParse())
00722     {
00723         delete d->d->data;
00724         d->d->data = d->d->source->parse(*this);
00725     }
00726     return d->d->data;
00727 }
00728 
00729 QDateTime KTimeZone::toUtc(const QDateTime &zoneDateTime) const
00730 {
00731     if (!zoneDateTime.isValid()  ||  zoneDateTime.timeSpec() != Qt::LocalTime)
00732         return QDateTime();
00733     int secs = offsetAtZoneTime(zoneDateTime);
00734     if (secs == InvalidOffset)
00735         return QDateTime();
00736     QDateTime dt = zoneDateTime;
00737     dt.setTimeSpec(Qt::UTC);
00738     return dt.addSecs(-secs);
00739 }
00740 
00741 QDateTime KTimeZone::toZoneTime(const QDateTime &utcDateTime, bool *secondOccurrence) const
00742 {
00743     if (secondOccurrence)
00744         *secondOccurrence = false;
00745     if (!utcDateTime.isValid()  ||  utcDateTime.timeSpec() != Qt::UTC)    // check for invalid time
00746         return QDateTime();
00747 
00748     // Convert UTC to local time
00749     if (hasTransitions())
00750     {
00751         if (!data(true))
00752         {
00753             // No data - default to UTC
00754             QDateTime dt = utcDateTime;
00755             dt.setTimeSpec(Qt::LocalTime);
00756             return dt;
00757         }
00758 
00759         int index = d->d->data->transitionIndex(utcDateTime);
00760         int secs = (index >= 0) ? d->d->data->transitions()[index].phase().utcOffset() : d->d->data->previousUtcOffset();
00761         QDateTime dt = utcDateTime.addSecs(secs);
00762         if (secondOccurrence)
00763         {
00764             // Check whether the local time occurs twice around a daylight savings time
00765             // shift, and if so, whether it's the first or second occurrence.
00766             *secondOccurrence = d->d->data->d->isSecondOccurrence(dt, index);
00767         }
00768         dt.setTimeSpec(Qt::LocalTime);
00769         return dt;
00770     }
00771     else
00772     {
00773         int secs = offsetAtUtc(utcDateTime);
00774         QDateTime dt = utcDateTime.addSecs(secs);
00775         dt.setTimeSpec(Qt::LocalTime);
00776         if (secondOccurrence)
00777         {
00778             // Check whether the local time occurs twice around a daylight savings time
00779             // shift, and if so, whether it's the first or second occurrence.
00780             *secondOccurrence = (secs != offsetAtZoneTime(dt));
00781         }
00782         return dt;
00783     }
00784 }
00785 
00786 QDateTime KTimeZone::convert(const KTimeZone &newZone, const QDateTime &zoneDateTime) const
00787 {
00788     if (newZone == *this)
00789     {
00790         if (zoneDateTime.timeSpec() != Qt::LocalTime)
00791             return QDateTime();
00792         return zoneDateTime;
00793     }
00794     return newZone.toZoneTime(toUtc(zoneDateTime));
00795 }
00796 
00797 int KTimeZone::offsetAtZoneTime(const QDateTime &zoneDateTime, int *secondOffset) const
00798 {
00799     return d->offsetAtZoneTime(this, zoneDateTime, secondOffset);
00800 }
00801 
00802 int KTimeZone::offsetAtUtc(const QDateTime &utcDateTime) const
00803 {
00804     return d->offsetAtUtc(this, utcDateTime);
00805 }
00806 
00807 int KTimeZone::offset(time_t t) const
00808 {
00809     return d->offset(this, t);
00810 }
00811 
00812 int KTimeZone::currentOffset(Qt::TimeSpec basis) const
00813 {
00814     // Get current offset of this time zone to UTC
00815     time_t now = time(0);
00816     int secs = offset(now);
00817 
00818     switch (basis)
00819     {
00820         case Qt::LocalTime:
00821             // Return the current offset of this time zone to the local system time
00822             return secs - gmtoff(now);
00823         case Qt::UTC:
00824             // Return the current offset of this time zone to UTC
00825             return secs;
00826 
00827         default:
00828             break;
00829     }
00830     return 0;
00831 }
00832 
00833 bool KTimeZone::isDstAtUtc(const QDateTime &utcDateTime) const
00834 {
00835     return d->isDstAtUtc(this, utcDateTime);
00836 }
00837 
00838 bool KTimeZone::isDst(time_t t) const
00839 {
00840     return d->isDst(this, t);
00841 }
00842 
00843 KTimeZone KTimeZone::utc()
00844 {
00845     static KTimeZone utcZone(QLatin1String("UTC"));
00846     return utcZone;
00847 }
00848 
00849 QDateTime KTimeZone::fromTime_t(time_t t)
00850 {
00851     static QDate epochDate(1970,1,1);
00852     static QTime epochTime(0,0,0);
00853     int days = t / 86400;
00854     int secs;
00855     if (t >= 0)
00856         secs = t % 86400;
00857     else
00858     {
00859         secs = 86400 - (-t % 86400);
00860         --days;
00861     }
00862     return QDateTime(epochDate.addDays(days), epochTime.addSecs(secs), Qt::UTC);
00863 }
00864 
00865 time_t KTimeZone::toTime_t(const QDateTime &utcDateTime)
00866 {
00867     static QDate epochDate(1970,1,1);
00868     static QTime epochTime(0,0,0);
00869     if (utcDateTime.timeSpec() != Qt::UTC)
00870         return InvalidTime_t;
00871     qint64 days = epochDate.daysTo(utcDateTime.date());
00872     qint64 secs = epochTime.secsTo(utcDateTime.time());
00873     qint64 t64 = days * 86400 + secs;
00874     time_t t = static_cast<time_t>(t64);
00875     if (static_cast<qint64>(t) != t64)
00876         return InvalidTime_t;
00877     return t;
00878 }
00879 
00880 
00881 /******************************************************************************/
00882 
00883 class KTimeZoneSourcePrivate
00884 {
00885 public:
00886     bool mUseZoneParse;
00887 };
00888 
00889 
00890 KTimeZoneSource::KTimeZoneSource()
00891   : d(new KTimeZoneSourcePrivate)
00892 {
00893     d->mUseZoneParse = true;
00894 }
00895 
00896 KTimeZoneSource::KTimeZoneSource(bool useZoneParse)
00897   : d(new KTimeZoneSourcePrivate)
00898 {
00899     d->mUseZoneParse = useZoneParse;
00900 }
00901 
00902 KTimeZoneSource::~KTimeZoneSource()
00903 {
00904     delete d;
00905 }
00906 
00907 KTimeZoneData *KTimeZoneSource::parse(const KTimeZone &) const
00908 {
00909     Q_ASSERT(d->mUseZoneParse);  // method should never be called if it isn't usable
00910     return new KTimeZoneData;
00911 }
00912 
00913 bool KTimeZoneSource::useZoneParse() const
00914 {
00915     return d->mUseZoneParse;
00916 }
00917 
00918 
00919 /******************************************************************************/
00920 
00921 class KTimeZoneLeapSecondsPrivate
00922 {
00923     public:
00924         QDateTime  dt;         // UTC time when this change occurred
00925         QString    comment;    // optional comment
00926         int        seconds;    // number of leap seconds
00927 };
00928 
00929 
00930 KTimeZone::LeapSeconds::LeapSeconds()
00931   : d(new KTimeZoneLeapSecondsPrivate)
00932 {
00933 }
00934 
00935 KTimeZone::LeapSeconds::LeapSeconds(const QDateTime &utc, int leap, const QString &cmt)
00936   : d(new KTimeZoneLeapSecondsPrivate)
00937 {
00938     if (utc.timeSpec() == Qt::UTC)   // invalid if start time is not UTC
00939     {
00940         d->dt      = utc;
00941         d->comment = cmt;
00942         d->seconds = leap;
00943     }
00944 }
00945 
00946 KTimeZone::LeapSeconds::LeapSeconds(const KTimeZone::LeapSeconds &c)
00947   : d(new KTimeZoneLeapSecondsPrivate)
00948 {
00949     d->dt      = c.d->dt;
00950     d->comment = c.d->comment;
00951     d->seconds = c.d->seconds;
00952 }
00953 
00954 KTimeZone::LeapSeconds::~LeapSeconds()
00955 {
00956     delete d;
00957 }
00958 
00959 KTimeZone::LeapSeconds &KTimeZone::LeapSeconds::operator=(const KTimeZone::LeapSeconds &c)
00960 {
00961     d->dt      = c.d->dt;
00962     d->comment = c.d->comment;
00963     d->seconds = c.d->seconds;
00964     return *this;
00965 }
00966 
00967 bool KTimeZone::LeapSeconds::operator<(const KTimeZone::LeapSeconds& c) const
00968 {
00969     return d->dt < c.d->dt;
00970 }
00971 
00972 QDateTime KTimeZone::LeapSeconds::dateTime() const
00973 {
00974     return d->dt;
00975 }
00976 
00977 bool KTimeZone::LeapSeconds::isValid() const
00978 {
00979     return d->dt.isValid();
00980 }
00981 
00982 int KTimeZone::LeapSeconds::leapSeconds() const
00983 {
00984     return d->seconds;
00985 }
00986 
00987 QString KTimeZone::LeapSeconds::comment() const
00988 {
00989     return d->comment;
00990 }
00991 
00992 
00993 /******************************************************************************/
00994 
00995 
00996 int KTimeZoneDataPrivate::transitionIndex(const QDateTime &dt) const
00997 {
00998     // Do a binary search to find the last transition before this date/time
00999     int start = -1;
01000     int end = transitions.count();
01001     if (dt.timeSpec() == Qt::UTC)
01002     {
01003         while (end - start > 1)
01004         {
01005             int i = (start + end) / 2;
01006             if (dt < transitions[i].time())
01007                 end = i;
01008             else
01009                 start = i;
01010         }
01011     }
01012     else
01013     {
01014         QDateTime dtutc = dt;
01015         dtutc.setTimeSpec(Qt::UTC);
01016         while (end - start > 1)
01017         {
01018             int i = (start + end) / 2;
01019             if (dtutc.addSecs(-transitions[i].phase().utcOffset()) < transitions[i].time())
01020                 end = i;
01021             else
01022                 start = i;
01023         }
01024     }
01025     return end ? start : -1;
01026 }
01027 
01028 // Find the indexes to the transitions at or after start, and before or at end.
01029 // start and end must be UTC.
01030 // Reply = false if none.
01031 bool KTimeZoneDataPrivate::transitionIndexes(const QDateTime &start, const QDateTime &end, int &ixstart, int &ixend) const
01032 {
01033     ixstart = 0;
01034     if (start.isValid() && start.timeSpec() == Qt::UTC)
01035     {
01036         ixstart = transitionIndex(start);
01037         if (ixstart < 0)
01038             ixstart = 0;
01039         else if (transitions[ixstart].time() < start)
01040         {
01041             if (++ixstart >= transitions.count())
01042                 return false;   // there are no transitions at/after 'start'
01043         }
01044     }
01045     ixend = -1;
01046     if (end.isValid() && end.timeSpec() == Qt::UTC)
01047     {
01048         ixend = transitionIndex(end);
01049         if (ixend < 0)
01050             return false;   // there are no transitions at/before 'end'
01051     }
01052     return true;
01053 }
01054 
01055 /* Check if it's a local time which occurs both before and after the specified
01056  * transition (for which it has to span a daylight saving to standard time change).
01057  * @param utcLocalTime local time set to Qt::UTC
01058  */
01059 bool KTimeZoneDataPrivate::isSecondOccurrence(const QDateTime &utcLocalTime, int transitionIndex) const
01060 {
01061     if (transitionIndex < 0)
01062         return false;
01063     int offset = transitions[transitionIndex].phase().utcOffset();
01064     int prevoffset = (transitionIndex > 0) ? transitions[transitionIndex-1].phase().utcOffset() : preUtcOffset;
01065     int phaseDiff = prevoffset - offset;
01066     if (phaseDiff <= 0)
01067         return false;
01068     // Find how long after the start of the latest phase 'dt' is
01069     int afterStart = transitions[transitionIndex].time().secsTo(utcLocalTime) - offset;
01070     return (afterStart < phaseDiff);
01071 }
01072 
01073 
01074 
01075 KTimeZoneData::KTimeZoneData()
01076   : d(new KTimeZoneDataPrivate)
01077 { }
01078 
01079 KTimeZoneData::KTimeZoneData(const KTimeZoneData &c)
01080   : d(new KTimeZoneDataPrivate)
01081 {
01082     d->phases        = c.d->phases;
01083     d->transitions   = c.d->transitions;
01084     d->leapChanges   = c.d->leapChanges;
01085     d->utcOffsets    = c.d->utcOffsets;
01086     d->abbreviations = c.d->abbreviations;
01087     d->preUtcOffset  = c.d->preUtcOffset;
01088 }
01089 
01090 KTimeZoneData::~KTimeZoneData()
01091 {
01092     delete d;
01093 }
01094 
01095 KTimeZoneData &KTimeZoneData::operator=(const KTimeZoneData &c)
01096 {
01097     d->phases        = c.d->phases;
01098     d->transitions   = c.d->transitions;
01099     d->leapChanges   = c.d->leapChanges;
01100     d->utcOffsets    = c.d->utcOffsets;
01101     d->abbreviations = c.d->abbreviations;
01102     d->preUtcOffset  = c.d->preUtcOffset;
01103     return *this;
01104 }
01105 
01106 KTimeZoneData *KTimeZoneData::clone() const
01107 {
01108     return new KTimeZoneData(*this);
01109 }
01110 
01111 QList<QByteArray> KTimeZoneData::abbreviations() const
01112 {
01113     if (d->abbreviations.isEmpty())
01114     {
01115         for (int i = 0, end = d->phases.count();  i < end;  ++i)
01116         {
01117             const QList<QByteArray> abbrevs = d->phases[i].abbreviations();
01118             for (int j = 0, jend = abbrevs.count();  j < jend;  ++j)
01119                 if (!d->abbreviations.contains(abbrevs[j]))
01120                     d->abbreviations.append(abbrevs[j]);
01121         }
01122         if (d->abbreviations.isEmpty())
01123             d->abbreviations += "UTC";
01124     }
01125     return d->abbreviations;
01126 }
01127 
01128 QByteArray KTimeZoneData::abbreviation(const QDateTime &utcDateTime) const
01129 {
01130     if (d->phases.isEmpty())
01131         return "UTC";
01132     const KTimeZone::Transition *tr = transition(utcDateTime);
01133     if (!tr)
01134         return QByteArray();
01135     const QList<QByteArray> abbrevs = tr->phase().abbreviations();
01136     if (abbrevs.isEmpty())
01137         return QByteArray();
01138     return abbrevs[0];
01139 }
01140 
01141 QList<int> KTimeZoneData::utcOffsets() const
01142 {
01143     if (d->utcOffsets.isEmpty())
01144     {
01145         for (int i = 0, end = d->phases.count();  i < end;  ++i)
01146         {
01147             int offset = d->phases[i].utcOffset();
01148             if (!d->utcOffsets.contains(offset))
01149                 d->utcOffsets.append(offset);
01150         }
01151         if (d->utcOffsets.isEmpty())
01152             d->utcOffsets += 0;
01153         else
01154             qSort(d->utcOffsets);
01155     }
01156     return d->utcOffsets;
01157 }
01158 
01159 QList<KTimeZone::Phase> KTimeZoneData::phases() const
01160 {
01161     return d->phases;
01162 }
01163 
01164 void KTimeZoneData::setPhases(const QList<KTimeZone::Phase> &phases, int previousUtcOffset)
01165 {
01166     d->phases = phases;
01167     d->preUtcOffset = previousUtcOffset;
01168 }
01169 
01170 bool KTimeZoneData::hasTransitions() const
01171 {
01172     return false;
01173 }
01174 
01175 QList<KTimeZone::Transition> KTimeZoneData::transitions(const QDateTime &start, const QDateTime &end) const
01176 {
01177     int ixstart, ixend;
01178     if (!d->transitionIndexes(start, end, ixstart, ixend))
01179         return QList<KTimeZone::Transition>();   // there are no transitions within the time period
01180     if (ixend >= 0)
01181         return d->transitions.mid(ixstart, ixend - ixstart + 1);
01182     if (ixstart > 0)
01183         return d->transitions.mid(ixstart);
01184     return d->transitions;
01185 }
01186 
01187 void KTimeZoneData::setTransitions(const QList<KTimeZone::Transition> &transitions)
01188 {
01189     d->transitions = transitions;
01190 }
01191 
01192 int KTimeZoneData::previousUtcOffset() const
01193 {
01194     return d->preUtcOffset;
01195 }
01196 
01197 const KTimeZone::Transition *KTimeZoneData::transition(const QDateTime &dt, const KTimeZone::Transition **secondTransition,
01198                                                        bool *validTime) const
01199 {
01200     int secondIndex;
01201     int index = transitionIndex(dt, (secondTransition ? &secondIndex : 0), validTime);
01202     if (secondTransition)
01203         *secondTransition = (secondIndex >= 0) ? &d->transitions[secondIndex] : 0;
01204     return (index >= 0) ? &d->transitions[index] : 0;
01205 }
01206 
01207 int KTimeZoneData::transitionIndex(const QDateTime &dt, int *secondIndex, bool *validTime) const
01208 {
01209     if (validTime)
01210         *validTime = true;
01211 
01212     // Find the last transition before this date/time
01213     int index = d->transitionIndex(dt);
01214     if (dt.timeSpec() == Qt::UTC)
01215     {
01216         if (secondIndex)
01217             *secondIndex = index;
01218         return index;
01219     }
01220     else
01221     {
01222         /* Check whether the specified local time actually occurs.
01223          * Find the start of the next phase, and check if it falls in the gap
01224          * between the two phases.
01225          */
01226         QDateTime dtutc = dt;
01227         dtutc.setTimeSpec(Qt::UTC);
01228         int count = d->transitions.count();
01229         int next = (index >= 0) ? index + 1 : 0;
01230         if (next < count)
01231         {
01232             KTimeZone::Phase nextPhase = d->transitions[next].phase();
01233             int offset = (index >= 0) ? d->transitions[index].phase().utcOffset() : d->preUtcOffset;
01234             int phaseDiff = nextPhase.utcOffset() - offset;
01235             if (phaseDiff > 0)
01236             {
01237                 // Get UTC equivalent as if 'dt' was in the next phase
01238                 if (dtutc.secsTo(d->transitions[next].time()) + nextPhase.utcOffset() < phaseDiff)
01239                 {
01240                     // The time falls in the gap between the two phases,
01241                     // so return an invalid value.
01242                     if (validTime)
01243                         *validTime = false;
01244                     if (secondIndex)
01245                         *secondIndex = -1;
01246                     return -1;
01247                 }
01248             }
01249         }
01250 
01251         if (index < 0)
01252         {
01253             // The specified time is before the first phase
01254             if (secondIndex)
01255                 *secondIndex = -1;
01256             return -1;
01257         }
01258 
01259         /* Check if it's a local time which occurs both before and after the 'latest'
01260          * phase start time (for which it has to span a daylight saving to standard
01261          * time change).
01262          */
01263         bool duplicate = true;
01264         if (d->isSecondOccurrence(dtutc, index))
01265         {
01266             // 'dt' occurs twice
01267             if (secondIndex)
01268             {
01269                 *secondIndex = index;
01270                 duplicate = false;
01271             }
01272             // Get the transition containing the first occurrence of 'dt'
01273             if (index <= 0)
01274                 return -1;   // first occurrence of 'dt' is just before the first transition
01275             --index;
01276         }
01277 
01278         if (secondIndex  &&  duplicate)
01279             *secondIndex = index;
01280         return index;
01281     }
01282 }
01283 
01284 QList<QDateTime> KTimeZoneData::transitionTimes(const KTimeZone::Phase &phase, const QDateTime &start, const QDateTime &end) const
01285 {
01286     QList<QDateTime> times;
01287     int ixstart, ixend;
01288     if (d->transitionIndexes(start, end, ixstart, ixend))
01289     {
01290         if (ixend < 0)
01291             ixend = d->transitions.count() - 1;
01292         while (ixstart <= ixend)
01293         {
01294             if (d->transitions[ixstart].phase() == phase)
01295                 times += d->transitions[ixstart].time();
01296         }
01297     }
01298     return times;
01299 }
01300 
01301 QList<KTimeZone::LeapSeconds> KTimeZoneData::leapSecondChanges() const
01302 {
01303     return d->leapChanges;
01304 }
01305 
01306 void KTimeZoneData::setLeapSecondChanges(const QList<KTimeZone::LeapSeconds> &adjusts)
01307 {
01308     d->leapChanges = adjusts;
01309 }
01310 
01311 KTimeZone::LeapSeconds KTimeZoneData::leapSecondChange(const QDateTime &utc) const
01312 {
01313     if (utc.timeSpec() != Qt::UTC)
01314         kError() << "KTimeZoneData::leapSecondChange(): non-UTC time specified" << endl;
01315     else
01316     {
01317         for (int i = d->leapChanges.count();  --i >= 0;  )
01318         {
01319             if (d->leapChanges[i].dateTime() < utc)
01320                 return d->leapChanges[i];
01321         }
01322     }
01323     return KTimeZone::LeapSeconds();
01324 }

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal