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

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
  •   WTF
  • KJSEmbed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  •   core
  • Phonon
  •   Backend
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal