Page MenuHomePhorge

No OneTemporary

diff --git a/kdecore/date/ksystemtimezone.cpp b/kdecore/date/ksystemtimezone.cpp
index 770dd6ce56..8134eeb469 100644
--- a/kdecore/date/ksystemtimezone.cpp
+++ b/kdecore/date/ksystemtimezone.cpp
@@ -1,888 +1,888 @@
/*
This file is part of the KDE libraries
Copyright (c) 2005-2010 David Jarvie <djarvie@kde.org>
Copyright (c) 2005 S.R.Haque <srhaque@iee.org>.
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 "moc_ksystemtimezone.cpp"
#include <config.h>
#include <config-date.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#include <climits>
#include <cstdlib>
#include <QtCore/QCoreApplication>
#include <QtCore/QFile>
#include <QtCore/QFileInfo>
#include <QtCore/QDir>
#include <QtCore/QRegExp>
#include <QtCore/QStringList>
#include <QtCore/QTextStream>
#include <QtDBus/QDBusConnection>
#include <QtDBus/QDBusInterface>
#include <QtDBus/QDBusConnectionInterface>
#include <QtDBus/QDBusReply>
#include <kglobal.h>
#include <klocale.h>
#include <kcodecs.h>
#include <kstringhandler.h>
#include <ktoolinvocation.h>
#include <kdebug.h>
#include <kconfiggroup.h>
#include "ktzfiletimezone.h"
#ifdef Q_OS_WIN
#include "ktimezone_win.h"
#endif
#define KTIMEZONED_DBUS_IFACE "org.kde.KTimeZoned"
/* 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)
{
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)));
}
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;
// 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<void> 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;
// 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)
{
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");
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
- KTimeZone oldzone = m_instance->zone(zonename);
+ 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);
- QRegExp lineSeparator(QLatin1String("[ \t]"));
- QRegExp ordinateSeparator(QLatin1String("[+-]"));
+ const QRegExp lineSeparator(QLatin1String("[ \t]"));
+ const QRegExp ordinateSeparator(QLatin1String("[+-]"));
if (!m_source)
m_source = new KSystemTimeZoneSource;
while (!str.atEnd())
{
- QString line = str.readLine();
+ const QString line = str.readLine();
if (line.isEmpty() || line[0] == QLatin1Char('#'))
continue;
QStringList tokens = KStringHandler::perlSplit(lineSeparator, line, 4);
- int n = tokens.count();
+ 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 "".
- int i = tokens[1].indexOf(ordinateSeparator, 1);
+ const int i = tokens[1].indexOf(ordinateSeparator, 1);
if (i < 0)
{
kError(161) << "readZoneTab() " << tokens[2] << ": invalid coordinates: " << tokens[1] << endl;
continue;
}
- float latitude = convertCoordinate(tokens[1].left(i));
- float longitude = convertCoordinate(tokens[1].mid(i));
+ 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("");
- KSystemTimeZone tz(m_source, tokens[2], tokens[0], latitude, longitude, (n > 3 ? tokens[3] : QString()));
+ const KSystemTimeZone tz(m_source, 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(":");
- bool change = (tz != originalZone);
+ 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;
- time_t t = mktime(&tmtime);
+ const time_t t = mktime(&tmtime);
int offset1 = (t == (time_t)-1) ? 0 : 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.
- int maxShift = 3600;
+ 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
- int o = offset1;
+ 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(":");
- bool change = (tz != originalZone);
+ const bool change = (tz != originalZone);
if (change)
{
::setenv("TZ", tz, 1);
::tzset();
}
- int secs = gmtoff(t);
+ 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
- tm *tmtime = localtime(&t);
+ 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<QByteArray> 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
{
- QByteArray tz = zone.name().toUtf8();
+ 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<QByteArray> 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
- tm *tmtime = localtime(&t);
+ 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<int> KSystemTimeZoneData::utcOffsets() const
{
return QList<int>();
}
diff --git a/kdecore/date/ktimezone.cpp b/kdecore/date/ktimezone.cpp
index 0f09daa98e..076d459373 100644
--- a/kdecore/date/ktimezone.cpp
+++ b/kdecore/date/ktimezone.cpp
@@ -1,1387 +1,1387 @@
/*
This file is part of the KDE libraries
Copyright (c) 2005-2008,2011 David Jarvie <djarvie@kde.org>
Copyright (c) 2005 S.R.Haque <srhaque@iee.org>.
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.
*/
#include "ktimezone.h"
#include <config.h>
#include <config-date.h> // SIZEOF_TIME_T
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#include <climits>
#include <cstdlib>
#include <QtCore/QSet>
#include <QtCore/QSharedData>
#include <QtCore/QCoreApplication>
#include <kdebug.h>
#include <kglobal.h>
int gmtoff(time_t t); // defined in ksystemtimezone.cpp
/******************************************************************************/
class KTimeZonesPrivate
{
public:
KTimeZonesPrivate() {}
KTimeZones::ZoneMap zones;
};
KTimeZones::KTimeZones()
: d(new KTimeZonesPrivate)
{
}
KTimeZones::~KTimeZones()
{
delete d;
}
const KTimeZones::ZoneMap KTimeZones::zones() const
{
return d->zones;
}
bool KTimeZones::add(const KTimeZone &zone)
{
if (!zone.isValid())
return false;
if (d->zones.find(zone.name()) != d->zones.end())
return false; // name already exists
d->zones.insert(zone.name(), zone);
return true;
}
KTimeZone KTimeZones::remove(const KTimeZone &zone)
{
if (zone.isValid())
{
for (ZoneMap::Iterator it = d->zones.begin(), end = d->zones.end(); it != end; ++it)
{
if (it.value() == zone)
{
d->zones.erase(it);
return zone;
}
}
}
return KTimeZone();
}
KTimeZone KTimeZones::remove(const QString &name)
{
if (!name.isEmpty())
{
ZoneMap::Iterator it = d->zones.find(name);
if (it != d->zones.end())
{
KTimeZone zone = it.value();
d->zones.erase(it);
return zone;
}
}
return KTimeZone();
}
void KTimeZones::clear()
{
d->zones.clear();
}
KTimeZone KTimeZones::zone(const QString &name) const
{
if (!name.isEmpty())
{
ZoneMap::ConstIterator it = d->zones.constFind(name);
if (it != d->zones.constEnd())
return it.value();
if (name == KTimeZone::utc().name())
return KTimeZone::utc();
}
return KTimeZone(); // error
}
/******************************************************************************/
class KTimeZonePhasePrivate : public QSharedData
{
public:
QByteArray abbreviations; // time zone abbreviations (zero-delimited)
QString comment; // optional comment
int utcOffset; // seconds to add to UTC
bool dst; // true if daylight savings time
explicit KTimeZonePhasePrivate(int offset = 0, bool ds = false)
: QSharedData(),
utcOffset(offset),
dst(ds)
{}
KTimeZonePhasePrivate(const KTimeZonePhasePrivate& rhs)
: QSharedData(rhs),
abbreviations(rhs.abbreviations),
comment(rhs.comment),
utcOffset(rhs.utcOffset),
dst(rhs.dst)
{}
bool operator==(const KTimeZonePhasePrivate &rhs) const
{
return abbreviations == rhs.abbreviations
&& comment == rhs.comment
&& utcOffset == rhs.utcOffset
&& dst == rhs.dst;
}
};
KTimeZone::Phase::Phase()
: d(new KTimeZonePhasePrivate)
{
}
KTimeZone::Phase::Phase(int utcOffset, const QByteArray &abbrevs,
bool dst, const QString &cmt)
: d(new KTimeZonePhasePrivate(utcOffset, dst))
{
d->abbreviations = abbrevs;
d->comment = cmt;
}
KTimeZone::Phase::Phase(int utcOffset, const QList<QByteArray> &abbrevs,
bool dst, const QString &cmt)
: d(new KTimeZonePhasePrivate(utcOffset, dst))
{
for (int i = 0, end = abbrevs.count(); i < end; ++i)
{
if (i > 0)
d->abbreviations += '\0';
d->abbreviations += abbrevs[i];
}
d->comment = cmt;
}
KTimeZone::Phase::Phase(const KTimeZone::Phase &rhs)
: d(rhs.d)
{
}
KTimeZone::Phase::~Phase()
{
}
KTimeZone::Phase &KTimeZone::Phase::operator=(const KTimeZone::Phase &rhs)
{
d = rhs.d;
return *this;
}
bool KTimeZone::Phase::operator==(const KTimeZone::Phase &rhs) const
{
return d == rhs.d || *d == *rhs.d;
}
int KTimeZone::Phase::utcOffset() const
{
return d->utcOffset;
}
QList<QByteArray> KTimeZone::Phase::abbreviations() const
{
return d->abbreviations.split('\0');
}
bool KTimeZone::Phase::isDst() const
{
return d->dst;
}
QString KTimeZone::Phase::comment() const
{
return d->comment;
}
/******************************************************************************/
class KTimeZoneTransitionPrivate
{
public:
QDateTime time;
KTimeZone::Phase phase;
};
KTimeZone::Transition::Transition()
: d(new KTimeZoneTransitionPrivate)
{
}
KTimeZone::Transition::Transition(const QDateTime &t, const KTimeZone::Phase &p)
: d(new KTimeZoneTransitionPrivate)
{
d->time = t;
d->phase = p;
}
KTimeZone::Transition::Transition(const KTimeZone::Transition &t)
: d(new KTimeZoneTransitionPrivate)
{
d->time = t.d->time;
d->phase = t.d->phase;
}
KTimeZone::Transition::~Transition()
{
delete d;
}
KTimeZone::Transition &KTimeZone::Transition::operator=(const KTimeZone::Transition &t)
{
d->time = t.d->time;
d->phase = t.d->phase;
return *this;
}
bool KTimeZone::Transition::operator<(const KTimeZone::Transition &rhs) const
{
return d->time < rhs.d->time;
}
QDateTime KTimeZone::Transition::time() const { return d->time; }
KTimeZone::Phase KTimeZone::Transition::phase() const { return d->phase; }
/******************************************************************************/
class KTimeZoneDataPrivate
{
public:
QList<KTimeZone::Phase> phases;
QList<KTimeZone::Transition> transitions;
QList<KTimeZone::LeapSeconds> leapChanges;
QList<int> utcOffsets;
QList<QByteArray> abbreviations;
int preUtcOffset; // UTC offset to use before the first phase
KTimeZoneDataPrivate() : preUtcOffset(0) {}
// Find the last transition before a specified UTC or local date/time.
int transitionIndex(const QDateTime &dt) const;
bool transitionIndexes(const QDateTime &start, const QDateTime &end, int &ixstart, int &ixend) const;
bool isSecondOccurrence(const QDateTime &utcLocalTime, int transitionIndex) const;
};
/******************************************************************************/
class KTimeZonePrivate : public QSharedData
{
public:
KTimeZonePrivate() : source(0), data(0), refCount(1), cachedTransitionIndex(-1) {}
KTimeZonePrivate(KTimeZoneSource *src, const QString& nam,
const QString &country, float lat, float lon, const QString &cmnt);
KTimeZonePrivate(const KTimeZonePrivate &);
~KTimeZonePrivate() { delete data; }
KTimeZonePrivate &operator=(const KTimeZonePrivate &);
static KTimeZoneSource *utcSource();
static void cleanup();
KTimeZoneSource *source;
QString name;
QString countryCode;
QString comment;
float latitude;
float longitude;
mutable KTimeZoneData *data;
int refCount; // holds the number of KTimeZoneBackend instances using the KTimeZonePrivate instance as a d-pointer.
int cachedTransitionIndex;
QDateTime cachedTransitionStartZoneTime;
QDateTime cachedTransitionEndZoneTime;
bool cachedTransitionTimesValid;
private:
static KTimeZoneSource *mUtcSource;
};
KTimeZoneSource *KTimeZonePrivate::mUtcSource = 0;
KTimeZonePrivate::KTimeZonePrivate(KTimeZoneSource *src, const QString& nam,
const QString &country, float lat, float lon, const QString &cmnt)
: source(src),
name(nam),
countryCode(country.toUpper()),
comment(cmnt),
latitude(lat),
longitude(lon),
data(0),
refCount(1),
cachedTransitionIndex(-1)
{
// Detect duff values.
if (latitude > 90 || latitude < -90)
latitude = KTimeZone::UNKNOWN;
if (longitude > 180 || longitude < -180)
longitude = KTimeZone::UNKNOWN;
}
KTimeZonePrivate::KTimeZonePrivate(const KTimeZonePrivate &rhs)
: QSharedData(rhs),
source(rhs.source),
name(rhs.name),
countryCode(rhs.countryCode),
comment(rhs.comment),
latitude(rhs.latitude),
longitude(rhs.longitude),
refCount(1),
cachedTransitionIndex(rhs.cachedTransitionIndex),
cachedTransitionStartZoneTime(rhs.cachedTransitionStartZoneTime),
cachedTransitionEndZoneTime(rhs.cachedTransitionEndZoneTime),
cachedTransitionTimesValid(rhs.cachedTransitionTimesValid)
{
if (rhs.data)
data = rhs.data->clone();
else
data = 0;
}
KTimeZonePrivate &KTimeZonePrivate::operator=(const KTimeZonePrivate &rhs)
{
// Changing the contents of a KTimeZonePrivate instance by means of operator=() doesn't affect how
// many references to it are held.
source = rhs.source;
name = rhs.name;
countryCode = rhs.countryCode;
comment = rhs.comment;
latitude = rhs.latitude;
longitude = rhs.longitude;
cachedTransitionIndex = rhs.cachedTransitionIndex;
cachedTransitionStartZoneTime = rhs.cachedTransitionStartZoneTime;
cachedTransitionEndZoneTime = rhs.cachedTransitionEndZoneTime;
cachedTransitionTimesValid = rhs.cachedTransitionTimesValid;
delete data;
if (rhs.data)
data = rhs.data->clone();
else
data = 0;
// refCount is unchanged
return *this;
}
KTimeZoneSource *KTimeZonePrivate::utcSource()
{
if (!mUtcSource)
{
mUtcSource = new KTimeZoneSource;
qAddPostRoutine(KTimeZonePrivate::cleanup);
}
return mUtcSource;
}
void KTimeZonePrivate::cleanup()
{
delete mUtcSource;
}
/******************************************************************************/
K_GLOBAL_STATIC(KTimeZonePrivate, s_emptyTimeZonePrivate)
KTimeZoneBackend::KTimeZoneBackend()
: d(&*s_emptyTimeZonePrivate)
{
++d->refCount;
}
KTimeZoneBackend::KTimeZoneBackend(const QString &name)
: d(new KTimeZonePrivate(KTimeZonePrivate::utcSource(), name, QString(), KTimeZone::UNKNOWN, KTimeZone::UNKNOWN, QString()))
{}
KTimeZoneBackend::KTimeZoneBackend(KTimeZoneSource *source, const QString &name,
const QString &countryCode, float latitude, float longitude, const QString &comment)
: d(new KTimeZonePrivate(source, name, countryCode, latitude, longitude, comment))
{}
KTimeZoneBackend::KTimeZoneBackend(const KTimeZoneBackend &other)
: d(other.d)
{
++d->refCount;
}
KTimeZoneBackend::~KTimeZoneBackend()
{
if (d && --d->refCount == 0)
delete d;
d = 0;
}
KTimeZoneBackend &KTimeZoneBackend::operator=(const KTimeZoneBackend &other)
{
if (d != other.d)
{
if (--d->refCount == 0)
delete d;
d = other.d;
++d->refCount;
}
return *this;
}
QByteArray KTimeZoneBackend::type() const
{
return "KTimeZone";
}
KTimeZoneBackend *KTimeZoneBackend::clone() const
{
return new KTimeZoneBackend(*this);
}
int KTimeZoneBackend::offsetAtZoneTime(const KTimeZone* caller, const QDateTime &zoneDateTime, int *secondOffset) const
{
if (!zoneDateTime.isValid() || zoneDateTime.timeSpec() != Qt::LocalTime) // check for invalid time
{
if (secondOffset)
*secondOffset = 0;
return 0;
}
- QList<KTimeZone::Transition> transitions = caller->transitions();
+ const QList<KTimeZone::Transition> transitions = caller->transitions();
int index = d->cachedTransitionIndex;
if (index >= 0 && index < transitions.count())
{
// There is a cached transition - check whether zoneDateTime uses it.
// Caching is used because this method has been found to consume
// significant CPU in real life applications.
if (!d->cachedTransitionTimesValid)
{
- int offset = transitions.at(index).phase().utcOffset();
- int preoffset = (index > 0) ? transitions.at(index - 1).phase().utcOffset() : d->data ? d->data->previousUtcOffset() : 0;
- d->cachedTransitionStartZoneTime = transitions.at(index).time().addSecs(qMax(offset, preoffset));
+ const int offset = transitions[index].phase().utcOffset();
+ const int preoffset = (index > 0) ? transitions[index - 1].phase().utcOffset() : d->data ? d->data->previousUtcOffset() : 0;
+ d->cachedTransitionStartZoneTime = transitions[index].time().addSecs(qMax(offset, preoffset));
if (index + 1 < transitions.count())
{
- int postoffset = transitions.at(index + 1).phase().utcOffset();
- d->cachedTransitionEndZoneTime = transitions.at(index + 1).time().addSecs(qMin(offset, postoffset));
+ const int postoffset = transitions[index + 1].phase().utcOffset();
+ d->cachedTransitionEndZoneTime = transitions[index + 1].time().addSecs(qMin(offset, postoffset));
}
d->cachedTransitionTimesValid = true;
}
QDateTime dtutc = zoneDateTime;
dtutc.setTimeSpec(Qt::UTC);
if (dtutc >= d->cachedTransitionStartZoneTime
&& (index + 1 >= transitions.count() || dtutc < d->cachedTransitionEndZoneTime))
{
// The time falls within the cached transition limits, so return its UTC offset
- int offset = transitions.at(index).phase().utcOffset();
+ const int offset = transitions[index].phase().utcOffset();
if (secondOffset)
*secondOffset = offset;
#ifdef COMPILING_TESTS
qDebug("-> Using cache"); // test output requires qDebug instead of kDebug
#endif
return offset;
}
}
// The time doesn't fall within the cached transition, or there isn't a cached transition
#ifdef COMPILING_TESTS
qDebug("-> No cache"); // test output requires qDebug instead of kDebug
#endif
bool validTime;
int secondIndex = -1;
index = caller->transitionIndex(zoneDateTime, (secondOffset ? &secondIndex : 0), &validTime);
- const KTimeZone::Transition* tr = (index >= 0) ? &transitions.at(index) : 0;
- int offset = tr ? tr->phase().utcOffset()
- : validTime ? (d->data ? d->data->previousUtcOffset() : 0)
- : KTimeZone::InvalidOffset;
+ const KTimeZone::Transition* tr = (index >= 0) ? &transitions[index] : 0;
+ const int offset = tr ? tr->phase().utcOffset()
+ : validTime ? (d->data ? d->data->previousUtcOffset() : 0)
+ : KTimeZone::InvalidOffset;
if (secondOffset)
*secondOffset = (secondIndex >= 0) ? transitions.at(secondIndex).phase().utcOffset() : offset;
// Cache transition data for subsequent date/time values which occur after the same transition.
d->cachedTransitionIndex = index;
d->cachedTransitionTimesValid = false;
return offset;
}
int KTimeZoneBackend::offsetAtUtc(const KTimeZone* caller, const QDateTime &utcDateTime) const
{
if (!utcDateTime.isValid() || utcDateTime.timeSpec() != Qt::UTC) // check for invalid time
return 0;
- QList<KTimeZone::Transition> transitions = caller->transitions();
+ const QList<KTimeZone::Transition> transitions = caller->transitions();
int index = d->cachedTransitionIndex;
if (index >= 0 && index < transitions.count())
{
// There is a cached transition - check whether utcDateTime uses it.
- int offset = transitions.at(index).phase().utcOffset();
- if (utcDateTime >= transitions.at(index).time()
+ if (utcDateTime >= transitions[index].time()
&& (index + 1 >= transitions.count()
- || utcDateTime < transitions.at(index + 1).time()))
+ || utcDateTime < transitions[index + 1].time()))
{
// The time falls within the cached transition, so return its UTC offset
#ifdef COMPILING_TESTS
qDebug("Using cache"); // test output requires qDebug instead of kDebug
#endif
- return offset;
+ return transitions[index].phase().utcOffset();
}
}
// The time doesn't fall within the cached transition, or there isn't a cached transition
#ifdef COMPILING_TESTS
qDebug("No cache"); // test output requires qDebug instead of kDebug
#endif
index = caller->transitionIndex(utcDateTime);
d->cachedTransitionIndex = index; // cache transition data
d->cachedTransitionTimesValid = false;
const KTimeZone::Transition* tr = (index >= 0) ? &transitions.at(index) : 0;
return tr ? tr->phase().utcOffset() : (d->data ? d->data->previousUtcOffset() : 0);
}
int KTimeZoneBackend::offset(const KTimeZone* caller, time_t t) const
{
return offsetAtUtc(caller, KTimeZone::fromTime_t(t));
}
bool KTimeZoneBackend::isDstAtUtc(const KTimeZone* caller, const QDateTime &utcDateTime) const
{
if (!utcDateTime.isValid() || utcDateTime.timeSpec() != Qt::UTC) // check for invalid time
return false;
const KTimeZone::Transition *tr = caller->transition(utcDateTime);
if (!tr)
return false;
return tr->phase().isDst();
}
bool KTimeZoneBackend::isDst(const KTimeZone* caller, time_t t) const
{
return isDstAtUtc(caller, KTimeZone::fromTime_t(t));
}
bool KTimeZoneBackend::hasTransitions(const KTimeZone* caller) const
{
Q_UNUSED(caller);
return false;
}
/******************************************************************************/
#if SIZEOF_TIME_T == 8
const time_t KTimeZone::InvalidTime_t = 0x800000000000000LL;
#else
const time_t KTimeZone::InvalidTime_t = 0x80000000;
#endif
const int KTimeZone::InvalidOffset = 0x80000000;
const float KTimeZone::UNKNOWN = 1000.0;
KTimeZone::KTimeZone()
: d(new KTimeZoneBackend())
{}
KTimeZone::KTimeZone(const QString &name)
: d(new KTimeZoneBackend(name))
{}
KTimeZone::KTimeZone(const KTimeZone &tz)
: d(tz.d->clone())
{}
KTimeZone::~KTimeZone()
{
delete d;
}
KTimeZone::KTimeZone(KTimeZoneBackend *impl)
: d(impl)
{
// 'impl' should be a newly constructed object, with refCount = 1
Q_ASSERT(d->d->refCount == 1 || d->d == &*s_emptyTimeZonePrivate);
}
KTimeZone &KTimeZone::operator=(const KTimeZone &tz)
{
if (d != tz.d)
{
delete d;
d = tz.d->clone();
}
return *this;
}
bool KTimeZone::operator==(const KTimeZone &rhs) const
{
return d->d == rhs.d->d;
}
QByteArray KTimeZone::type() const
{
return d->type();
}
bool KTimeZone::isValid() const
{
return !d->d->name.isEmpty();
}
QString KTimeZone::countryCode() const
{
return d->d->countryCode;
}
float KTimeZone::latitude() const
{
return d->d->latitude;
}
float KTimeZone::longitude() const
{
return d->d->longitude;
}
QString KTimeZone::comment() const
{
return d->d->comment;
}
QString KTimeZone::name() const
{
return d->d->name;
}
QList<QByteArray> KTimeZone::abbreviations() const
{
if (!data(true))
return QList<QByteArray>();
return d->d->data->abbreviations();
}
QByteArray KTimeZone::abbreviation(const QDateTime &utcDateTime) const
{
if (utcDateTime.timeSpec() != Qt::UTC || !data(true))
return QByteArray();
return d->d->data->abbreviation(utcDateTime);
}
QList<int> KTimeZone::utcOffsets() const
{
if (!data(true))
return QList<int>();
return d->d->data->utcOffsets();
}
QList<KTimeZone::Phase> KTimeZone::phases() const
{
if (!data(true))
return QList<KTimeZone::Phase>();
return d->d->data->phases();
}
bool KTimeZone::hasTransitions() const
{
return d->hasTransitions(this);
}
QList<KTimeZone::Transition> KTimeZone::transitions(const QDateTime &start, const QDateTime &end) const
{
if (!data(true))
return QList<KTimeZone::Transition>();
return d->d->data->transitions(start, end);
}
const KTimeZone::Transition *KTimeZone::transition(const QDateTime &dt, const Transition **secondTransition,
bool *validTime) const
{
if (!data(true))
return 0;
return d->d->data->transition(dt, secondTransition, validTime);
}
int KTimeZone::transitionIndex(const QDateTime &dt, int *secondIndex, bool *validTime) const
{
if (!data(true))
return -1;
return d->d->data->transitionIndex(dt, secondIndex, validTime);
}
QList<QDateTime> KTimeZone::transitionTimes(const Phase &phase, const QDateTime &start, const QDateTime &end) const
{
if (!data(true))
return QList<QDateTime>();
return d->d->data->transitionTimes(phase, start, end);
}
QList<KTimeZone::LeapSeconds> KTimeZone::leapSecondChanges() const
{
if (!data(true))
return QList<KTimeZone::LeapSeconds>();
return d->d->data->leapSecondChanges();
}
KTimeZoneSource *KTimeZone::source() const
{
return d->d->source;
}
const KTimeZoneData *KTimeZone::data(bool create) const
{
if (!isValid())
return 0;
if (create && !d->d->data && d->d->source->useZoneParse())
d->d->data = d->d->source->parse(*this);
return d->d->data;
}
void KTimeZone::setData(KTimeZoneData *data, KTimeZoneSource *source)
{
if (!isValid())
return;
delete d->d->data;
d->d->data = data;
if (source)
d->d->source = source;
}
bool KTimeZone::updateBase(const KTimeZone &other)
{
if (d->d->name.isEmpty() || d->d->name != other.d->d->name)
return false;
d->d->countryCode = other.d->d->countryCode;
d->d->comment = other.d->d->comment;
d->d->latitude = other.d->d->latitude;
d->d->longitude = other.d->d->longitude;
return true;
}
bool KTimeZone::parse() const
{
if (!isValid())
return false;
if (d->d->source->useZoneParse())
{
delete d->d->data;
d->d->data = d->d->source->parse(*this);
}
return d->d->data;
}
QDateTime KTimeZone::toUtc(const QDateTime &zoneDateTime) const
{
if (!zoneDateTime.isValid() || zoneDateTime.timeSpec() != Qt::LocalTime)
return QDateTime();
- int secs = offsetAtZoneTime(zoneDateTime);
+ const int secs = offsetAtZoneTime(zoneDateTime);
if (secs == InvalidOffset)
return QDateTime();
QDateTime dt = zoneDateTime;
dt.setTimeSpec(Qt::UTC);
return dt.addSecs(-secs);
}
QDateTime KTimeZone::toZoneTime(const QDateTime &utcDateTime, bool *secondOccurrence) const
{
if (secondOccurrence)
*secondOccurrence = false;
if (!utcDateTime.isValid() || utcDateTime.timeSpec() != Qt::UTC) // check for invalid time
return QDateTime();
// Convert UTC to local time
if (hasTransitions())
{
if (!data(true))
{
// No data - default to UTC
QDateTime dt = utcDateTime;
dt.setTimeSpec(Qt::LocalTime);
return dt;
}
- int index = d->d->data->transitionIndex(utcDateTime);
- int secs = (index >= 0) ? d->d->data->transitions().at(index).phase().utcOffset() : d->d->data->previousUtcOffset();
+ const KTimeZoneData *data = d->d->data;
+ const int index = data->transitionIndex(utcDateTime);
+ const int secs = (index >= 0) ? data->transitions()[index].phase().utcOffset() : data->previousUtcOffset();
QDateTime dt = utcDateTime.addSecs(secs);
if (secondOccurrence)
{
// Check whether the local time occurs twice around a daylight savings time
// shift, and if so, whether it's the first or second occurrence.
- *secondOccurrence = d->d->data->d->isSecondOccurrence(dt, index);
+ *secondOccurrence = data->d->isSecondOccurrence(dt, index);
}
dt.setTimeSpec(Qt::LocalTime);
return dt;
}
else
{
- int secs = offsetAtUtc(utcDateTime);
+ const int secs = offsetAtUtc(utcDateTime);
QDateTime dt = utcDateTime.addSecs(secs);
dt.setTimeSpec(Qt::LocalTime);
if (secondOccurrence)
{
// Check whether the local time occurs twice around a daylight savings time
// shift, and if so, whether it's the first or second occurrence.
*secondOccurrence = (secs != offsetAtZoneTime(dt));
}
return dt;
}
}
QDateTime KTimeZone::convert(const KTimeZone &newZone, const QDateTime &zoneDateTime) const
{
if (newZone == *this)
{
if (zoneDateTime.timeSpec() != Qt::LocalTime)
return QDateTime();
return zoneDateTime;
}
return newZone.toZoneTime(toUtc(zoneDateTime));
}
int KTimeZone::offsetAtZoneTime(const QDateTime &zoneDateTime, int *secondOffset) const
{
return d->offsetAtZoneTime(this, zoneDateTime, secondOffset);
}
int KTimeZone::offsetAtUtc(const QDateTime &utcDateTime) const
{
return d->offsetAtUtc(this, utcDateTime);
}
int KTimeZone::offset(time_t t) const
{
return d->offset(this, t);
}
int KTimeZone::currentOffset(Qt::TimeSpec basis) const
{
// Get current offset of this time zone to UTC
- time_t now = time(0);
- int secs = offset(now);
+ const time_t now = time(0);
+ const int secs = offset(now);
switch (basis)
{
case Qt::LocalTime:
// Return the current offset of this time zone to the local system time
return secs - gmtoff(now);
case Qt::UTC:
// Return the current offset of this time zone to UTC
return secs;
default:
break;
}
return 0;
}
bool KTimeZone::isDstAtUtc(const QDateTime &utcDateTime) const
{
return d->isDstAtUtc(this, utcDateTime);
}
bool KTimeZone::isDst(time_t t) const
{
return d->isDst(this, t);
}
KTimeZone KTimeZone::utc()
{
static KTimeZone utcZone(QLatin1String("UTC"));
return utcZone;
}
QDateTime KTimeZone::fromTime_t(time_t t)
{
static const int secondsADay = 86400;
static const QDate epochDate(1970,1,1);
static const QTime epochTime(0,0,0);
int days = t / secondsADay;
int secs;
if (t >= 0)
secs = t % secondsADay;
else
{
secs = secondsADay - (-t % secondsADay);
--days;
}
return QDateTime(epochDate.addDays(days), epochTime.addSecs(secs), Qt::UTC);
}
time_t KTimeZone::toTime_t(const QDateTime &utcDateTime)
{
static const QDate epochDate(1970,1,1);
static const QTime epochTime(0,0,0);
if (utcDateTime.timeSpec() != Qt::UTC)
return InvalidTime_t;
- qint64 days = epochDate.daysTo(utcDateTime.date());
- qint64 secs = epochTime.secsTo(utcDateTime.time());
- qint64 t64 = days * 86400 + secs;
- time_t t = static_cast<time_t>(t64);
+ const qint64 days = epochDate.daysTo(utcDateTime.date());
+ const qint64 secs = epochTime.secsTo(utcDateTime.time());
+ const qint64 t64 = days * 86400 + secs;
+ const time_t t = static_cast<time_t>(t64);
if (static_cast<qint64>(t) != t64)
return InvalidTime_t;
return t;
}
/******************************************************************************/
class KTimeZoneSourcePrivate
{
public:
bool mUseZoneParse;
};
KTimeZoneSource::KTimeZoneSource()
: d(new KTimeZoneSourcePrivate)
{
d->mUseZoneParse = true;
}
KTimeZoneSource::KTimeZoneSource(bool useZoneParse)
: d(new KTimeZoneSourcePrivate)
{
d->mUseZoneParse = useZoneParse;
}
KTimeZoneSource::~KTimeZoneSource()
{
delete d;
}
KTimeZoneData *KTimeZoneSource::parse(const KTimeZone &) const
{
Q_ASSERT(d->mUseZoneParse); // method should never be called if it isn't usable
return new KTimeZoneData;
}
bool KTimeZoneSource::useZoneParse() const
{
return d->mUseZoneParse;
}
/******************************************************************************/
class KTimeZoneLeapSecondsPrivate
{
public:
QDateTime dt; // UTC time when this change occurred
QString comment; // optional comment
int seconds; // number of leap seconds
};
KTimeZone::LeapSeconds::LeapSeconds()
: d(new KTimeZoneLeapSecondsPrivate)
{
}
KTimeZone::LeapSeconds::LeapSeconds(const QDateTime &utc, int leap, const QString &cmt)
: d(new KTimeZoneLeapSecondsPrivate)
{
if (utc.timeSpec() == Qt::UTC) // invalid if start time is not UTC
{
d->dt = utc;
d->comment = cmt;
d->seconds = leap;
}
}
KTimeZone::LeapSeconds::LeapSeconds(const KTimeZone::LeapSeconds &c)
: d(new KTimeZoneLeapSecondsPrivate)
{
d->dt = c.d->dt;
d->comment = c.d->comment;
d->seconds = c.d->seconds;
}
KTimeZone::LeapSeconds::~LeapSeconds()
{
delete d;
}
KTimeZone::LeapSeconds &KTimeZone::LeapSeconds::operator=(const KTimeZone::LeapSeconds &c)
{
d->dt = c.d->dt;
d->comment = c.d->comment;
d->seconds = c.d->seconds;
return *this;
}
bool KTimeZone::LeapSeconds::operator<(const KTimeZone::LeapSeconds& c) const
{
return d->dt < c.d->dt;
}
QDateTime KTimeZone::LeapSeconds::dateTime() const
{
return d->dt;
}
bool KTimeZone::LeapSeconds::isValid() const
{
return d->dt.isValid();
}
int KTimeZone::LeapSeconds::leapSeconds() const
{
return d->seconds;
}
QString KTimeZone::LeapSeconds::comment() const
{
return d->comment;
}
/******************************************************************************/
int KTimeZoneDataPrivate::transitionIndex(const QDateTime &dt) const
{
// Do a binary search to find the last transition before this date/time
int start = -1;
int end = transitions.count();
if (dt.timeSpec() == Qt::UTC)
{
while (end - start > 1)
{
int i = (start + end) / 2;
if (dt < transitions[i].time())
end = i;
else
start = i;
}
}
else
{
QDateTime dtutc = dt;
dtutc.setTimeSpec(Qt::UTC);
while (end - start > 1)
{
- int i = (start + end) / 2;
+ const int i = (start + end) / 2;
if (dtutc.addSecs(-transitions[i].phase().utcOffset()) < transitions[i].time())
end = i;
else
start = i;
}
}
return end ? start : -1;
}
// Find the indexes to the transitions at or after start, and before or at end.
// start and end must be UTC.
// Reply = false if none.
bool KTimeZoneDataPrivate::transitionIndexes(const QDateTime &start, const QDateTime &end, int &ixstart, int &ixend) const
{
ixstart = 0;
if (start.isValid() && start.timeSpec() == Qt::UTC)
{
ixstart = transitionIndex(start);
if (ixstart < 0)
ixstart = 0;
else if (transitions[ixstart].time() < start)
{
if (++ixstart >= transitions.count())
return false; // there are no transitions at/after 'start'
}
}
ixend = -1;
if (end.isValid() && end.timeSpec() == Qt::UTC)
{
ixend = transitionIndex(end);
if (ixend < 0)
return false; // there are no transitions at/before 'end'
}
return true;
}
/* Check if it's a local time which occurs both before and after the specified
* transition (for which it has to span a daylight saving to standard time change).
* @param utcLocalTime local time set to Qt::UTC
*/
bool KTimeZoneDataPrivate::isSecondOccurrence(const QDateTime &utcLocalTime, int transitionIndex) const
{
if (transitionIndex < 0)
return false;
- int offset = transitions[transitionIndex].phase().utcOffset();
- int prevoffset = (transitionIndex > 0) ? transitions[transitionIndex-1].phase().utcOffset() : preUtcOffset;
- int phaseDiff = prevoffset - offset;
+ const int offset = transitions[transitionIndex].phase().utcOffset();
+ const int prevoffset = (transitionIndex > 0) ? transitions[transitionIndex-1].phase().utcOffset() : preUtcOffset;
+ const int phaseDiff = prevoffset - offset;
if (phaseDiff <= 0)
return false;
// Find how long after the start of the latest phase 'dt' is
- int afterStart = transitions[transitionIndex].time().secsTo(utcLocalTime) - offset;
+ const int afterStart = transitions[transitionIndex].time().secsTo(utcLocalTime) - offset;
return (afterStart < phaseDiff);
}
KTimeZoneData::KTimeZoneData()
: d(new KTimeZoneDataPrivate)
{ }
KTimeZoneData::KTimeZoneData(const KTimeZoneData &c)
: d(new KTimeZoneDataPrivate)
{
d->phases = c.d->phases;
d->transitions = c.d->transitions;
d->leapChanges = c.d->leapChanges;
d->utcOffsets = c.d->utcOffsets;
d->abbreviations = c.d->abbreviations;
d->preUtcOffset = c.d->preUtcOffset;
}
KTimeZoneData::~KTimeZoneData()
{
delete d;
}
KTimeZoneData &KTimeZoneData::operator=(const KTimeZoneData &c)
{
d->phases = c.d->phases;
d->transitions = c.d->transitions;
d->leapChanges = c.d->leapChanges;
d->utcOffsets = c.d->utcOffsets;
d->abbreviations = c.d->abbreviations;
d->preUtcOffset = c.d->preUtcOffset;
return *this;
}
KTimeZoneData *KTimeZoneData::clone() const
{
return new KTimeZoneData(*this);
}
QList<QByteArray> KTimeZoneData::abbreviations() const
{
if (d->abbreviations.isEmpty())
{
for (int i = 0, end = d->phases.count(); i < end; ++i)
{
const QList<QByteArray> abbrevs = d->phases[i].abbreviations();
for (int j = 0, jend = abbrevs.count(); j < jend; ++j)
if (!d->abbreviations.contains(abbrevs[j]))
d->abbreviations.append(abbrevs[j]);
}
if (d->abbreviations.isEmpty())
d->abbreviations += "UTC";
}
return d->abbreviations;
}
QByteArray KTimeZoneData::abbreviation(const QDateTime &utcDateTime) const
{
if (d->phases.isEmpty())
return "UTC";
const KTimeZone::Transition *tr = transition(utcDateTime);
if (!tr)
return QByteArray();
const QList<QByteArray> abbrevs = tr->phase().abbreviations();
if (abbrevs.isEmpty())
return QByteArray();
return abbrevs[0];
}
QList<int> KTimeZoneData::utcOffsets() const
{
if (d->utcOffsets.isEmpty())
{
for (int i = 0, end = d->phases.count(); i < end; ++i)
{
- int offset = d->phases[i].utcOffset();
+ const int offset = d->phases[i].utcOffset();
if (!d->utcOffsets.contains(offset))
d->utcOffsets.append(offset);
}
if (d->utcOffsets.isEmpty())
d->utcOffsets += 0;
else
qSort(d->utcOffsets);
}
return d->utcOffsets;
}
QList<KTimeZone::Phase> KTimeZoneData::phases() const
{
return d->phases;
}
void KTimeZoneData::setPhases(const QList<KTimeZone::Phase> &phases, int previousUtcOffset)
{
d->phases = phases;
d->preUtcOffset = previousUtcOffset;
}
bool KTimeZoneData::hasTransitions() const
{
return false;
}
QList<KTimeZone::Transition> KTimeZoneData::transitions(const QDateTime &start, const QDateTime &end) const
{
int ixstart, ixend;
if (!d->transitionIndexes(start, end, ixstart, ixend))
return QList<KTimeZone::Transition>(); // there are no transitions within the time period
if (ixend >= 0)
return d->transitions.mid(ixstart, ixend - ixstart + 1);
if (ixstart > 0)
return d->transitions.mid(ixstart);
return d->transitions;
}
void KTimeZoneData::setTransitions(const QList<KTimeZone::Transition> &transitions)
{
d->transitions = transitions;
}
int KTimeZoneData::previousUtcOffset() const
{
return d->preUtcOffset;
}
const KTimeZone::Transition *KTimeZoneData::transition(const QDateTime &dt, const KTimeZone::Transition **secondTransition,
bool *validTime) const
{
int secondIndex;
- int index = transitionIndex(dt, (secondTransition ? &secondIndex : 0), validTime);
+ const int index = transitionIndex(dt, (secondTransition ? &secondIndex : 0), validTime);
if (secondTransition)
*secondTransition = (secondIndex >= 0) ? &d->transitions[secondIndex] : 0;
return (index >= 0) ? &d->transitions[index] : 0;
}
int KTimeZoneData::transitionIndex(const QDateTime &dt, int *secondIndex, bool *validTime) const
{
if (validTime)
*validTime = true;
// Find the last transition before this date/time
int index = d->transitionIndex(dt);
if (dt.timeSpec() == Qt::UTC)
{
if (secondIndex)
*secondIndex = index;
return index;
}
else
{
/* Check whether the specified local time actually occurs.
* Find the start of the next phase, and check if it falls in the gap
* between the two phases.
*/
QDateTime dtutc = dt;
dtutc.setTimeSpec(Qt::UTC);
- int count = d->transitions.count();
- int next = (index >= 0) ? index + 1 : 0;
+ const int count = d->transitions.count();
+ const int next = (index >= 0) ? index + 1 : 0;
if (next < count)
{
KTimeZone::Phase nextPhase = d->transitions[next].phase();
- int offset = (index >= 0) ? d->transitions[index].phase().utcOffset() : d->preUtcOffset;
- int phaseDiff = nextPhase.utcOffset() - offset;
+ const int offset = (index >= 0) ? d->transitions[index].phase().utcOffset() : d->preUtcOffset;
+ const int phaseDiff = nextPhase.utcOffset() - offset;
if (phaseDiff > 0)
{
// Get UTC equivalent as if 'dt' was in the next phase
if (dtutc.secsTo(d->transitions[next].time()) + nextPhase.utcOffset() < phaseDiff)
{
// The time falls in the gap between the two phases,
// so return an invalid value.
if (validTime)
*validTime = false;
if (secondIndex)
*secondIndex = -1;
return -1;
}
}
}
if (index < 0)
{
// The specified time is before the first phase
if (secondIndex)
*secondIndex = -1;
return -1;
}
/* Check if it's a local time which occurs both before and after the 'latest'
* phase start time (for which it has to span a daylight saving to standard
* time change).
*/
bool duplicate = true;
if (d->isSecondOccurrence(dtutc, index))
{
// 'dt' occurs twice
if (secondIndex)
{
*secondIndex = index;
duplicate = false;
}
// Get the transition containing the first occurrence of 'dt'
if (index <= 0)
return -1; // first occurrence of 'dt' is just before the first transition
--index;
}
if (secondIndex && duplicate)
*secondIndex = index;
return index;
}
}
QList<QDateTime> KTimeZoneData::transitionTimes(const KTimeZone::Phase &phase, const QDateTime &start, const QDateTime &end) const
{
QList<QDateTime> times;
int ixstart, ixend;
if (d->transitionIndexes(start, end, ixstart, ixend))
{
if (ixend < 0)
ixend = d->transitions.count() - 1;
while (ixstart <= ixend)
{
if (d->transitions[ixstart].phase() == phase)
times += d->transitions[ixstart].time();
}
}
return times;
}
QList<KTimeZone::LeapSeconds> KTimeZoneData::leapSecondChanges() const
{
return d->leapChanges;
}
void KTimeZoneData::setLeapSecondChanges(const QList<KTimeZone::LeapSeconds> &adjusts)
{
d->leapChanges = adjusts;
}
KTimeZone::LeapSeconds KTimeZoneData::leapSecondChange(const QDateTime &utc) const
{
if (utc.timeSpec() != Qt::UTC)
kError() << "KTimeZoneData::leapSecondChange(): non-UTC time specified" << endl;
else
{
for (int i = d->leapChanges.count(); --i >= 0; )
{
if (d->leapChanges[i].dateTime() < utc)
return d->leapChanges[i];
}
}
return KTimeZone::LeapSeconds();
}
diff --git a/kdecore/date/ktzfiletimezone.cpp b/kdecore/date/ktzfiletimezone.cpp
index bf33d71926..4de10e2e59 100644
--- a/kdecore/date/ktzfiletimezone.cpp
+++ b/kdecore/date/ktzfiletimezone.cpp
@@ -1,414 +1,414 @@
/*
This file is part of the KDE libraries
Copyright (c) 2005-2008 David Jarvie <djarvie@kde.org>
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.
*/
#include "ktzfiletimezone.h"
#include <config.h>
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#include <QtCore/QFile>
#include <QtCore/QDataStream>
#include <QtCore/QVector>
#include <kdebug.h>
// Use this replacement for QDateTime::setTime_t(uint) since our time
// values are signed.
static QDateTime fromTime_t(qint32 seconds)
{
static const QDate epochDate(1970,1,1);
static const QTime epochTime(0,0,0);
- int secs = (seconds >= 0) ? seconds % 86400 : -(-seconds % 86400);
+ const int secs = (seconds >= 0) ? seconds % 86400 : -(-seconds % 86400);
return QDateTime(epochDate.addDays(seconds / 86400), epochTime.addSecs(secs), Qt::UTC);
}
/******************************************************************************/
KTzfileTimeZoneBackend::KTzfileTimeZoneBackend(KTzfileTimeZoneSource *source, const QString &name,
const QString &countryCode, float latitude, float longitude, const QString &comment)
: KTimeZoneBackend(source, name, countryCode, latitude, longitude, comment)
{}
KTzfileTimeZoneBackend::~KTzfileTimeZoneBackend()
{}
KTimeZoneBackend *KTzfileTimeZoneBackend::clone() const
{
return new KTzfileTimeZoneBackend(*this);
}
QByteArray KTzfileTimeZoneBackend::type() const
{
return "KTzfileTimeZone";
}
bool KTzfileTimeZoneBackend::hasTransitions(const KTimeZone *caller) const
{
Q_UNUSED(caller)
return true;
}
/******************************************************************************/
KTzfileTimeZone::KTzfileTimeZone(KTzfileTimeZoneSource *source, const QString &name,
const QString &countryCode, float latitude, float longitude,
const QString &comment)
: KTimeZone(new KTzfileTimeZoneBackend(source, name, countryCode, latitude, longitude, comment))
{}
KTzfileTimeZone::~KTzfileTimeZone()
{}
/******************************************************************************/
class KTzfileTimeZoneDataPrivate
{
public:
};
KTzfileTimeZoneData::KTzfileTimeZoneData()
// : d(new KTzfileTimeZoneDataPrivate)
{ }
KTzfileTimeZoneData::KTzfileTimeZoneData(const KTzfileTimeZoneData &rhs)
: KTimeZoneData(rhs)
// d(new KTzfileTimeZoneDataPrivate)
{
}
KTzfileTimeZoneData::~KTzfileTimeZoneData()
{
// delete d;
}
KTzfileTimeZoneData &KTzfileTimeZoneData::operator=(const KTzfileTimeZoneData &rhs)
{
KTimeZoneData::operator=(rhs);
return *this;
}
KTimeZoneData *KTzfileTimeZoneData::clone() const
{
return new KTzfileTimeZoneData(*this);
}
bool KTzfileTimeZoneData::hasTransitions() const
{
return true;
}
/******************************************************************************/
class KTzfileTimeZoneSourcePrivate
{
public:
KTzfileTimeZoneSourcePrivate(const QString &loc)
: location(loc) {}
~KTzfileTimeZoneSourcePrivate() {}
QString location;
};
KTzfileTimeZoneSource::KTzfileTimeZoneSource(const QString &location)
: d(new KTzfileTimeZoneSourcePrivate(location))
{
if (location.length() > 1 && location.endsWith(QLatin1Char('/')))
d->location.chop(1);
}
KTzfileTimeZoneSource::~KTzfileTimeZoneSource()
{
delete d;
}
QString KTzfileTimeZoneSource::location() const
{
return d->location;
}
KTimeZoneData* KTzfileTimeZoneSource::parse(const KTimeZone &zone) const
{
quint32 abbrCharCount; // the number of characters of time zone abbreviation strings
quint32 ttisgmtcnt;
quint8 is;
quint8 T_, Z_, i_, f_; // tzfile identifier prefix
QString path = zone.name();
if (!path.startsWith(QLatin1Char('/')))
{
if (d->location == QLatin1String("/"))
path.prepend(d->location);
else
path = d->location + QLatin1Char('/') + path;
}
QFile f(path);
if (!f.open(QIODevice::ReadOnly))
{
kError() << "Cannot open " << f.fileName() << endl;
return 0;
}
QDataStream str(&f);
// Read the file type identifier
str >> T_ >> Z_ >> i_ >> f_;
if (T_ != 'T' || Z_ != 'Z' || i_ != 'i' || f_ != 'f')
{
kError() << "Not a TZFILE: " << f.fileName() << endl;
return 0;
}
// Discard 16 bytes reserved for future use
unsigned i;
for (i = 0; i < 4; ++i)
str >> ttisgmtcnt;
KTzfileTimeZoneData* data = new KTzfileTimeZoneData;
// Read the sizes of arrays held in the file
quint32 nTransitionTimes;
quint32 nLocalTimeTypes;
quint32 nLeapSecondAdjusts;
quint32 nIsStandard;
quint32 nIsUtc;
str >> nIsUtc
>> nIsStandard
>> nLeapSecondAdjusts
>> nTransitionTimes
>> nLocalTimeTypes
>> abbrCharCount;
// kDebug() << "header: " << nIsUtc << ", " << nIsStandard << ", " << nLeapSecondAdjusts << ", " <<
// nTransitionTimes << ", " << nLocalTimeTypes << ", " << abbrCharCount << endl;
// Read the transition times, at which the rules for computing local time change
struct TransitionTime
{
qint32 time; // time (as returned by time(2)) at which the rules for computing local time change
quint8 localTimeIndex; // index into the LocalTimeType array
};
//kDebug()<<"Reading zone "<<zone.name();
TransitionTime *transitionTimes = new TransitionTime[nTransitionTimes];
for (i = 0; i < nTransitionTimes; ++i)
{
str >> transitionTimes[i].time;
}
for (i = 0; i < nTransitionTimes; ++i)
{
str >> transitionTimes[i].localTimeIndex;
//kDebug() << "Transition time "<<i<<": "<<transitionTimes[i].time<<" lt index="<<(int)transitionTimes[i].localTimeIndex;
}
// Read the local time types
struct LocalTimeType
{
qint32 gmtoff; // number of seconds to be added to UTC
bool isdst; // whether tm_isdst should be set by localtime(3)
quint8 abbrIndex; // index into the list of time zone abbreviations
bool isutc; // transition times are in UTC. If UTC, isstd is ignored.
bool isstd; // if true, transition times are in standard time;
// if false, transition times are in wall clock time,
// i.e. standard time or daylight savings time
// whichever is current before the transition
};
LocalTimeType *localTimeTypes = new LocalTimeType[nLocalTimeTypes];
LocalTimeType *ltt = localTimeTypes;
for (i = 0; i < nLocalTimeTypes; ++ltt, ++i)
{
str >> ltt->gmtoff;
str >> is;
ltt->isdst = (is != 0);
str >> ltt->abbrIndex;
// kDebug() << "local type: " << ltt->gmtoff << ", " << is << ", " << ltt->abbrIndex;
ltt->isstd = false; // default if no data
ltt->isutc = false; // default if no data
}
// Read the timezone abbreviations. They are stored as null terminated strings in
// a character array.
// Make sure we don't fall foul of maliciously coded time zone abbreviations.
if (abbrCharCount > 64)
{
kError() << "excessive length for timezone abbreviations: " << abbrCharCount << endl;
delete data;
delete[] transitionTimes;
delete[] localTimeTypes;
return 0;
}
QByteArray array(abbrCharCount, 0);
str.readRawData(array.data(), array.size());
- char *abbrs = array.data();
+ const char *abbrs = array.data();
if (abbrs[abbrCharCount - 1] != 0)
{
// These abbreviations are corrupt!
kError() << "timezone abbreviations not null terminated: " << abbrs[abbrCharCount - 1] << endl;
delete data;
delete[] transitionTimes;
delete[] localTimeTypes;
return 0;
}
quint8 n = 0;
QList<QByteArray> abbreviations;
for (i = 0; i < abbrCharCount; ++n, i += strlen(abbrs + i) + 1)
{
abbreviations += QByteArray(abbrs + i);
// Convert the LocalTimeTypes pointer to a sequential index
ltt = localTimeTypes;
for (unsigned j = 0; j < nLocalTimeTypes; ++ltt, ++j)
{
if (ltt->abbrIndex == i)
ltt->abbrIndex = n;
}
}
// Read the leap second adjustments
qint32 t;
quint32 s;
QList<KTimeZone::LeapSeconds> leapChanges;
for (i = 0; i < nLeapSecondAdjusts; ++i)
{
str >> t >> s;
// kDebug() << "leap entry: " << t << ", " << s;
// Don't use QDateTime::setTime_t() because it takes an unsigned argument
leapChanges += KTimeZone::LeapSeconds(fromTime_t(t), static_cast<int>(s));
}
data->setLeapSecondChanges(leapChanges);
// Read the standard/wall time indicators.
// These are true if the transition times associated with local time types
// are specified as standard time, false if wall clock time.
for (i = 0; i < nIsStandard; ++i)
{
str >> is;
localTimeTypes[i].isstd = (is != 0);
// kDebug() << "standard: " << is;
}
// Read the UTC/local time indicators.
// These are true if the transition times associated with local time types
// are specified as UTC, false if local time.
for (i = 0; i < nIsUtc; ++i)
{
str >> is;
localTimeTypes[i].isutc = (is != 0);
// kDebug() << "UTC: " << is;
}
// Find the starting offset from UTC to use before the first transition time.
// This is first non-daylight savings local time type, or if there is none,
// the first local time type.
int firstoffset = (nLocalTimeTypes > 0) ? localTimeTypes[0].gmtoff : 0;
ltt = localTimeTypes;
for (i = 0; i < nLocalTimeTypes; ++ltt, ++i)
{
if (!ltt->isdst)
{
firstoffset = ltt->gmtoff;
break;
}
}
// Compile the time type data into a list of KTimeZone::Phase instances.
// Also check for local time types which are identical (this does happen)
// and use the same Phase instance for each.
QByteArray abbrev;
QList<KTimeZone::Phase> phases;
QList<QByteArray> phaseAbbrevs;
QVector<int> lttLookup(nLocalTimeTypes);
ltt = localTimeTypes;
for (i = 0; i < nLocalTimeTypes; ++ltt, ++i)
{
if (ltt->abbrIndex >= abbreviations.count())
{
kError() << "KTzfileTimeZoneSource::parse(): abbreviation index out of range" << endl;
abbrev = "???";
}
else
abbrev = abbreviations[ltt->abbrIndex];
// Check for an identical Phase
int phindex = 0;
for (int j = 0, jend = phases.count(); j < jend; ++j, ++phindex)
{
if (ltt->gmtoff == phases[j].utcOffset()
&& (bool)ltt->isdst == phases[j].isDst()
&& abbrev == phaseAbbrevs[j])
break;
}
lttLookup[i] = phindex;
if (phindex == phases.count())
{
phases += KTimeZone::Phase(ltt->gmtoff, abbrev, ltt->isdst);
phaseAbbrevs += abbrev;
}
}
data->setPhases(phases, firstoffset);
// Compile the transition list
QList<KTimeZone::Transition> transitions;
int stdoffset = firstoffset;
int offset = stdoffset;
TransitionTime *tt = transitionTimes;
for (i = 0; i < nTransitionTimes; ++tt, ++i)
{
if (tt->localTimeIndex >= nLocalTimeTypes)
{
kError() << "KTzfileTimeZoneSource::parse(): transition ignored: local time type out of range: " <<(int)tt->localTimeIndex<<" > "<<nLocalTimeTypes << endl;
continue;
}
// Convert local transition times to UTC
ltt = &localTimeTypes[tt->localTimeIndex];
if (!ltt->isutc)
{
/* The transition time is in local time, so convert it to UTC.
* If the transition is in "local wall clock time", use the UTC offset
* set up by the previous transition; otherwise, the transition is in
* standard time, so use the UTC offset set up by the last non-daylight
* savings time transition.
*/
tt->time -= ltt->isstd ? stdoffset : offset;
offset = ltt->gmtoff; // keep note of latest offset
if (!ltt->isdst)
stdoffset = offset; // keep note of latest standard time offset
}
- KTimeZone::Phase phase = phases[lttLookup[tt->localTimeIndex]];
+ const KTimeZone::Phase phase = phases[lttLookup[tt->localTimeIndex]];
//kDebug(161) << "Transition time "<<i<<": "<<fromTime_t(tt->time)<<", offset="<<phase.utcOffset()/60;
transitions += KTimeZone::Transition(fromTime_t(tt->time), phase);
}
data->setTransitions(transitions);
//for(int xxx=1;xxx<data->transitions().count();xxx++)
//kDebug(161) << "Transition time "<<xxx<<": "<<data->transitions()[xxx].time()<<", offset="<<data->transitions()[xxx].phase().utcOffset()/60;
delete[] localTimeTypes;
delete[] transitionTimes;
return data;
}

File Metadata

Mime Type
text/x-diff
Expires
Fri, Nov 1, 9:39 AM (1 d, 17 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
10076058
Default Alt Text
(84 KB)

Event Timeline