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

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
  • KPty
  • Kross
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.6.1
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