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

KDE's Doxygen guidelines are available online.

KDECore

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

kdelibs-4.8.3 API Reference

Skip menu "kdelibs-4.8.3 API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal