diff --git a/kdecore/date/ksystemtimezone.cpp b/kdecore/date/ksystemtimezone.cpp index c1124d4..8c3d2cc 100644 --- a/kdecore/date/ksystemtimezone.cpp +++ b/kdecore/date/ksystemtimezone.cpp @@ -1,920 +1,915 @@ /* This file is part of the KDE libraries Copyright (c) 2005-2010 David Jarvie Copyright (c) 2005 S.R.Haque . This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // This file requires HAVE_STRUCT_TM_TM_ZONE to be defined if struct tm member tm_zone is available. // This file requires HAVE_TM_GMTOFF to be defined if struct tm member tm_gmtoff is available. #include "ksystemtimezone.h" // #include #include #ifdef HAVE_SYS_TIME_H #include #endif #ifdef HAVE_TIME_H #include #endif #include #include #include #include #include #include #include #include #include #ifndef KDE_NO_TIMEZONED #include #include #include #include #endif #include #include #include #include #include #ifndef KDE_NO_DBUS #include #endif #include #include #include "ktzfiletimezone.h" #ifdef Q_OS_WIN #include "ktimezone_win.h" #endif #ifndef KDE_NO_TIMEZONED #define KTIMEZONED_DBUS_IFACE "org.kde.KTimeZoned" #else #warning "building without timezoned support" #endif /* Return the offset to UTC in the current time zone at the specified UTC time. * The thread-safe function localtime_r() is used in preference if available. */ int gmtoff(time_t t) { #ifdef _POSIX_THREAD_SAFE_FUNCTIONS tm tmtime; if (!localtime_r(&t, &tmtime)) return 0; #ifdef HAVE_TM_GMTOFF return tmtime.tm_gmtoff; #else int lwday = tmtime.tm_wday; int lt = 3600*tmtime.tm_hour + 60*tmtime.tm_min + tmtime.tm_sec; if (!gmtime_r(&t, &tmtime)) return 0; int uwday = tmtime.tm_wday; int ut = 3600*tmtime.tm_hour + 60*tmtime.tm_min + tmtime.tm_sec; #endif #else tm *tmtime = localtime(&t); if (!tmtime) return 0; #ifdef HAVE_TM_GMTOFF return tmtime->tm_gmtoff; #else int lwday = tmtime->tm_wday; int lt = 3600*tmtime->tm_hour + 60*tmtime->tm_min + tmtime->tm_sec; tmtime = gmtime(&t); int uwday = tmtime->tm_wday; int ut = 3600*tmtime->tm_hour + 60*tmtime->tm_min + tmtime->tm_sec; #endif #endif #ifndef HAVE_TM_GMTOFF if (lwday != uwday) { // Adjust for different day if (lwday == uwday + 1 || (lwday == 0 && uwday == 6)) lt += 24*3600; else lt -= 24*3600; } return lt - ut; #endif } /******************************************************************************/ class KSystemTimeZonesPrivate : public KTimeZones { public: static KSystemTimeZonesPrivate *instance(); static KTzfileTimeZoneSource *tzfileSource(); static void setLocalZone(); static void cleanup(); static void readConfig(bool init); #ifdef Q_OS_WIN static void updateTimezoneInformation() { instance()->updateTimezoneInformation(true); } #else static void updateZonetab() { instance()->readZoneTab(true); } #endif static KTimeZone m_localZone; static QString m_localZoneName; static QString m_zoneinfoDir; static QString m_zonetab; static KSystemTimeZoneSource *m_source; static bool m_ktimezonedError; private: KSystemTimeZonesPrivate() {} #ifdef Q_OS_WIN void updateTimezoneInformation(bool update); #else void readZoneTab(bool update); static float convertCoordinate(const QString &coordinate); #endif static KSystemTimeZones *m_parent; static KSystemTimeZonesPrivate *m_instance; static KTzfileTimeZoneSource *m_tzfileSource; }; KTimeZone KSystemTimeZonesPrivate::m_localZone; QString KSystemTimeZonesPrivate::m_localZoneName; QString KSystemTimeZonesPrivate::m_zoneinfoDir; QString KSystemTimeZonesPrivate::m_zonetab; KSystemTimeZoneSource *KSystemTimeZonesPrivate::m_source = 0; bool KSystemTimeZonesPrivate::m_ktimezonedError = true; KTzfileTimeZoneSource *KSystemTimeZonesPrivate::m_tzfileSource = 0; KSystemTimeZones *KSystemTimeZonesPrivate::m_parent = 0; KSystemTimeZonesPrivate *KSystemTimeZonesPrivate::m_instance = 0; KTzfileTimeZoneSource *KSystemTimeZonesPrivate::tzfileSource() { if (!m_tzfileSource) { instance(); m_tzfileSource = new KTzfileTimeZoneSource(m_zoneinfoDir); } return m_tzfileSource; } #ifndef NDEBUG K_GLOBAL_STATIC(KTimeZone, simulatedLocalZone) #endif KSystemTimeZones::KSystemTimeZones() : d(0) { #ifndef KDE_NO_TIMEZONED QDBusConnection dbus = QDBusConnection::sessionBus(); const QString dbusIface = QString::fromLatin1(KTIMEZONED_DBUS_IFACE); dbus.connect(QString(), QString(), dbusIface, QLatin1String("configChanged"), this, SLOT(configChanged())); dbus.connect(QString(), QString(), dbusIface, QLatin1String("zonetabChanged"), this, SLOT(zonetabChanged(QString))); // No need to connect to definitionChanged() - see comments in zoneDefinitionChanged() //dbus.connect(QString(), QString(), dbusIface, QLatin1String("definitionChanged"), this, SLOT(zoneDefinitionChanged(QString))); #endif } KSystemTimeZones::~KSystemTimeZones() { } KTimeZone KSystemTimeZones::local() { #ifndef NDEBUG if (simulatedLocalZone->isValid()) return *simulatedLocalZone; #endif KSystemTimeZonesPrivate::instance(); return KSystemTimeZonesPrivate::m_localZone; } KTimeZone KSystemTimeZones::realLocalZone() { KSystemTimeZonesPrivate::instance(); return KSystemTimeZonesPrivate::m_localZone; } void KSystemTimeZones::setLocalZone(const KTimeZone& tz) { Q_UNUSED(tz); #ifndef NDEBUG *simulatedLocalZone = tz; #endif } bool KSystemTimeZones::isSimulated() { #ifndef NDEBUG return simulatedLocalZone->isValid(); #else return false; #endif } QString KSystemTimeZones::zoneinfoDir() { KSystemTimeZonesPrivate::instance(); return KSystemTimeZonesPrivate::m_zoneinfoDir; } bool KSystemTimeZones::isTimeZoneDaemonAvailable() { KSystemTimeZonesPrivate::instance(); return !KSystemTimeZonesPrivate::m_ktimezonedError; } KTimeZones *KSystemTimeZones::timeZones() { return KSystemTimeZonesPrivate::instance(); } KTimeZone KSystemTimeZones::readZone(const QString &name) { return KTzfileTimeZone(KSystemTimeZonesPrivate::tzfileSource(), name); } const KTimeZones::ZoneMap KSystemTimeZones::zones() { return KSystemTimeZonesPrivate::instance()->zones(); } KTimeZone KSystemTimeZones::zone(const QString& name) { return KSystemTimeZonesPrivate::instance()->zone(name); } void KSystemTimeZones::configChanged() { - kDebug(161) << "KSystemTimeZones::configChanged()"; KSystemTimeZonesPrivate::m_ktimezonedError = false; KSystemTimeZonesPrivate::readConfig(false); } void KSystemTimeZones::zonetabChanged(const QString &zonetab) { Q_UNUSED(zonetab) #ifndef Q_OS_WIN - kDebug(161) << "KSystemTimeZones::zonetabChanged()"; KSystemTimeZonesPrivate::m_ktimezonedError = false; // Re-read zone.tab and update our collection, removing any deleted // zones and adding any new zones. KSystemTimeZonesPrivate::updateZonetab(); #endif } void KSystemTimeZones::zoneDefinitionChanged(const QString &zone) { // No need to do anything when the definition (as opposed to the // identity) of the local zone changes, since the updated details // will always be accessed by the system library calls to fetch // local zone information. Q_UNUSED(zone) KSystemTimeZonesPrivate::m_ktimezonedError = false; } // Perform initialization, create the unique KSystemTimeZones instance, // whose only function is to receive D-Bus signals from KTimeZoned, // and create the unique KSystemTimeZonesPrivate instance. KSystemTimeZonesPrivate *KSystemTimeZonesPrivate::instance() { if (!m_instance) { m_instance = new KSystemTimeZonesPrivate; // A KSystemTimeZones instance is required only to catch D-Bus signals. m_parent = new KSystemTimeZones; #ifndef KDE_NO_TIMEZONED // Ensure that the KDED time zones module has initialized. The call loads the module on demand. if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(QLatin1String("org.kde.kded"))) KToolInvocation::klauncher(); // this calls startKdeinit, and blocks until it returns const QString dbusIface = QString::fromLatin1(KTIMEZONED_DBUS_IFACE); QDBusInterface *ktimezoned = new QDBusInterface(QLatin1String("org.kde.kded"), QLatin1String("/modules/ktimezoned"), dbusIface); QDBusReply reply = ktimezoned->call(QLatin1String("initialize"), false); m_ktimezonedError = !reply.isValid(); if (m_ktimezonedError) kError(161) << "KSystemTimeZones: ktimezoned initialize() D-Bus call failed: " << reply.error().message() << endl; -kDebug(161)<<"instance(): ... initialised"; delete ktimezoned; #else m_ktimezonedError = false; #endif // Read the time zone config written by ktimezoned readConfig(true); // Go read the database. #ifdef Q_OS_WIN // On Windows, HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones // is the place to look. The TZI binary value is the TIME_ZONE_INFORMATION structure. m_instance->updateTimezoneInformation(false); #else // For Unix, read zone.tab. if (!m_zonetab.isEmpty()) m_instance->readZoneTab(false); #endif setLocalZone(); if (!m_localZone.isValid()) m_localZone = KTimeZone::utc(); // ensure a time zone is always returned qAddPostRoutine(KSystemTimeZonesPrivate::cleanup); } return m_instance; } void KSystemTimeZonesPrivate::readConfig(bool init) { #ifdef KDE_NO_TIMEZONED if (QFile(QLatin1String("/usr/share/zoneinfo/zone.tab")).exists()) { m_zoneinfoDir = QLatin1String("/usr/share/zoneinfo"); m_zonetab = QLatin1String("/usr/share/zoneinfo/zone.tab"); } else if (QFile(QLatin1String("/usr/lib/zoneinfo/zone.tab")).exists()) { m_zoneinfoDir = QLatin1String("/usr/lib/zoneinfo"); m_zonetab = QLatin1String("/usr/lib/zoneinfo/zone.tab"); } else { kError(161) << "No time zone information obtained, could not find zone.tab"; } m_localZoneName = QLatin1String("UTC"); #else KConfig config(QLatin1String("ktimezonedrc")); if (!init) config.reparseConfiguration(); KConfigGroup group(&config, "TimeZones"); if (!group.exists()) { kError(161) << "No time zone information obtained from ktimezoned"; m_ktimezonedError = true; } m_zoneinfoDir = group.readEntry("ZoneinfoDir"); m_zonetab = group.readEntry("Zonetab"); m_localZoneName = group.readEntry("LocalZone"); #endif if (m_zoneinfoDir.length() > 1 && m_zoneinfoDir.endsWith(QLatin1Char('/'))) m_zoneinfoDir.truncate(m_zoneinfoDir.length() - 1); // strip trailing '/' if (!init) setLocalZone(); - kDebug(161) << "readConfig(): local zone=" << m_localZoneName; } void KSystemTimeZonesPrivate::setLocalZone() { QString filename; if (m_localZoneName.startsWith(QLatin1Char('/'))) { // The time zone is specified by a file outside the zoneinfo directory filename = m_localZoneName; } else { // The zone name is either a known zone, or it's a relative file name // in zoneinfo directory which isn't in zone.tab. m_localZone = m_instance->zone(m_localZoneName); if (m_localZone.isValid()) return; // It's a relative file name filename = m_zoneinfoDir + QLatin1Char('/') + m_localZoneName; } // Parse the specified time zone data file QString zonename = filename; if (zonename.startsWith(m_zoneinfoDir + QLatin1Char('/'))) zonename = zonename.mid(m_zoneinfoDir.length() + 1); m_localZone = KTzfileTimeZone(KSystemTimeZonesPrivate::tzfileSource(), zonename); if (m_localZone.isValid() && m_instance) { // Add the new time zone to the list const KTimeZone oldzone = m_instance->zone(zonename); if (!oldzone.isValid() || oldzone.type() != "KTzfileTimeZone") { m_instance->remove(oldzone); m_instance->add(m_localZone); } } } void KSystemTimeZonesPrivate::cleanup() { delete m_parent; delete m_instance; delete m_source; delete m_tzfileSource; } #ifdef Q_OS_WIN void KSystemTimeZonesPrivate::updateTimezoneInformation(bool update) { if (!m_source) m_source = new KSystemTimeZoneSourceWindows; QStringList newZones; Q_FOREACH(const QString & tz, KSystemTimeZoneWindows::listTimeZones()) { // const std::wstring wstr = tz.toStdWString(); // const KTimeZone info = make_time_zone( wstr.c_str() ); KSystemTimeZoneWindows stz(m_source, tz); if (update) { // Update the existing collection with the new zone definition newZones += stz.name(); KTimeZone oldTz = zone(stz.name()); if (oldTz.isValid()) oldTz.updateBase(stz); // the zone previously existed, so update its definition else add(stz); // the zone didn't previously exist, so add it } else add(stz); } if (update) { // Remove any zones from the collection which no longer exist const ZoneMap oldZones = zones(); for (ZoneMap::const_iterator it = oldZones.begin(); it != oldZones.end(); ++it) { if (newZones.indexOf(it.key()) < 0) remove(it.value()); } } } #else /* * Find the location of the zoneinfo files and store in mZoneinfoDir. * Parse zone.tab and for each time zone, create a KSystemTimeZone instance. */ void KSystemTimeZonesPrivate::readZoneTab(bool update) { - kDebug(161) << "readZoneTab(" << m_zonetab<< ")"; QStringList newZones; QFile f; f.setFileName(m_zonetab); if (!f.open(QIODevice::ReadOnly)) return; QTextStream str(&f); const QRegExp lineSeparator(QLatin1String("[ \t]")); const QRegExp ordinateSeparator(QLatin1String("[+-]")); if (!m_source) m_source = new KSystemTimeZoneSource; while (!str.atEnd()) { const QString line = str.readLine(); if (line.isEmpty() || line[0] == QLatin1Char('#')) continue; QStringList tokens = KStringHandler::perlSplit(lineSeparator, line, 4); const int n = tokens.count(); if (n < 3) { kError(161) << "readZoneTab(): invalid record: " << line << endl; continue; } // Got three tokens. Now check for two ordinates plus first one is "". const int i = tokens[1].indexOf(ordinateSeparator, 1); if (i < 0) { kError(161) << "readZoneTab() " << tokens[2] << ": invalid coordinates: " << tokens[1] << endl; continue; } const float latitude = convertCoordinate(tokens[1].left(i)); const float longitude = convertCoordinate(tokens[1].mid(i)); // Add entry to list. if (tokens[0] == QLatin1String("??")) tokens[0] = QString::fromLatin1(""); // Solaris sets the empty Comments field to '-', making it not empty. // Clean it up. if (n > 3 && tokens[3] == QLatin1String("-")) tokens[3] = QString::fromLatin1(""); // Note: KTzfileTimeZone is used in preference to KSystemTimeZone because of // the large overhead incurred by tzset() - see KSystemTimeZones class // description for details. const KTzfileTimeZone tz(tzfileSource(), tokens[2], tokens[0], latitude, longitude, (n > 3 ? tokens[3] : QString())); if (update) { // Update the existing collection with the new zone definition newZones += tz.name(); KTimeZone oldTz = zone(tz.name()); if (oldTz.isValid()) oldTz.updateBase(tz); // the zone previously existed, so update its definition else add(tz); // the zone didn't previously exist, so add it } else add(tz); } f.close(); if (update) { // Remove any zones from the collection which no longer exist const ZoneMap oldZones = zones(); for (ZoneMap::ConstIterator it = oldZones.constBegin(); it != oldZones.constEnd(); ++it) { if (newZones.indexOf(it.key()) < 0) remove(it.value()); } } } /** * Convert sHHMM or sHHMMSS to a floating point number of degrees. */ float KSystemTimeZonesPrivate::convertCoordinate(const QString &coordinate) { int value = coordinate.toInt(); int degrees = 0; int minutes = 0; int seconds = 0; if (coordinate.length() > 6) { degrees = value / 10000; value -= degrees * 10000; minutes = value / 100; value -= minutes * 100; seconds = value; } else { degrees = value / 100; value -= degrees * 100; minutes = value; } value = degrees * 3600 + minutes * 60 + seconds; return value / 3600.0; } #endif /******************************************************************************/ KSystemTimeZoneBackend::KSystemTimeZoneBackend(KSystemTimeZoneSource *source, const QString &name, const QString &countryCode, float latitude, float longitude, const QString &comment) : KTimeZoneBackend(source, name, countryCode, latitude, longitude, comment) {} KSystemTimeZoneBackend::~KSystemTimeZoneBackend() {} KTimeZoneBackend *KSystemTimeZoneBackend::clone() const { return new KSystemTimeZoneBackend(*this); } QByteArray KSystemTimeZoneBackend::type() const { return "KSystemTimeZone"; } int KSystemTimeZoneBackend::offsetAtZoneTime(const KTimeZone *caller, const QDateTime &zoneDateTime, int *secondOffset) const { if (!caller->isValid() || !zoneDateTime.isValid() || zoneDateTime.timeSpec() != Qt::LocalTime) return 0; // Make this time zone the current local time zone const QByteArray originalZone = qgetenv("TZ"); // save the original local time zone QByteArray tz = caller->name().toUtf8(); tz.prepend(":"); const bool change = (tz != originalZone); if (change) { ::setenv("TZ", tz, 1); ::tzset(); } // Convert zone time to UTC, and then get the offset to UTC tm tmtime; tmtime.tm_sec = zoneDateTime.time().second(); tmtime.tm_min = zoneDateTime.time().minute(); tmtime.tm_hour = zoneDateTime.time().hour(); tmtime.tm_mday = zoneDateTime.date().day(); tmtime.tm_mon = zoneDateTime.date().month() - 1; tmtime.tm_year = zoneDateTime.date().year() - 1900; tmtime.tm_isdst = -1; const time_t t = mktime(&tmtime); int offset1 = (t == (time_t)-1) ? KTimeZone::InvalidOffset : gmtoff(t); if (secondOffset) { int offset2 = offset1; if (t != (time_t)-1) { // Check if there is a backward DST change near to this time, by // checking if the UTC offset is different 1 hour later or earlier. // ASSUMPTION: DST SHIFTS ARE NEVER GREATER THAN 1 HOUR. const int maxShift = 3600; offset2 = gmtoff(t + maxShift); if (offset2 < offset1) { // There is a backward DST shift during the following hour if (offset1 - offset2 < maxShift) offset2 = gmtoff(t + (offset1 - offset2)); } else if ((offset2 = gmtoff(t - maxShift)) > offset1) { // There is a backward DST shift during the previous hour if (offset2 - offset1 < maxShift) offset2 = gmtoff(t - (offset2 - offset1)); // Put UTC offsets into the correct order const int o = offset1; offset1 = offset2; offset2 = o; } else offset2 = offset1; } *secondOffset = offset2; } if (change) { // Restore the original local time zone if (originalZone.isEmpty()) ::unsetenv("TZ"); else ::setenv("TZ", originalZone, 1); ::tzset(); } return offset1; } int KSystemTimeZoneBackend::offsetAtUtc(const KTimeZone *caller, const QDateTime &utcDateTime) const { return offset(caller, KTimeZone::toTime_t(utcDateTime)); } int KSystemTimeZoneBackend::offset(const KTimeZone *caller, time_t t) const { if (!caller->isValid() || t == KTimeZone::InvalidTime_t) return 0; // Make this time zone the current local time zone const QByteArray originalZone = qgetenv("TZ"); // save the original local time zone QByteArray tz = caller->name().toUtf8(); tz.prepend(":"); const bool change = (tz != originalZone); if (change) { ::setenv("TZ", tz, 1); ::tzset(); } const int secs = gmtoff(t); if (change) { // Restore the original local time zone if (originalZone.isEmpty()) ::unsetenv("TZ"); else ::setenv("TZ", originalZone, 1); ::tzset(); } return secs; } bool KSystemTimeZoneBackend::isDstAtUtc(const KTimeZone *caller, const QDateTime &utcDateTime) const { return isDst(caller, KTimeZone::toTime_t(utcDateTime)); } bool KSystemTimeZoneBackend::isDst(const KTimeZone *caller, time_t t) const { Q_UNUSED(caller) if (t != (time_t)-1) { #ifdef _POSIX_THREAD_SAFE_FUNCTIONS tm tmtime; if (localtime_r(&t, &tmtime)) return tmtime.tm_isdst > 0; #else const tm *tmtime = localtime(&t); if (tmtime) return tmtime->tm_isdst > 0; #endif } return false; } /******************************************************************************/ KSystemTimeZone::KSystemTimeZone(KSystemTimeZoneSource *source, const QString &name, const QString &countryCode, float latitude, float longitude, const QString &comment) : KTimeZone(new KSystemTimeZoneBackend(source, name, countryCode, latitude, longitude, comment)) { } KSystemTimeZone::~KSystemTimeZone() { } /******************************************************************************/ class KSystemTimeZoneDataPrivate { public: QByteArray TZ; QList abbreviations; }; // N.B. KSystemTimeZoneSourcePrivate is also used by KSystemTimeZoneData class KSystemTimeZoneSourcePrivate { public: static void setTZ(const QByteArray &zoneName); static void restoreTZ(); static QByteArray savedTZ; // temporary value of TZ environment variable saved by setTZ() static QByteArray originalTZ; // saved value of TZ environment variable during multiple parse() calls static bool TZIsSaved; // TZ has been saved in savedTZ static bool multiParse; // true if performing multiple parse() calls }; QByteArray KSystemTimeZoneSourcePrivate::savedTZ; QByteArray KSystemTimeZoneSourcePrivate::originalTZ; bool KSystemTimeZoneSourcePrivate::TZIsSaved = false; bool KSystemTimeZoneSourcePrivate::multiParse = false; KSystemTimeZoneSource::KSystemTimeZoneSource() : d(0) // : d(new KSystemTimeZoneSourcePrivate) { } KSystemTimeZoneSource::~KSystemTimeZoneSource() { // delete d; } KTimeZoneData* KSystemTimeZoneSource::parse(const KTimeZone &zone) const { const QByteArray tz = zone.name().toUtf8(); KSystemTimeZoneSourcePrivate::setTZ(tz); // make this time zone the current local time zone tzset(); // initialize the tzname array KSystemTimeZoneData* data = new KSystemTimeZoneData; data->d->TZ = tz; data->d->abbreviations.append(tzname[0]); data->d->abbreviations.append(tzname[1]); // There is no easy means to access the sequence of daylight savings time // changes, or leap seconds adjustments, so leave that data empty. KSystemTimeZoneSourcePrivate::restoreTZ(); // restore the original local time zone if necessary return data; } void KSystemTimeZoneSource::startParseBlock() { KSystemTimeZoneSourcePrivate::originalTZ = qgetenv("TZ"); // save the original local time zone KSystemTimeZoneSourcePrivate::multiParse = true; } void KSystemTimeZoneSource::endParseBlock() { if (KSystemTimeZoneSourcePrivate::multiParse) { // Restore the original local time zone if (KSystemTimeZoneSourcePrivate::originalTZ.isEmpty()) ::unsetenv("TZ"); else ::setenv("TZ", KSystemTimeZoneSourcePrivate::originalTZ, 1); ::tzset(); KSystemTimeZoneSourcePrivate::multiParse = false; } } // Set the TZ environment variable to the specified time zone, // saving its current setting first if necessary. void KSystemTimeZoneSourcePrivate::setTZ(const QByteArray &zoneName) { QByteArray tz = zoneName; tz.prepend(":"); bool setTZ = multiParse; if (!setTZ) { savedTZ = qgetenv("TZ"); // save the original local time zone TZIsSaved = true; setTZ = (tz != savedTZ); } if (setTZ) { ::setenv("TZ", tz, 1); ::tzset(); } } // Restore the TZ environment variable if it was saved by setTz() void KSystemTimeZoneSourcePrivate::restoreTZ() { if (TZIsSaved) { if (savedTZ.isEmpty()) ::unsetenv("TZ"); else ::setenv("TZ", savedTZ, 1); ::tzset(); TZIsSaved = false; } } /******************************************************************************/ KSystemTimeZoneData::KSystemTimeZoneData() : d(new KSystemTimeZoneDataPrivate) { } KSystemTimeZoneData::KSystemTimeZoneData(const KSystemTimeZoneData &rhs) : KTimeZoneData(), d(new KSystemTimeZoneDataPrivate) { operator=(rhs); } KSystemTimeZoneData::~KSystemTimeZoneData() { delete d; } KSystemTimeZoneData &KSystemTimeZoneData::operator=(const KSystemTimeZoneData &rhs) { d->TZ = rhs.d->TZ; d->abbreviations = rhs.d->abbreviations; return *this; } KTimeZoneData *KSystemTimeZoneData::clone() const { return new KSystemTimeZoneData(*this); } QList KSystemTimeZoneData::abbreviations() const { return d->abbreviations; } QByteArray KSystemTimeZoneData::abbreviation(const QDateTime &utcDateTime) const { QByteArray abbr; if (utcDateTime.timeSpec() != Qt::UTC) return abbr; time_t t = utcDateTime.toTime_t(); if (t != KTimeZone::InvalidTime_t) { KSystemTimeZoneSourcePrivate::setTZ(d->TZ); // make this time zone the current local time zone /* Use tm.tm_zone if available because it returns the abbreviation * in use at the time specified. Otherwise, use tzname[] which * returns the appropriate current abbreviation instead. */ #ifdef _POSIX_THREAD_SAFE_FUNCTIONS tm tmtime; if (localtime_r(&t, &tmtime)) #ifdef HAVE_STRUCT_TM_TM_ZONE abbr = tmtime.tm_zone; #else abbr = tzname[(tmtime.tm_isdst > 0) ? 1 : 0]; #endif #else const tm *tmtime = localtime(&t); if (tmtime) #ifdef HAVE_STRUCT_TM_TM_ZONE abbr = tmtime->tm_zone; #else abbr = tzname[(tmtime->tm_isdst > 0) ? 1 : 0]; #endif #endif KSystemTimeZoneSourcePrivate::restoreTZ(); // restore the original local time zone if necessary } return abbr; } QList KSystemTimeZoneData::utcOffsets() const { return QList(); } #include "../../ksystemtimezone.moc"