• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdelibs-4.14.38 API Reference
  • KDE Home
  • Contact Us
 

KDECore

  • kdecore
  • date
ksystemtimezone.cpp
Go to the documentation of this file.
1/*
2 This file is part of the KDE libraries
3 Copyright (c) 2005-2010 David Jarvie <djarvie@kde.org>
4 Copyright (c) 2005 S.R.Haque <srhaque@iee.org>.
5
6 This library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public
8 License as published by the Free Software Foundation; either
9 version 2 of the License, or (at your option) any later version.
10
11 This library is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Library General Public License for more details.
15
16 You should have received a copy of the GNU Library General Public License
17 along with this library; see the file COPYING.LIB. If not, write to
18 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20*/
21
22// This file requires HAVE_STRUCT_TM_TM_ZONE to be defined if struct tm member tm_zone is available.
23// This file requires HAVE_TM_GMTOFF to be defined if struct tm member tm_gmtoff is available.
24
25#include "ksystemtimezone.moc"
26
27#include <config.h>
28#include <config-date.h>
29
30#ifdef HAVE_SYS_TIME_H
31#include <sys/time.h>
32#endif
33#ifdef HAVE_TIME_H
34#include <time.h>
35#endif
36#include <climits>
37#include <cstdlib>
38
39#include <QtCore/QCoreApplication>
40#include <QtCore/QFile>
41#include <QtCore/QFileInfo>
42#include <QtCore/QDir>
43#include <QtCore/QRegExp>
44#include <QtCore/QStringList>
45#include <QtCore/QTextStream>
46#include <QtDBus/QDBusConnection>
47#include <QtDBus/QDBusInterface>
48#include <QtDBus/QDBusConnectionInterface>
49#include <QtDBus/QDBusReply>
50
51#include <kglobal.h>
52#include <klocale.h>
53#include <kcodecs.h>
54#include <kstringhandler.h>
55#include <ktemporaryfile.h>
56#include <ktoolinvocation.h>
57#include <kdebug.h>
58#include <kconfiggroup.h>
59#include "ktzfiletimezone.h"
60#ifdef Q_OS_WIN
61#include "ktimezone_win.h"
62#endif
63
64#define KTIMEZONED_DBUS_IFACE "org.kde.KTimeZoned"
65
66
67/* Return the offset to UTC in the current time zone at the specified UTC time.
68 * The thread-safe function localtime_r() is used in preference if available.
69 */
70int gmtoff(time_t t)
71{
72#ifdef _POSIX_THREAD_SAFE_FUNCTIONS
73 tm tmtime;
74 if (!localtime_r(&t, &tmtime))
75 return 0;
76#ifdef HAVE_TM_GMTOFF
77 return tmtime.tm_gmtoff;
78#else
79 int lwday = tmtime.tm_wday;
80 int lt = 3600*tmtime.tm_hour + 60*tmtime.tm_min + tmtime.tm_sec;
81 if (!gmtime_r(&t, &tmtime))
82 return 0;
83 int uwday = tmtime.tm_wday;
84 int ut = 3600*tmtime.tm_hour + 60*tmtime.tm_min + tmtime.tm_sec;
85#endif
86#else
87 tm *tmtime = localtime(&t);
88 if (!tmtime)
89 return 0;
90#ifdef HAVE_TM_GMTOFF
91 return tmtime->tm_gmtoff;
92#else
93 int lwday = tmtime->tm_wday;
94 int lt = 3600*tmtime->tm_hour + 60*tmtime->tm_min + tmtime->tm_sec;
95 tmtime = gmtime(&t);
96 int uwday = tmtime->tm_wday;
97 int ut = 3600*tmtime->tm_hour + 60*tmtime->tm_min + tmtime->tm_sec;
98#endif
99#endif
100#ifndef HAVE_TM_GMTOFF
101 if (lwday != uwday)
102 {
103 // Adjust for different day
104 if (lwday == uwday + 1 || (lwday == 0 && uwday == 6))
105 lt += 24*3600;
106 else
107 lt -= 24*3600;
108 }
109 return lt - ut;
110#endif
111}
112
113
114/******************************************************************************/
115
116class KSystemTimeZonesPrivate : public KTimeZones
117{
118public:
119 static KSystemTimeZonesPrivate *instance();
120 static KTzfileTimeZoneSource *tzfileSource();
121 static void setLocalZone();
122 static void cleanup();
123 static void readConfig(bool init);
124#ifdef Q_OS_WIN
125 static void updateTimezoneInformation()
126 {
127 instance()->updateTimezoneInformation(true);
128 }
129#else
130 static void updateZonetab() { instance()->readZoneTab(true); }
131#endif
132
133 static KTimeZone m_localZone;
134 static QString m_localZoneName;
135 static QString m_zoneinfoDir;
136 static QString m_zonetab;
137 static KSystemTimeZoneSource *m_source;
138 static bool m_ktimezonedError;
139
140private:
141 KSystemTimeZonesPrivate() {}
142#ifdef Q_OS_WIN
143 void updateTimezoneInformation(bool update);
144#else
145 void readZoneTab(bool update);
146 static float convertCoordinate(const QString &coordinate);
147#endif
148
149 static KSystemTimeZones *m_parent;
150 static KSystemTimeZonesPrivate *m_instance;
151 static KTzfileTimeZoneSource *m_tzfileSource;
152};
153
154KTimeZone KSystemTimeZonesPrivate::m_localZone;
155QString KSystemTimeZonesPrivate::m_localZoneName;
156QString KSystemTimeZonesPrivate::m_zoneinfoDir;
157QString KSystemTimeZonesPrivate::m_zonetab;
158KSystemTimeZoneSource *KSystemTimeZonesPrivate::m_source = 0;
159bool KSystemTimeZonesPrivate::m_ktimezonedError = true;
160KTzfileTimeZoneSource *KSystemTimeZonesPrivate::m_tzfileSource = 0;
161KSystemTimeZones *KSystemTimeZonesPrivate::m_parent = 0;
162KSystemTimeZonesPrivate *KSystemTimeZonesPrivate::m_instance = 0;
163
164KTzfileTimeZoneSource *KSystemTimeZonesPrivate::tzfileSource()
165{
166 if (!m_tzfileSource)
167 {
168 instance();
169 m_tzfileSource = new KTzfileTimeZoneSource(m_zoneinfoDir);
170 }
171 return m_tzfileSource;
172}
173
174
175#ifndef NDEBUG
176K_GLOBAL_STATIC(KTimeZone, simulatedLocalZone)
177#endif
178
179
180KSystemTimeZones::KSystemTimeZones()
181 : d(0)
182{
183 QDBusConnection dbus = QDBusConnection::sessionBus();
184 const QString dbusIface = QString::fromLatin1(KTIMEZONED_DBUS_IFACE);
185 dbus.connect(QString(), QString(), dbusIface, QLatin1String("configChanged"), this, SLOT(configChanged()));
186 dbus.connect(QString(), QString(), dbusIface, QLatin1String("zonetabChanged"), this, SLOT(zonetabChanged(QString)));
187 // No need to connect to definitionChanged() - see comments in zoneDefinitionChanged()
188 //dbus.connect(QString(), QString(), dbusIface, QLatin1String("definitionChanged"), this, SLOT(zoneDefinitionChanged(QString)));
189}
190
191KSystemTimeZones::~KSystemTimeZones()
192{
193}
194
195KTimeZone KSystemTimeZones::local()
196{
197#ifndef NDEBUG
198 if (simulatedLocalZone->isValid())
199 return *simulatedLocalZone;
200#endif
201 KSystemTimeZonesPrivate::instance();
202 return KSystemTimeZonesPrivate::m_localZone;
203}
204
205KTimeZone KSystemTimeZones::realLocalZone()
206{
207 KSystemTimeZonesPrivate::instance();
208 return KSystemTimeZonesPrivate::m_localZone;
209}
210
211void KSystemTimeZones::setLocalZone(const KTimeZone& tz)
212{
213 Q_UNUSED(tz);
214#ifndef NDEBUG
215 *simulatedLocalZone = tz;
216#endif
217}
218
219bool KSystemTimeZones::isSimulated()
220{
221#ifndef NDEBUG
222 return simulatedLocalZone->isValid();
223#else
224 return false;
225#endif
226}
227
228QString KSystemTimeZones::zoneinfoDir()
229{
230 KSystemTimeZonesPrivate::instance();
231 return KSystemTimeZonesPrivate::m_zoneinfoDir;
232}
233
234bool KSystemTimeZones::isTimeZoneDaemonAvailable()
235{
236 KSystemTimeZonesPrivate::instance();
237 return !KSystemTimeZonesPrivate::m_ktimezonedError;
238}
239
240KTimeZones *KSystemTimeZones::timeZones()
241{
242 return KSystemTimeZonesPrivate::instance();
243}
244
245KTimeZone KSystemTimeZones::readZone(const QString &name)
246{
247 return KTzfileTimeZone(KSystemTimeZonesPrivate::tzfileSource(), name);
248}
249
250const KTimeZones::ZoneMap KSystemTimeZones::zones()
251{
252 return KSystemTimeZonesPrivate::instance()->zones();
253}
254
255KTimeZone KSystemTimeZones::zone(const QString& name)
256{
257 return KSystemTimeZonesPrivate::instance()->zone(name);
258}
259
260void KSystemTimeZones::configChanged()
261{
262 kDebug(161) << "KSystemTimeZones::configChanged()";
263 KSystemTimeZonesPrivate::m_ktimezonedError = false;
264 KSystemTimeZonesPrivate::readConfig(false);
265}
266
267void KSystemTimeZones::zonetabChanged(const QString &zonetab)
268{
269 Q_UNUSED(zonetab)
270#ifndef Q_OS_WIN
271 kDebug(161) << "KSystemTimeZones::zonetabChanged()";
272 KSystemTimeZonesPrivate::m_ktimezonedError = false;
273 // Re-read zone.tab and update our collection, removing any deleted
274 // zones and adding any new zones.
275 KSystemTimeZonesPrivate::updateZonetab();
276#endif
277}
278
279void KSystemTimeZones::zoneDefinitionChanged(const QString &zone)
280{
281 // No need to do anything when the definition (as opposed to the
282 // identity) of the local zone changes, since the updated details
283 // will always be accessed by the system library calls to fetch
284 // local zone information.
285 Q_UNUSED(zone)
286 KSystemTimeZonesPrivate::m_ktimezonedError = false;
287}
288
289// Perform initialization, create the unique KSystemTimeZones instance,
290// whose only function is to receive D-Bus signals from KTimeZoned,
291// and create the unique KSystemTimeZonesPrivate instance.
292KSystemTimeZonesPrivate *KSystemTimeZonesPrivate::instance()
293{
294 if (!m_instance)
295 {
296 m_instance = new KSystemTimeZonesPrivate;
297
298 // A KSystemTimeZones instance is required only to catch D-Bus signals.
299 m_parent = new KSystemTimeZones;
300 // Ensure that the KDED time zones module has initialized. The call loads the module on demand.
301 if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(QLatin1String("org.kde.kded")))
302 KToolInvocation::klauncher(); // this calls startKdeinit, and blocks until it returns
303 const QString dbusIface = QString::fromLatin1(KTIMEZONED_DBUS_IFACE);
304 QDBusInterface *ktimezoned = new QDBusInterface(QLatin1String("org.kde.kded"), QLatin1String("/modules/ktimezoned"), dbusIface);
305 QDBusReply<void> reply = ktimezoned->call(QLatin1String("initialize"), false);
306 m_ktimezonedError = !reply.isValid();
307 if (m_ktimezonedError)
308 kError(161) << "KSystemTimeZones: ktimezoned initialize() D-Bus call failed: " << reply.error().message() << endl;
309kDebug(161)<<"instance(): ... initialised";
310 delete ktimezoned;
311
312 // Read the time zone config written by ktimezoned
313 readConfig(true);
314
315 // Go read the database.
316#ifdef Q_OS_WIN
317 // On Windows, HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones
318 // is the place to look. The TZI binary value is the TIME_ZONE_INFORMATION structure.
319 m_instance->updateTimezoneInformation(false);
320#else
321 // For Unix, read zone.tab.
322 if (!m_zonetab.isEmpty())
323 m_instance->readZoneTab(false);
324#endif
325 setLocalZone();
326 if (!m_localZone.isValid())
327 m_localZone = KTimeZone::utc(); // ensure a time zone is always returned
328
329 qAddPostRoutine(KSystemTimeZonesPrivate::cleanup);
330 }
331 return m_instance;
332}
333
334void KSystemTimeZonesPrivate::readConfig(bool init)
335{
336 KConfig config(QLatin1String("ktimezonedrc"));
337 if (!init)
338 config.reparseConfiguration();
339 KConfigGroup group(&config, "TimeZones");
340 if (!group.exists())
341 {
342 kError(161) << "No time zone information obtained from ktimezoned";
343 m_ktimezonedError = true;
344 }
345 m_zoneinfoDir = group.readEntry("ZoneinfoDir");
346 m_zonetab = group.readEntry("Zonetab");
347 m_localZoneName = group.readEntry("LocalZone");
348 if (m_zoneinfoDir.length() > 1 && m_zoneinfoDir.endsWith(QLatin1Char('/')))
349 m_zoneinfoDir.truncate(m_zoneinfoDir.length() - 1); // strip trailing '/'
350 if (!init)
351 setLocalZone();
352 kDebug(161) << "readConfig(): local zone=" << m_localZoneName;
353}
354
355void KSystemTimeZonesPrivate::setLocalZone()
356{
357 QString filename;
358 if (m_localZoneName.startsWith(QLatin1Char('/'))) {
359 // The time zone is specified by a file outside the zoneinfo directory
360 filename = m_localZoneName;
361 } else {
362 // The zone name is either a known zone, or it's a relative file name
363 // in zoneinfo directory which isn't in zone.tab.
364 m_localZone = m_instance->zone(m_localZoneName);
365 if (m_localZone.isValid())
366 return;
367 // It's a relative file name
368 filename = m_zoneinfoDir + QLatin1Char('/') + m_localZoneName;
369 }
370
371 // Parse the specified time zone data file
372 QString zonename = filename;
373 if (zonename.startsWith(m_zoneinfoDir + QLatin1Char('/')))
374 zonename = zonename.mid(m_zoneinfoDir.length() + 1);
375 m_localZone = KTzfileTimeZone(KSystemTimeZonesPrivate::tzfileSource(), zonename);
376 if (m_localZone.isValid() && m_instance)
377 {
378 // Add the new time zone to the list
379 const KTimeZone oldzone = m_instance->zone(zonename);
380 if (!oldzone.isValid() || oldzone.type() != "KTzfileTimeZone")
381 {
382 m_instance->remove(oldzone);
383 m_instance->add(m_localZone);
384 }
385 }
386}
387
388void KSystemTimeZonesPrivate::cleanup()
389{
390 delete m_parent;
391 delete m_instance;
392 delete m_source;
393 delete m_tzfileSource;
394}
395
396#ifdef Q_OS_WIN
397
398void KSystemTimeZonesPrivate::updateTimezoneInformation(bool update)
399{
400 if (!m_source)
401 m_source = new KSystemTimeZoneSourceWindows;
402 QStringList newZones;
403 Q_FOREACH(const QString & tz, KSystemTimeZoneWindows::listTimeZones())
404 {
405 // const std::wstring wstr = tz.toStdWString();
406 // const KTimeZone info = make_time_zone( wstr.c_str() );
407 KSystemTimeZoneWindows stz(m_source, tz);
408 if (update)
409 {
410 // Update the existing collection with the new zone definition
411 newZones += stz.name();
412 KTimeZone oldTz = zone(stz.name());
413 if (oldTz.isValid())
414 oldTz.updateBase(stz); // the zone previously existed, so update its definition
415 else
416 add(stz); // the zone didn't previously exist, so add it
417 }
418 else
419 add(stz);
420 }
421 if (update)
422 {
423 // Remove any zones from the collection which no longer exist
424 const ZoneMap oldZones = zones();
425 for (ZoneMap::const_iterator it = oldZones.begin(); it != oldZones.end(); ++it)
426 {
427 if (newZones.indexOf(it.key()) < 0)
428 remove(it.value());
429 }
430 }
431}
432
433#else
434/*
435 * Find the location of the zoneinfo files and store in mZoneinfoDir.
436 * Parse zone.tab and for each time zone, create a KSystemTimeZone instance.
437 */
438void KSystemTimeZonesPrivate::readZoneTab(bool update)
439{
440 kDebug(161) << "readZoneTab(" << m_zonetab<< ")";
441 QStringList newZones;
442 QFile f;
443 f.setFileName(m_zonetab);
444 if (!f.open(QIODevice::ReadOnly))
445 return;
446 QTextStream str(&f);
447 const QRegExp lineSeparator(QLatin1String("[ \t]"));
448 const QRegExp ordinateSeparator(QLatin1String("[+-]"));
449 if (!m_source)
450 m_source = new KSystemTimeZoneSource;
451 while (!str.atEnd())
452 {
453 const QString line = str.readLine();
454 if (line.isEmpty() || line[0] == QLatin1Char('#'))
455 continue;
456 QStringList tokens = KStringHandler::perlSplit(lineSeparator, line, 4);
457 const int n = tokens.count();
458 if (n < 3)
459 {
460 kError(161) << "readZoneTab(): invalid record: " << line << endl;
461 continue;
462 }
463
464 // Got three tokens. Now check for two ordinates plus first one is "".
465 const int i = tokens[1].indexOf(ordinateSeparator, 1);
466 if (i < 0)
467 {
468 kError(161) << "readZoneTab() " << tokens[2] << ": invalid coordinates: " << tokens[1] << endl;
469 continue;
470 }
471
472 const float latitude = convertCoordinate(tokens[1].left(i));
473 const float longitude = convertCoordinate(tokens[1].mid(i));
474
475 // Add entry to list.
476 if (tokens[0] == QLatin1String("??"))
477 tokens[0] = QString::fromLatin1("");
478 // Solaris sets the empty Comments field to '-', making it not empty.
479 // Clean it up.
480 if (n > 3 && tokens[3] == QLatin1String("-"))
481 tokens[3] = QString::fromLatin1("");
482 // Note: KTzfileTimeZone is used in preference to KSystemTimeZone because of
483 // the large overhead incurred by tzset() - see KSystemTimeZones class
484 // description for details.
485 const KTzfileTimeZone tz(tzfileSource(), tokens[2], tokens[0], latitude, longitude, (n > 3 ? tokens[3] : QString()));
486 if (update)
487 {
488 // Update the existing collection with the new zone definition
489 newZones += tz.name();
490 KTimeZone oldTz = zone(tz.name());
491 if (oldTz.isValid())
492 oldTz.updateBase(tz); // the zone previously existed, so update its definition
493 else
494 add(tz); // the zone didn't previously exist, so add it
495 }
496 else
497 add(tz);
498 }
499 f.close();
500
501 if (update)
502 {
503 // Remove any zones from the collection which no longer exist
504 const ZoneMap oldZones = zones();
505 for (ZoneMap::ConstIterator it = oldZones.constBegin(); it != oldZones.constEnd(); ++it)
506 {
507 if (newZones.indexOf(it.key()) < 0)
508 remove(it.value());
509 }
510 }
511}
512
516float KSystemTimeZonesPrivate::convertCoordinate(const QString &coordinate)
517{
518 int value = coordinate.toInt();
519 int degrees = 0;
520 int minutes = 0;
521 int seconds = 0;
522
523 if (coordinate.length() > 6)
524 {
525 degrees = value / 10000;
526 value -= degrees * 10000;
527 minutes = value / 100;
528 value -= minutes * 100;
529 seconds = value;
530 }
531 else
532 {
533 degrees = value / 100;
534 value -= degrees * 100;
535 minutes = value;
536 }
537 value = degrees * 3600 + minutes * 60 + seconds;
538 return value / 3600.0;
539}
540#endif
541
542
543/******************************************************************************/
544
545
546KSystemTimeZoneBackend::KSystemTimeZoneBackend(KSystemTimeZoneSource *source, const QString &name,
547 const QString &countryCode, float latitude, float longitude, const QString &comment)
548 : KTimeZoneBackend(source, name, countryCode, latitude, longitude, comment)
549{}
550
551KSystemTimeZoneBackend::~KSystemTimeZoneBackend()
552{}
553
554KTimeZoneBackend *KSystemTimeZoneBackend::clone() const
555{
556 return new KSystemTimeZoneBackend(*this);
557}
558
559QByteArray KSystemTimeZoneBackend::type() const
560{
561 return "KSystemTimeZone";
562}
563
564int KSystemTimeZoneBackend::offsetAtZoneTime(const KTimeZone *caller, const QDateTime &zoneDateTime, int *secondOffset) const
565{
566 if (!caller->isValid() || !zoneDateTime.isValid() || zoneDateTime.timeSpec() != Qt::LocalTime)
567 return 0;
568 // Make this time zone the current local time zone
569 const QByteArray originalZone = qgetenv("TZ"); // save the original local time zone
570 QByteArray tz = caller->name().toUtf8();
571 tz.prepend(":");
572 const bool change = (tz != originalZone);
573 if (change)
574 {
575 ::setenv("TZ", tz, 1);
576 ::tzset();
577 }
578
579 // Convert zone time to UTC, and then get the offset to UTC
580 tm tmtime;
581 tmtime.tm_sec = zoneDateTime.time().second();
582 tmtime.tm_min = zoneDateTime.time().minute();
583 tmtime.tm_hour = zoneDateTime.time().hour();
584 tmtime.tm_mday = zoneDateTime.date().day();
585 tmtime.tm_mon = zoneDateTime.date().month() - 1;
586 tmtime.tm_year = zoneDateTime.date().year() - 1900;
587 tmtime.tm_isdst = -1;
588 const time_t t = mktime(&tmtime);
589 int offset1 = (t == (time_t)-1) ? KTimeZone::InvalidOffset : gmtoff(t);
590 if (secondOffset)
591 {
592 int offset2 = offset1;
593 if (t != (time_t)-1)
594 {
595 // Check if there is a backward DST change near to this time, by
596 // checking if the UTC offset is different 1 hour later or earlier.
597 // ASSUMPTION: DST SHIFTS ARE NEVER GREATER THAN 1 HOUR.
598 const int maxShift = 3600;
599 offset2 = gmtoff(t + maxShift);
600 if (offset2 < offset1)
601 {
602 // There is a backward DST shift during the following hour
603 if (offset1 - offset2 < maxShift)
604 offset2 = gmtoff(t + (offset1 - offset2));
605 }
606 else if ((offset2 = gmtoff(t - maxShift)) > offset1)
607 {
608 // There is a backward DST shift during the previous hour
609 if (offset2 - offset1 < maxShift)
610 offset2 = gmtoff(t - (offset2 - offset1));
611 // Put UTC offsets into the correct order
612 const int o = offset1;
613 offset1 = offset2;
614 offset2 = o;
615 }
616 else offset2 = offset1;
617 }
618 *secondOffset = offset2;
619 }
620
621 if (change)
622 {
623 // Restore the original local time zone
624 if (originalZone.isEmpty())
625 ::unsetenv("TZ");
626 else
627 ::setenv("TZ", originalZone, 1);
628 ::tzset();
629 }
630 return offset1;
631}
632
633int KSystemTimeZoneBackend::offsetAtUtc(const KTimeZone *caller, const QDateTime &utcDateTime) const
634{
635 return offset(caller, KTimeZone::toTime_t(utcDateTime));
636}
637
638int KSystemTimeZoneBackend::offset(const KTimeZone *caller, time_t t) const
639{
640 if (!caller->isValid() || t == KTimeZone::InvalidTime_t)
641 return 0;
642
643 // Make this time zone the current local time zone
644 const QByteArray originalZone = qgetenv("TZ"); // save the original local time zone
645 QByteArray tz = caller->name().toUtf8();
646 tz.prepend(":");
647 const bool change = (tz != originalZone);
648 if (change)
649 {
650 ::setenv("TZ", tz, 1);
651 ::tzset();
652 }
653
654 const int secs = gmtoff(t);
655
656 if (change)
657 {
658 // Restore the original local time zone
659 if (originalZone.isEmpty())
660 ::unsetenv("TZ");
661 else
662 ::setenv("TZ", originalZone, 1);
663 ::tzset();
664 }
665 return secs;
666}
667
668bool KSystemTimeZoneBackend::isDstAtUtc(const KTimeZone *caller, const QDateTime &utcDateTime) const
669{
670 return isDst(caller, KTimeZone::toTime_t(utcDateTime));
671}
672
673bool KSystemTimeZoneBackend::isDst(const KTimeZone *caller, time_t t) const
674{
675 Q_UNUSED(caller)
676 if (t != (time_t)-1)
677 {
678#ifdef _POSIX_THREAD_SAFE_FUNCTIONS
679 tm tmtime;
680 if (localtime_r(&t, &tmtime))
681 return tmtime.tm_isdst > 0;
682#else
683 const tm *tmtime = localtime(&t);
684 if (tmtime)
685 return tmtime->tm_isdst > 0;
686#endif
687 }
688 return false;
689}
690
691
692/******************************************************************************/
693
694KSystemTimeZone::KSystemTimeZone(KSystemTimeZoneSource *source, const QString &name,
695 const QString &countryCode, float latitude, float longitude, const QString &comment)
696 : KTimeZone(new KSystemTimeZoneBackend(source, name, countryCode, latitude, longitude, comment))
697{
698}
699
700KSystemTimeZone::~KSystemTimeZone()
701{
702}
703
704
705/******************************************************************************/
706
707class KSystemTimeZoneDataPrivate
708{
709public:
710 QByteArray TZ;
711 QList<QByteArray> abbreviations;
712};
713
714
715// N.B. KSystemTimeZoneSourcePrivate is also used by KSystemTimeZoneData
716class KSystemTimeZoneSourcePrivate
717{
718public:
719 static void setTZ(const QByteArray &zoneName);
720 static void restoreTZ();
721 static QByteArray savedTZ; // temporary value of TZ environment variable saved by setTZ()
722 static QByteArray originalTZ; // saved value of TZ environment variable during multiple parse() calls
723 static bool TZIsSaved; // TZ has been saved in savedTZ
724 static bool multiParse; // true if performing multiple parse() calls
725};
726
727QByteArray KSystemTimeZoneSourcePrivate::savedTZ;
728QByteArray KSystemTimeZoneSourcePrivate::originalTZ;
729bool KSystemTimeZoneSourcePrivate::TZIsSaved = false;
730bool KSystemTimeZoneSourcePrivate::multiParse = false;
731
732
733KSystemTimeZoneSource::KSystemTimeZoneSource()
734 : d(0)
735// : d(new KSystemTimeZoneSourcePrivate)
736{
737}
738
739KSystemTimeZoneSource::~KSystemTimeZoneSource()
740{
741// delete d;
742}
743
744KTimeZoneData* KSystemTimeZoneSource::parse(const KTimeZone &zone) const
745{
746 const QByteArray tz = zone.name().toUtf8();
747 KSystemTimeZoneSourcePrivate::setTZ(tz); // make this time zone the current local time zone
748
749 tzset(); // initialize the tzname array
750 KSystemTimeZoneData* data = new KSystemTimeZoneData;
751 data->d->TZ = tz;
752 data->d->abbreviations.append(tzname[0]);
753 data->d->abbreviations.append(tzname[1]);
754
755 // There is no easy means to access the sequence of daylight savings time
756 // changes, or leap seconds adjustments, so leave that data empty.
757
758 KSystemTimeZoneSourcePrivate::restoreTZ(); // restore the original local time zone if necessary
759 return data;
760}
761
762void KSystemTimeZoneSource::startParseBlock()
763{
764 KSystemTimeZoneSourcePrivate::originalTZ = qgetenv("TZ"); // save the original local time zone
765 KSystemTimeZoneSourcePrivate::multiParse = true;
766}
767
768void KSystemTimeZoneSource::endParseBlock()
769{
770 if (KSystemTimeZoneSourcePrivate::multiParse)
771 {
772 // Restore the original local time zone
773 if (KSystemTimeZoneSourcePrivate::originalTZ.isEmpty())
774 ::unsetenv("TZ");
775 else
776 ::setenv("TZ", KSystemTimeZoneSourcePrivate::originalTZ, 1);
777 ::tzset();
778 KSystemTimeZoneSourcePrivate::multiParse = false;
779 }
780}
781
782// Set the TZ environment variable to the specified time zone,
783// saving its current setting first if necessary.
784void KSystemTimeZoneSourcePrivate::setTZ(const QByteArray &zoneName)
785{
786 QByteArray tz = zoneName;
787 tz.prepend(":");
788 bool setTZ = multiParse;
789 if (!setTZ)
790 {
791 savedTZ = qgetenv("TZ"); // save the original local time zone
792 TZIsSaved = true;
793 setTZ = (tz != savedTZ);
794 }
795 if (setTZ)
796 {
797 ::setenv("TZ", tz, 1);
798 ::tzset();
799 }
800}
801
802// Restore the TZ environment variable if it was saved by setTz()
803void KSystemTimeZoneSourcePrivate::restoreTZ()
804{
805 if (TZIsSaved)
806 {
807 if (savedTZ.isEmpty())
808 ::unsetenv("TZ");
809 else
810 ::setenv("TZ", savedTZ, 1);
811 ::tzset();
812 TZIsSaved = false;
813 }
814}
815
816
817/******************************************************************************/
818
819KSystemTimeZoneData::KSystemTimeZoneData()
820 : d(new KSystemTimeZoneDataPrivate)
821{ }
822
823KSystemTimeZoneData::KSystemTimeZoneData(const KSystemTimeZoneData &rhs)
824 : KTimeZoneData(),
825 d(new KSystemTimeZoneDataPrivate)
826{
827 operator=(rhs);
828}
829
830KSystemTimeZoneData::~KSystemTimeZoneData()
831{
832 delete d;
833}
834
835KSystemTimeZoneData &KSystemTimeZoneData::operator=(const KSystemTimeZoneData &rhs)
836{
837 d->TZ = rhs.d->TZ;
838 d->abbreviations = rhs.d->abbreviations;
839 return *this;
840}
841
842KTimeZoneData *KSystemTimeZoneData::clone() const
843{
844 return new KSystemTimeZoneData(*this);
845}
846
847QList<QByteArray> KSystemTimeZoneData::abbreviations() const
848{
849 return d->abbreviations;
850}
851
852QByteArray KSystemTimeZoneData::abbreviation(const QDateTime &utcDateTime) const
853{
854 QByteArray abbr;
855 if (utcDateTime.timeSpec() != Qt::UTC)
856 return abbr;
857 time_t t = utcDateTime.toTime_t();
858 if (t != KTimeZone::InvalidTime_t)
859 {
860 KSystemTimeZoneSourcePrivate::setTZ(d->TZ); // make this time zone the current local time zone
861
862 /* Use tm.tm_zone if available because it returns the abbreviation
863 * in use at the time specified. Otherwise, use tzname[] which
864 * returns the appropriate current abbreviation instead.
865 */
866#ifdef _POSIX_THREAD_SAFE_FUNCTIONS
867 tm tmtime;
868 if (localtime_r(&t, &tmtime))
869#ifdef HAVE_STRUCT_TM_TM_ZONE
870 abbr = tmtime.tm_zone;
871#else
872 abbr = tzname[(tmtime.tm_isdst > 0) ? 1 : 0];
873#endif
874#else
875 const tm *tmtime = localtime(&t);
876 if (tmtime)
877#ifdef HAVE_STRUCT_TM_TM_ZONE
878 abbr = tmtime->tm_zone;
879#else
880 abbr = tzname[(tmtime->tm_isdst > 0) ? 1 : 0];
881#endif
882#endif
883 KSystemTimeZoneSourcePrivate::restoreTZ(); // restore the original local time zone if necessary
884 }
885 return abbr;
886}
887
888QList<int> KSystemTimeZoneData::utcOffsets() const
889{
890 return QList<int>();
891}
892
KConfigGroup
A class for one specific group in a KConfig object.
Definition: kconfiggroup.h:54
KConfig
The central class of the KDE configuration data system.
Definition: kconfig.h:71
KSystemTimeZoneBackend
Backend class for KSystemTimeZone class.
Definition: ksystemtimezone.h:322
KSystemTimeZoneBackend::isDstAtUtc
virtual bool isDstAtUtc(const KTimeZone *caller, const QDateTime &utcDateTime) const
Implements KSystemTimeZone::isDstAtUtc().
Definition: ksystemtimezone.cpp:668
KSystemTimeZoneBackend::clone
virtual KTimeZoneBackend * clone() const
Creates a copy of this instance.
Definition: ksystemtimezone.cpp:554
KSystemTimeZoneBackend::offsetAtUtc
virtual int offsetAtUtc(const KTimeZone *caller, const QDateTime &utcDateTime) const
Implements KSystemTimeZone::offsetAtUtc().
Definition: ksystemtimezone.cpp:633
KSystemTimeZoneBackend::offsetAtZoneTime
virtual int offsetAtZoneTime(const KTimeZone *caller, const QDateTime &zoneDateTime, int *secondOffset) const
Implements KSystemTimeZone::offsetAtZoneTime().
Definition: ksystemtimezone.cpp:564
KSystemTimeZoneBackend::isDst
virtual bool isDst(const KTimeZone *caller, time_t t) const
Implements KSystemTimeZone::isDst().
Definition: ksystemtimezone.cpp:673
KSystemTimeZoneBackend::offset
virtual int offset(const KTimeZone *caller, time_t t) const
Implements KSystemTimeZone::offset().
Definition: ksystemtimezone.cpp:638
KSystemTimeZoneBackend::type
virtual QByteArray type() const
Returns the class name of the data represented by this instance.
Definition: ksystemtimezone.cpp:559
KSystemTimeZoneBackend::~KSystemTimeZoneBackend
~KSystemTimeZoneBackend()
Definition: ksystemtimezone.cpp:551
KSystemTimeZoneBackend::KSystemTimeZoneBackend
KSystemTimeZoneBackend(KSystemTimeZoneSource *source, const QString &name, const QString &countryCode, float latitude, float longitude, const QString &comment)
Implements KSystemTimeZone::KSystemTimeZone().
Definition: ksystemtimezone.cpp:546
KSystemTimeZoneData
Parsed system time zone data.
Definition: ksystemtimezone.h:493
KSystemTimeZoneData::operator=
KSystemTimeZoneData & operator=(const KSystemTimeZoneData &)
Assignment; no special ownership assumed.
Definition: ksystemtimezone.cpp:835
KSystemTimeZoneData::clone
virtual KTimeZoneData * clone() const
Creates a new copy of this object.
Definition: ksystemtimezone.cpp:842
KSystemTimeZoneData::abbreviations
virtual QList< QByteArray > abbreviations() const
Returns the complete list of time zone abbreviations.
Definition: ksystemtimezone.cpp:847
KSystemTimeZoneData::KSystemTimeZoneData
KSystemTimeZoneData()
Definition: ksystemtimezone.cpp:819
KSystemTimeZoneData::utcOffsets
virtual QList< int > utcOffsets() const
Returns the complete list of UTC offsets for the time zone.
Definition: ksystemtimezone.cpp:888
KSystemTimeZoneData::~KSystemTimeZoneData
virtual ~KSystemTimeZoneData()
Definition: ksystemtimezone.cpp:830
KSystemTimeZoneData::abbreviation
virtual QByteArray abbreviation(const QDateTime &utcDateTime) const
Returns the time zone abbreviation current at a specified time.
Definition: ksystemtimezone.cpp:852
KSystemTimeZoneSourceWindows
A class to read and parse the timezone information from the Windows registry.
Definition: ktimezone_win.h:44
KSystemTimeZoneSource
A class to read and parse system time zone data.
Definition: ksystemtimezone.h:442
KSystemTimeZoneSource::~KSystemTimeZoneSource
virtual ~KSystemTimeZoneSource()
Definition: ksystemtimezone.cpp:739
KSystemTimeZoneSource::startParseBlock
static void startParseBlock()
Use in conjunction with endParseBlock() to improve efficiency when calling parse() for a group of KSy...
Definition: ksystemtimezone.cpp:762
KSystemTimeZoneSource::KSystemTimeZoneSource
KSystemTimeZoneSource()
Constructs a system time zone source.
Definition: ksystemtimezone.cpp:733
KSystemTimeZoneSource::endParseBlock
static void endParseBlock()
Definition: ksystemtimezone.cpp:768
KSystemTimeZoneSource::parse
virtual KTimeZoneData * parse(const KTimeZone &zone) const
Extract detailed information for one time zone, via the system time zone library functions.
Definition: ksystemtimezone.cpp:744
KSystemTimeZoneWindows
The KSystemTimeZoneWindows class represents a time zone defined in the Windows registry.
Definition: ktimezone_win.h:78
KSystemTimeZoneWindows::listTimeZones
static QStringList listTimeZones()
Static helper method that lists all availalbe timezones on the system as per the information in the W...
Definition: ktimezone_win.cpp:687
KSystemTimeZone::KSystemTimeZone
KSystemTimeZone(KSystemTimeZoneSource *source, const QString &name, const QString &countryCode=QString(), float latitude=UNKNOWN, float longitude=UNKNOWN, const QString &comment=QString())
Creates a time zone.
Definition: ksystemtimezone.cpp:694
KSystemTimeZone::~KSystemTimeZone
~KSystemTimeZone()
Definition: ksystemtimezone.cpp:700
KSystemTimeZones
The KSystemTimeZones class represents the system time zone database, consisting of a collection of in...
Definition: ksystemtimezone.h:95
KSystemTimeZones::readZone
static KTimeZone readZone(const QString &name)
Returns the time zone with the given name, containing the full time zone definition read directly fro...
Definition: ksystemtimezone.cpp:245
KSystemTimeZones::local
static KTimeZone local()
Returns the current local system time zone.
Definition: ksystemtimezone.cpp:195
KSystemTimeZones::setLocalZone
static void setLocalZone(const KTimeZone &tz)
Set or clear the simulated local system time zone.
Definition: ksystemtimezone.cpp:211
KSystemTimeZones::zoneinfoDir
static QString zoneinfoDir()
Returns the location of the system time zone zoneinfo database.
Definition: ksystemtimezone.cpp:228
KSystemTimeZones::isSimulated
static bool isSimulated()
Check whether there is a simulated local system time zone.
Definition: ksystemtimezone.cpp:219
KSystemTimeZones::realLocalZone
static KTimeZone realLocalZone()
Return the real (not simulated) local system time zone.
Definition: ksystemtimezone.cpp:205
KSystemTimeZones::zones
static const KTimeZones::ZoneMap zones()
Returns all the time zones defined in this collection.
Definition: ksystemtimezone.cpp:250
KSystemTimeZones::zone
static KTimeZone zone(const QString &name)
Returns the time zone with the given name.
Definition: ksystemtimezone.cpp:255
KSystemTimeZones::isTimeZoneDaemonAvailable
static bool isTimeZoneDaemonAvailable()
Return whether the KDE time zone daemon, ktimezoned, appears to be available and working.
Definition: ksystemtimezone.cpp:234
KSystemTimeZones::timeZones
static KTimeZones * timeZones()
Returns the unique KTimeZones instance containing the system time zones collection.
Definition: ksystemtimezone.cpp:240
KSystemTimeZones::~KSystemTimeZones
~KSystemTimeZones()
Definition: ksystemtimezone.cpp:191
KTimeZoneBackend
Base backend class for KTimeZone classes.
Definition: ktimezone.h:1121
KTimeZoneData
Base class for the parsed data returned by a KTimeZoneSource class.
Definition: ktimezone.h:1303
KTimeZone
Base class representing a time zone.
Definition: ktimezone.h:417
KTimeZone::InvalidTime_t
static const time_t InvalidTime_t
Indicates an invalid time_t value.
Definition: ktimezone.h:1077
KTimeZone::InvalidOffset
static const int InvalidOffset
Indicates an invalid UTC offset.
Definition: ktimezone.h:1073
KTimeZone::name
QString name() const
Returns the name of the time zone.
Definition: ktimezone.cpp:669
KTimeZone::isValid
bool isValid() const
Checks whether the instance is valid.
Definition: ktimezone.cpp:644
KTimeZone::toTime_t
static time_t toTime_t(const QDateTime &utcDateTime)
Converts a UTC QDateTime to a UTC time, measured in seconds since 00:00:00 UTC 1st January 1970 (as r...
Definition: ktimezone.cpp:934
KTimeZone::type
QByteArray type() const
Returns the class name of the data represented by this instance.
Definition: ktimezone.cpp:639
KTimeZone::utc
static KTimeZone utc()
Returns a standard UTC time zone, with name "UTC".
Definition: ktimezone.cpp:911
KTimeZone::updateBase
bool updateBase(const KTimeZone &other)
Update the definition of the time zone to be identical to another KTimeZone instance.
Definition: ktimezone.cpp:773
KTimeZones
The KTimeZones class represents a time zone database which consists of a collection of individual tim...
Definition: ktimezone.h:309
KTimeZones::ZoneMap
QMap< QString, KTimeZone > ZoneMap
Map of KTimeZone instances, indexed by time zone name.
Definition: ktimezone.h:323
KToolInvocation::klauncher
static OrgKdeKLauncherInterface * klauncher()
Returns the D-Bus interface of the service launcher.
KTzfileTimeZoneSource
A class to read and parse tzfile time zone definition files.
Definition: ktzfiletimezone.h:139
KTzfileTimeZone
The KTzfileTimeZone class represents a time zone defined in tzfile(5) format.
Definition: ktzfiletimezone.h:51
QDateTime
QList
Definition: kaboutdata.h:33
QStringList
QString
K_GLOBAL_STATIC
#define K_GLOBAL_STATIC(TYPE, NAME)
This macro makes it easy to use non-POD types as global statics.
Definition: kglobal.h:221
kDebug
#define kDebug
Definition: kdebug.h:316
kError
static QDebug kError(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
Definition: kdebug.h:187
kcodecs.h
kconfiggroup.h
kdebug.h
kglobal.h
klocale.h
kstringhandler.h
KTIMEZONED_DBUS_IFACE
#define KTIMEZONED_DBUS_IFACE
Definition: ksystemtimezone.cpp:64
gmtoff
int gmtoff(time_t t)
Definition: ksystemtimezone.cpp:70
ktemporaryfile.h
ktimezone_win.h
ktoolinvocation.h
readConfig
TsConfig readConfig(const QString &fname)
Definition: ktranscript.cpp:390
ktzfiletimezone.h
TZFILE time zone functions.
KGlobal::config
KSharedConfigPtr config()
Returns the general config object.
Definition: kglobal.cpp:139
KMacroExpander::group
@ group
Definition: kmacroexpander_unix.cpp:34
KStringHandler::perlSplit
QStringList perlSplit(const QString &sep, const QString &s, int max=0)
Split a QString into a QStringList in a similar fashion to the static QStringList function in Qt,...
Definition: kstringhandler.cpp:89
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon Feb 20 2023 00:00:00 by doxygen 1.9.6 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDECore

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

kdelibs-4.14.38 API Reference

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

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