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

KDECore

ksystemtimezone.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 "ksystemtimezone.moc"
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/QCoreApplication>
00039 #include <QtCore/QFile>
00040 #include <QtCore/QFileInfo>
00041 #include <QtCore/QDir>
00042 #include <QtCore/QRegExp>
00043 #include <QtCore/QStringList>
00044 #include <QtCore/QTextStream>
00045 #include <QtDBus/QDBusConnection>
00046 #include <QtDBus/QDBusInterface>
00047 #include <QtDBus/QDBusReply>
00048 
00049 #include <kglobal.h>
00050 #include <klocale.h>
00051 #include <kcodecs.h>
00052 #include <kstringhandler.h>
00053 #include <ktemporaryfile.h>
00054 #include <kdebug.h>
00055 #include <kconfiggroup.h>
00056 #include "ktzfiletimezone.h"
00057 
00058 
00059 #define KTIMEZONED_DBUS_IFACE "org.kde.KTimeZoned"
00060 
00061 
00062 /* Return the offset to UTC in the current time zone at the specified UTC time.
00063  * The thread-safe function localtime_r() is used in preference if available.
00064  */
00065 int gmtoff(time_t t)
00066 {
00067 #ifdef _POSIX_THREAD_SAFE_FUNCTIONS
00068     tm tmtime;
00069     if (!localtime_r(&t, &tmtime))
00070         return 0;
00071 #ifdef HAVE_TM_GMTOFF
00072     return tmtime.tm_gmtoff;
00073 #else
00074     int lwday = tmtime.tm_wday;
00075     int lt = 3600*tmtime.tm_hour + 60*tmtime.tm_min + tmtime.tm_sec;
00076     if (!gmtime_r(&t, &tmtime))
00077         return 0;
00078     int uwday = tmtime.tm_wday;
00079     int ut = 3600*tmtime.tm_hour + 60*tmtime.tm_min + tmtime.tm_sec;
00080 #endif
00081 #else
00082     tm *tmtime = localtime(&t);
00083     if (!tmtime)
00084         return 0;
00085 #ifdef HAVE_TM_GMTOFF
00086     return tmtime->tm_gmtoff;
00087 #else
00088     int lwday = tmtime->tm_wday;
00089     int lt = 3600*tmtime->tm_hour + 60*tmtime->tm_min + tmtime->tm_sec;
00090     tmtime = gmtime(&t);
00091     int uwday = tmtime->tm_wday;
00092     int ut = 3600*tmtime->tm_hour + 60*tmtime->tm_min + tmtime->tm_sec;
00093 #endif
00094 #endif
00095 #ifndef HAVE_TM_GMTOFF
00096     if (lwday != uwday)
00097     {
00098       // Adjust for different day
00099       if (lwday == uwday + 1  ||  lwday == 0 && uwday == 6)
00100         lt += 24*3600;
00101       else
00102         lt -= 24*3600;
00103     }
00104     return lt - ut;
00105 #endif
00106 }
00107 
00108 
00109 /******************************************************************************/
00110 
00111 class KSystemTimeZonesPrivate : public KTimeZones
00112 {
00113 public:
00114     static KSystemTimeZonesPrivate *instance();
00115     static KTzfileTimeZoneSource *tzfileSource();
00116     static void setLocalZone();
00117     static void cleanup();
00118     static void readConfig(bool init);
00119 #ifndef Q_OS_WIN
00120     static void updateZonetab()  { instance()->readZoneTab(true); }
00121 #endif
00122 
00123     static KTimeZone m_localZone;
00124     static QString m_localZoneName;
00125     static QString m_zoneinfoDir;
00126     static QString m_zonetab;
00127     static KSystemTimeZoneSource *m_source;
00128 
00129 private:
00130     KSystemTimeZonesPrivate() {}
00131 #ifndef Q_OS_WIN
00132     void readZoneTab(bool update);
00133     static float convertCoordinate(const QString &coordinate);
00134 #endif
00135 
00136     static KSystemTimeZones *m_parent;
00137     static KSystemTimeZonesPrivate *m_instance;
00138     static KTzfileTimeZoneSource *m_tzfileSource;
00139 };
00140 
00141 KTimeZone                KSystemTimeZonesPrivate::m_localZone;
00142 QString                  KSystemTimeZonesPrivate::m_localZoneName;
00143 QString                  KSystemTimeZonesPrivate::m_zoneinfoDir;
00144 QString                  KSystemTimeZonesPrivate::m_zonetab;
00145 KSystemTimeZoneSource   *KSystemTimeZonesPrivate::m_source = 0;
00146 KTzfileTimeZoneSource   *KSystemTimeZonesPrivate::m_tzfileSource = 0;
00147 KSystemTimeZones        *KSystemTimeZonesPrivate::m_parent = 0;
00148 KSystemTimeZonesPrivate *KSystemTimeZonesPrivate::m_instance = 0;
00149 
00150 KTzfileTimeZoneSource *KSystemTimeZonesPrivate::tzfileSource()
00151 {
00152     if (!m_tzfileSource)
00153     {
00154         instance();
00155         m_tzfileSource = new KTzfileTimeZoneSource(m_zoneinfoDir);
00156     }
00157     return m_tzfileSource;
00158 }
00159 
00160 
00161 KSystemTimeZones::KSystemTimeZones()
00162   : d(0)
00163 {
00164     QDBusConnection dbus = QDBusConnection::sessionBus();
00165     dbus.connect(QString(), QString(), KTIMEZONED_DBUS_IFACE, "configChanged", this, SLOT(configChanged()));
00166     dbus.connect(QString(), QString(), KTIMEZONED_DBUS_IFACE, "zonetabChanged", this, SLOT(zonetabChanged(QString)));
00167     // No need to connect to definitionChanged() - see comments in zoneDefinitionChanged()
00168     //dbus.connect(QString(), QString(), KTIMEZONED_DBUS_IFACE, "definitionChanged", this, SLOT(zoneDefinitionChanged(QString)));
00169 }
00170 
00171 KSystemTimeZones::~KSystemTimeZones()
00172 {
00173 }
00174 
00175 KTimeZone KSystemTimeZones::local()
00176 {
00177     KSystemTimeZonesPrivate::instance();
00178     return KSystemTimeZonesPrivate::m_localZone;
00179 }
00180 
00181 QString KSystemTimeZones::zoneinfoDir()
00182 {
00183     KSystemTimeZonesPrivate::instance();
00184     return KSystemTimeZonesPrivate::m_zoneinfoDir;
00185 }
00186 
00187 KTimeZones *KSystemTimeZones::timeZones()
00188 {
00189     return KSystemTimeZonesPrivate::instance();
00190 }
00191 
00192 KTimeZone KSystemTimeZones::readZone(const QString &name)
00193 {
00194     return KTzfileTimeZone(KSystemTimeZonesPrivate::tzfileSource(), name);
00195 }
00196 
00197 const KTimeZones::ZoneMap KSystemTimeZones::zones()
00198 {
00199     return KSystemTimeZonesPrivate::instance()->zones();
00200 }
00201 
00202 KTimeZone KSystemTimeZones::zone(const QString& name)
00203 {
00204     return KSystemTimeZonesPrivate::instance()->zone(name);
00205 }
00206 
00207 void KSystemTimeZones::configChanged()
00208 {
00209     kDebug(161) << "KSystemTimeZones::configChanged()";
00210     KSystemTimeZonesPrivate::readConfig(false);
00211 }
00212 
00213 void KSystemTimeZones::zonetabChanged(const QString &zonetab)
00214 {
00215     Q_UNUSED(zonetab)
00216 #ifndef Q_OS_WIN
00217     kDebug(161) << "KSystemTimeZones::zonetabChanged()";
00218     // Re-read zone.tab and update our collection, removing any deleted
00219     // zones and adding any new zones.
00220     KSystemTimeZonesPrivate::updateZonetab();
00221 #endif
00222 }
00223 
00224 void KSystemTimeZones::zoneDefinitionChanged(const QString &zone)
00225 {
00226     // No need to do anything when the definition (as opposed to the
00227     // identity) of the local zone changes, since the updated details
00228     // will always be accessed by the system library calls to fetch
00229     // local zone information.
00230     Q_UNUSED(zone)
00231 }
00232 
00233 // Perform initialization, create the unique KSystemTimeZones instance,
00234 // whose only function is to receive D-Bus signals from KTimeZoned,
00235 // and create the unique KSystemTimeZonesPrivate instance.
00236 KSystemTimeZonesPrivate *KSystemTimeZonesPrivate::instance()
00237 {
00238     if (!m_instance)
00239     {
00240         m_instance = new KSystemTimeZonesPrivate;
00241 
00242         // A KSystemTimeZones instance is required only to catch D-Bus signals.
00243         m_parent = new KSystemTimeZones;
00244         // Ensure that the KDED time zones module has initialized. The call loads the module on demand.
00245         QDBusInterface *ktimezoned = new QDBusInterface("org.kde.kded", "/modules/ktimezoned", KTIMEZONED_DBUS_IFACE);
00246         QDBusReply<void> reply = ktimezoned->call("initialize", false);
00247         if (!reply.isValid())
00248             kError(161) << "KSystemTimeZones: ktimezoned initialize() D-Bus call failed: " << reply.error().message() << endl;
00249 kDebug(161)<<"instance(): ... initialised";
00250         delete ktimezoned;
00251 
00252         // Read the time zone config written by ktimezoned
00253         readConfig(true);
00254 
00255         // Go read the database.
00256 #ifdef Q_OS_WIN
00257         // On Windows, HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones
00258         // is the place to look. The TZI binary value is the TIME_ZONE_INFORMATION structure.
00259 #else
00260         // For Unix, read zone.tab.
00261         if (!m_zonetab.isEmpty())
00262             m_instance->readZoneTab(false);
00263 #endif
00264         setLocalZone();
00265         if (!m_localZone.isValid())
00266             m_localZone = KTimeZone::utc();   // ensure a time zone is always returned
00267 
00268         qAddPostRoutine(KSystemTimeZonesPrivate::cleanup);
00269     }
00270     return m_instance;
00271 }
00272 
00273 void KSystemTimeZonesPrivate::readConfig(bool init)
00274 {
00275     KConfig config(QLatin1String("ktimezonedrc"));
00276     if (!init)
00277         config.reparseConfiguration();
00278     KConfigGroup group(&config, "TimeZones");
00279     m_zoneinfoDir   = group.readEntry("ZoneinfoDir");
00280     m_zonetab       = group.readEntry("Zonetab");
00281     m_localZoneName = group.readEntry("LocalZone");
00282     if (!init)
00283         setLocalZone();
00284     kDebug(161) << "readConfig(): local zone=" << m_localZoneName;
00285 }
00286 
00287 void KSystemTimeZonesPrivate::setLocalZone()
00288 {
00289     if (m_localZoneName.startsWith('/'))
00290     {
00291         // The time zone is specified by a file outside the zoneinfo directory
00292         m_localZone = KTzfileTimeZone(KSystemTimeZonesPrivate::tzfileSource(), m_localZoneName);
00293         if (m_localZone.isValid() && m_instance)
00294         {
00295             // Add the new time zone to the list
00296             KTimeZone oldzone = m_instance->zone(m_localZoneName);
00297             if (!oldzone.isValid() || oldzone.type() != "KTzfileTimeZone")
00298             {
00299                 m_instance->remove(oldzone);
00300                 m_instance->add(m_localZone);
00301             }
00302         }
00303     }
00304     else
00305         m_localZone = m_instance->zone(m_localZoneName);
00306 }
00307 
00308 void KSystemTimeZonesPrivate::cleanup()
00309 {
00310     delete m_parent;
00311     delete m_instance;
00312     delete m_source;
00313     delete m_tzfileSource;
00314 }
00315 
00316 #ifndef Q_OS_WIN
00317 /*
00318  * Find the location of the zoneinfo files and store in mZoneinfoDir.
00319  * Parse zone.tab and for each time zone, create a KSystemTimeZone instance.
00320  */
00321 void KSystemTimeZonesPrivate::readZoneTab(bool update)
00322 {
00323     kDebug(161) << "readZoneTab(" << m_zonetab<< ")";
00324     QStringList newZones;
00325     QFile f;
00326     f.setFileName(m_zonetab);
00327     if (!f.open(QIODevice::ReadOnly))
00328         return;
00329     QTextStream str(&f);
00330     QRegExp lineSeparator("[ \t]");
00331     QRegExp ordinateSeparator("[+-]");
00332     if (!m_source)
00333         m_source = new KSystemTimeZoneSource;
00334     while (!str.atEnd())
00335     {
00336         QString line = str.readLine();
00337         if (line.isEmpty() || line[0] == '#')
00338             continue;
00339         QStringList tokens = KStringHandler::perlSplit(lineSeparator, line, 4);
00340         int n = tokens.count();
00341         if (n < 3)
00342         {
00343             kError(161) << "readZoneTab(): invalid record: " << line << endl;
00344             continue;
00345         }
00346 
00347         // Got three tokens. Now check for two ordinates plus first one is "".
00348         int i = tokens[1].indexOf(QRegExp("[+-]"), 1);
00349         if (i < 0)
00350         {
00351             kError(161) << "readZoneTab() " << tokens[2] << ": invalid coordinates: " << tokens[1] << endl;
00352             continue;
00353         }
00354 
00355         float latitude = convertCoordinate(tokens[1].left(i));
00356         float longitude = convertCoordinate(tokens[1].mid(i));
00357 
00358         // Add entry to list.
00359         if (tokens[0] == "??")
00360             tokens[0] = "";
00361         // Solaris sets the empty Comments field to '-', making it not empty.
00362         // Clean it up.
00363         if (n > 3  &&  tokens[3] == "-")
00364             tokens[3] = "";
00365         KSystemTimeZone tz(m_source, tokens[2], tokens[0], latitude, longitude, (n > 3 ? tokens[3] : QString()));
00366         if (update)
00367         {
00368             // Update the existing collection with the new zone definition
00369             newZones += tz.name();
00370             KTimeZone oldTz = zone(tz.name());
00371             if (oldTz.isValid())
00372                 oldTz.updateBase(tz);   // the zone previously existed, so update its definition
00373             else
00374                 add(tz);   // the zone didn't previously exist, so add it
00375         }
00376         else
00377             add(tz);
00378     }
00379     f.close();
00380 
00381     if (update)
00382     {
00383         // Remove any zones from the collection which no longer exist
00384         const ZoneMap oldZones = zones();
00385         for (ZoneMap::ConstIterator it = oldZones.constBegin();  it != oldZones.constEnd();  ++it)
00386         {
00387             if (newZones.indexOf(it.key()) < 0)
00388                 remove(it.value());
00389         }
00390     }
00391 }
00392 
00396 float KSystemTimeZonesPrivate::convertCoordinate(const QString &coordinate)
00397 {
00398     int value = coordinate.toInt();
00399     int degrees = 0;
00400     int minutes = 0;
00401     int seconds = 0;
00402 
00403     if (coordinate.length() > 6)
00404     {
00405         degrees = value / 10000;
00406         value -= degrees * 10000;
00407         minutes = value / 100;
00408         value -= minutes * 100;
00409         seconds = value;
00410     }
00411     else
00412     {
00413         degrees = value / 100;
00414         value -= degrees * 100;
00415         minutes = value;
00416     }
00417     value = degrees * 3600 + minutes * 60 + seconds;
00418     return value / 3600.0;
00419 }
00420 #endif
00421 
00422 
00423 /******************************************************************************/
00424 
00425 
00426 KSystemTimeZoneBackend::KSystemTimeZoneBackend(KSystemTimeZoneSource *source, const QString &name,
00427         const QString &countryCode, float latitude, float longitude, const QString &comment)
00428   : KTimeZoneBackend(source, name, countryCode, latitude, longitude, comment)
00429 {}
00430 
00431 KSystemTimeZoneBackend::~KSystemTimeZoneBackend()
00432 {}
00433 
00434 KTimeZoneBackend *KSystemTimeZoneBackend::clone() const
00435 {
00436     return new KSystemTimeZoneBackend(*this);
00437 }
00438 
00439 QByteArray KSystemTimeZoneBackend::type() const
00440 {
00441     return "KSystemTimeZone";
00442 }
00443 
00444 int KSystemTimeZoneBackend::offsetAtZoneTime(const KTimeZone *caller, const QDateTime &zoneDateTime, int *secondOffset) const
00445 {
00446     if (!caller->isValid()  ||  !zoneDateTime.isValid()  ||  zoneDateTime.timeSpec() != Qt::LocalTime)
00447         return 0;
00448     // Make this time zone the current local time zone
00449     const QByteArray originalZone = qgetenv("TZ");   // save the original local time zone
00450     QByteArray tz = caller->name().toUtf8();
00451     tz.prepend(":");
00452     bool change = (tz != originalZone);
00453     if (change)
00454     {
00455         ::setenv("TZ", tz, 1);
00456         ::tzset();
00457     }
00458 
00459     // Convert zone time to UTC, and then get the offset to UTC
00460     tm tmtime;
00461     tmtime.tm_sec    = zoneDateTime.time().second();
00462     tmtime.tm_min    = zoneDateTime.time().minute();
00463     tmtime.tm_hour   = zoneDateTime.time().hour();
00464     tmtime.tm_mday   = zoneDateTime.date().day();
00465     tmtime.tm_mon    = zoneDateTime.date().month() - 1;
00466     tmtime.tm_year   = zoneDateTime.date().year() - 1900;
00467     tmtime.tm_isdst  = -1;
00468     time_t t = mktime(&tmtime);
00469     int offset1 = (t == (time_t)-1) ? 0 : gmtoff(t);
00470     if (secondOffset)
00471     {
00472         int offset2 = offset1;
00473         if (t != (time_t)-1)
00474         {
00475             // Check if there is a backward DST change near to this time, by
00476             // checking if the UTC offset is different 1 hour later or earlier.
00477             // ASSUMPTION: DST SHIFTS ARE NEVER GREATER THAN 1 HOUR.
00478             int maxShift = 3600;
00479             offset2 = gmtoff(t + maxShift);
00480             if (offset2 < offset1)
00481             {
00482                 // There is a backward DST shift during the following hour
00483                 if (offset1 - offset2 < maxShift)
00484                     offset2 = gmtoff(t + (offset1 - offset2));
00485             }
00486             else if ((offset2 = gmtoff(t - maxShift)) > offset1)
00487             {
00488                 // There is a backward DST shift during the previous hour
00489                 if (offset2 - offset1 < maxShift)
00490                     offset2 = gmtoff(t - (offset2 - offset1));
00491                 // Put UTC offsets into the correct order
00492                 int o = offset1;
00493                 offset1 = offset2;
00494                 offset2 = o;
00495             }
00496             else offset2 = offset1;
00497         }
00498         *secondOffset = offset2;
00499     }
00500 
00501     if (change)
00502     {
00503         // Restore the original local time zone
00504         if (originalZone.isEmpty())
00505             ::unsetenv("TZ");
00506         else
00507             ::setenv("TZ", originalZone, 1);
00508         ::tzset();
00509     }
00510     return offset1;
00511 }
00512 
00513 int KSystemTimeZoneBackend::offsetAtUtc(const KTimeZone *caller, const QDateTime &utcDateTime) const
00514 {
00515     return offset(caller, KTimeZone::toTime_t(utcDateTime));
00516 }
00517 
00518 int KSystemTimeZoneBackend::offset(const KTimeZone *caller, time_t t) const
00519 {
00520     if (!caller->isValid()  ||  t == KTimeZone::InvalidTime_t)
00521         return 0;
00522 
00523     // Make this time zone the current local time zone
00524     const QByteArray originalZone = qgetenv("TZ");   // save the original local time zone
00525     QByteArray tz = caller->name().toUtf8();
00526     tz.prepend(":");
00527     bool change = (tz != originalZone);
00528     if (change)
00529     {
00530         ::setenv("TZ", tz, 1);
00531         ::tzset();
00532     }
00533 
00534     int secs = gmtoff(t);
00535 
00536     if (change)
00537     {
00538         // Restore the original local time zone
00539         if (originalZone.isEmpty())
00540             ::unsetenv("TZ");
00541         else
00542             ::setenv("TZ", originalZone, 1);
00543         ::tzset();
00544     }
00545     return secs;
00546 }
00547 
00548 bool KSystemTimeZoneBackend::isDstAtUtc(const KTimeZone *caller, const QDateTime &utcDateTime) const
00549 {
00550     return isDst(caller, KTimeZone::toTime_t(utcDateTime));
00551 }
00552 
00553 bool KSystemTimeZoneBackend::isDst(const KTimeZone *caller, time_t t) const
00554 {
00555     Q_UNUSED(caller)
00556     if (t != (time_t)-1)
00557     {
00558 #ifdef _POSIX_THREAD_SAFE_FUNCTIONS
00559         tm tmtime;
00560         if (localtime_r(&t, &tmtime))
00561             return tmtime.tm_isdst > 0;
00562 #else
00563         tm *tmtime = localtime(&t);
00564         if (tmtime)
00565             return tmtime->tm_isdst > 0;
00566 #endif
00567     }
00568     return false;
00569 }
00570 
00571 
00572 /******************************************************************************/
00573 
00574 KSystemTimeZone::KSystemTimeZone(KSystemTimeZoneSource *source, const QString &name,
00575         const QString &countryCode, float latitude, float longitude, const QString &comment)
00576   : KTimeZone(new KSystemTimeZoneBackend(source, name, countryCode, latitude, longitude, comment))
00577 {
00578 }
00579 
00580 KSystemTimeZone::~KSystemTimeZone()
00581 {
00582 }
00583 
00584 
00585 /******************************************************************************/
00586 
00587 class KSystemTimeZoneDataPrivate
00588 {
00589 public:
00590     QByteArray TZ;
00591     QList<QByteArray> abbreviations;
00592 };
00593 
00594 
00595 // N.B. KSystemTimeZoneSourcePrivate is also used by KSystemTimeZoneData
00596 class KSystemTimeZoneSourcePrivate
00597 {
00598 public:
00599     static void setTZ(const QByteArray &zoneName);
00600     static void restoreTZ();
00601     static QByteArray savedTZ;       // temporary value of TZ environment variable saved by setTZ()
00602     static QByteArray originalTZ;    // saved value of TZ environment variable during multiple parse() calls
00603     static bool       TZIsSaved;     // TZ has been saved in savedTZ
00604     static bool       multiParse;    // true if performing multiple parse() calls
00605 };
00606 
00607 QByteArray KSystemTimeZoneSourcePrivate::savedTZ;
00608 QByteArray KSystemTimeZoneSourcePrivate::originalTZ;
00609 bool       KSystemTimeZoneSourcePrivate::TZIsSaved = false;
00610 bool       KSystemTimeZoneSourcePrivate::multiParse = false;
00611 
00612 
00613 KSystemTimeZoneSource::KSystemTimeZoneSource()
00614     : d(0)
00615 //  : d(new KSystemTimeZoneSourcePrivate)
00616 {
00617 }
00618 
00619 KSystemTimeZoneSource::~KSystemTimeZoneSource()
00620 {
00621 //    delete d;
00622 }
00623 
00624 KTimeZoneData* KSystemTimeZoneSource::parse(const KTimeZone &zone) const
00625 {
00626     QByteArray tz = zone.name().toUtf8();
00627     KSystemTimeZoneSourcePrivate::setTZ(tz);   // make this time zone the current local time zone
00628 
00629     tzset();    // initialize the tzname array
00630     KSystemTimeZoneData* data = new KSystemTimeZoneData;
00631     data->d->TZ = tz;
00632     data->d->abbreviations.append(tzname[0]);
00633     data->d->abbreviations.append(tzname[1]);
00634 
00635     // There is no easy means to access the sequence of daylight savings time
00636     // changes, or leap seconds adjustments, so leave that data empty.
00637 
00638     KSystemTimeZoneSourcePrivate::restoreTZ();   // restore the original local time zone if necessary
00639     return data;
00640 }
00641 
00642 void KSystemTimeZoneSource::startParseBlock()
00643 {
00644     KSystemTimeZoneSourcePrivate::originalTZ = qgetenv("TZ");   // save the original local time zone
00645     KSystemTimeZoneSourcePrivate::multiParse = true;
00646 }
00647 
00648 void KSystemTimeZoneSource::endParseBlock()
00649 {
00650     if (KSystemTimeZoneSourcePrivate::multiParse)
00651     {
00652         // Restore the original local time zone
00653         if (KSystemTimeZoneSourcePrivate::originalTZ.isEmpty())
00654             ::unsetenv("TZ");
00655         else
00656             ::setenv("TZ", KSystemTimeZoneSourcePrivate::originalTZ, 1);
00657         ::tzset();
00658         KSystemTimeZoneSourcePrivate::multiParse = false;
00659     }
00660 }
00661 
00662 // Set the TZ environment variable to the specified time zone,
00663 // saving its current setting first if necessary.
00664 void KSystemTimeZoneSourcePrivate::setTZ(const QByteArray &zoneName)
00665 {
00666     QByteArray tz = zoneName;
00667     tz.prepend(":");
00668     bool setTZ = multiParse;
00669     if (!setTZ)
00670     {
00671         savedTZ = qgetenv("TZ");   // save the original local time zone
00672         TZIsSaved = true;
00673         setTZ = (tz != savedTZ);
00674     }
00675     if (setTZ)
00676     {
00677         ::setenv("TZ", tz, 1);
00678         ::tzset();
00679     }
00680 }
00681 
00682 // Restore the TZ environment variable if it was saved by setTz()
00683 void KSystemTimeZoneSourcePrivate::restoreTZ()
00684 {
00685     if (TZIsSaved)
00686     {
00687         if (savedTZ.isEmpty())
00688             ::unsetenv("TZ");
00689         else
00690             ::setenv("TZ", savedTZ, 1);
00691         ::tzset();
00692         TZIsSaved = false;
00693     }
00694 }
00695 
00696 
00697 /******************************************************************************/
00698 
00699 KSystemTimeZoneData::KSystemTimeZoneData()
00700   : d(new KSystemTimeZoneDataPrivate)
00701 { }
00702 
00703 KSystemTimeZoneData::KSystemTimeZoneData(const KSystemTimeZoneData &rhs)
00704   : KTimeZoneData(),
00705     d(new KSystemTimeZoneDataPrivate)
00706 {
00707     operator=(rhs);
00708 }
00709 
00710 KSystemTimeZoneData::~KSystemTimeZoneData()
00711 {
00712     delete d;
00713 }
00714 
00715 KSystemTimeZoneData &KSystemTimeZoneData::operator=(const KSystemTimeZoneData &rhs)
00716 {
00717     d->TZ = rhs.d->TZ;
00718     d->abbreviations = rhs.d->abbreviations;
00719     return *this;
00720 }
00721 
00722 KTimeZoneData *KSystemTimeZoneData::clone() const
00723 {
00724     return new KSystemTimeZoneData(*this);
00725 }
00726 
00727 QList<QByteArray> KSystemTimeZoneData::abbreviations() const
00728 {
00729     return d->abbreviations;
00730 }
00731 
00732 QByteArray KSystemTimeZoneData::abbreviation(const QDateTime &utcDateTime) const
00733 {
00734     QByteArray abbr;
00735     if (utcDateTime.timeSpec() != Qt::UTC)
00736         return abbr;
00737     time_t t = utcDateTime.toTime_t();
00738     if (t != KTimeZone::InvalidTime_t)
00739     {
00740         KSystemTimeZoneSourcePrivate::setTZ(d->TZ);   // make this time zone the current local time zone
00741 
00742         /* Use tm.tm_zone if available because it returns the abbreviation
00743          * in use at the time specified. Otherwise, use tzname[] which
00744          * returns the appropriate current abbreviation instead.
00745          */
00746 #ifdef _POSIX_THREAD_SAFE_FUNCTIONS
00747         tm tmtime;
00748         if (localtime_r(&t, &tmtime))
00749 #ifdef HAVE_STRUCT_TM_TM_ZONE
00750             abbr = tmtime.tm_zone;
00751 #else
00752             abbr = tzname[(tmtime.tm_isdst > 0) ? 1 : 0];
00753 #endif
00754 #else
00755         tm *tmtime = localtime(&t);
00756         if (tmtime)
00757 #ifdef HAVE_STRUCT_TM_TM_ZONE
00758             abbr = tmtime->tm_zone;
00759 #else
00760             abbr = tzname[(tmtime->tm_isdst > 0) ? 1 : 0];
00761 #endif
00762 #endif
00763         KSystemTimeZoneSourcePrivate::restoreTZ();   // restore the original local time zone if necessary
00764     }
00765     return abbr;
00766 }
00767 
00768 QList<int> KSystemTimeZoneData::utcOffsets() const
00769 {
00770     return QList<int>();
00771 }

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
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.7
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