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

KDECore

  • sources
  • kde-4.14
  • kdelibs
  • 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  */
70 int 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 
116 class KSystemTimeZonesPrivate : public KTimeZones
117 {
118 public:
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 
140 private:
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 
154 KTimeZone KSystemTimeZonesPrivate::m_localZone;
155 QString KSystemTimeZonesPrivate::m_localZoneName;
156 QString KSystemTimeZonesPrivate::m_zoneinfoDir;
157 QString KSystemTimeZonesPrivate::m_zonetab;
158 KSystemTimeZoneSource *KSystemTimeZonesPrivate::m_source = 0;
159 bool KSystemTimeZonesPrivate::m_ktimezonedError = true;
160 KTzfileTimeZoneSource *KSystemTimeZonesPrivate::m_tzfileSource = 0;
161 KSystemTimeZones *KSystemTimeZonesPrivate::m_parent = 0;
162 KSystemTimeZonesPrivate *KSystemTimeZonesPrivate::m_instance = 0;
163 
164 KTzfileTimeZoneSource *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
176 K_GLOBAL_STATIC(KTimeZone, simulatedLocalZone)
177 #endif
178 
179 
180 KSystemTimeZones::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 
191 KSystemTimeZones::~KSystemTimeZones()
192 {
193 }
194 
195 KTimeZone 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 
205 KTimeZone KSystemTimeZones::realLocalZone()
206 {
207  KSystemTimeZonesPrivate::instance();
208  return KSystemTimeZonesPrivate::m_localZone;
209 }
210 
211 void KSystemTimeZones::setLocalZone(const KTimeZone& tz)
212 {
213  Q_UNUSED(tz);
214 #ifndef NDEBUG
215  *simulatedLocalZone = tz;
216 #endif
217 }
218 
219 bool KSystemTimeZones::isSimulated()
220 {
221 #ifndef NDEBUG
222  return simulatedLocalZone->isValid();
223 #else
224  return false;
225 #endif
226 }
227 
228 QString KSystemTimeZones::zoneinfoDir()
229 {
230  KSystemTimeZonesPrivate::instance();
231  return KSystemTimeZonesPrivate::m_zoneinfoDir;
232 }
233 
234 bool KSystemTimeZones::isTimeZoneDaemonAvailable()
235 {
236  KSystemTimeZonesPrivate::instance();
237  return !KSystemTimeZonesPrivate::m_ktimezonedError;
238 }
239 
240 KTimeZones *KSystemTimeZones::timeZones()
241 {
242  return KSystemTimeZonesPrivate::instance();
243 }
244 
245 KTimeZone KSystemTimeZones::readZone(const QString &name)
246 {
247  return KTzfileTimeZone(KSystemTimeZonesPrivate::tzfileSource(), name);
248 }
249 
250 const KTimeZones::ZoneMap KSystemTimeZones::zones()
251 {
252  return KSystemTimeZonesPrivate::instance()->zones();
253 }
254 
255 KTimeZone KSystemTimeZones::zone(const QString& name)
256 {
257  return KSystemTimeZonesPrivate::instance()->zone(name);
258 }
259 
260 void KSystemTimeZones::configChanged()
261 {
262  kDebug(161) << "KSystemTimeZones::configChanged()";
263  KSystemTimeZonesPrivate::m_ktimezonedError = false;
264  KSystemTimeZonesPrivate::readConfig(false);
265 }
266 
267 void 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 
279 void 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.
292 KSystemTimeZonesPrivate *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;
309 kDebug(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 
334 void 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 
355 void 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 
388 void 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 
398 void 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  */
438 void 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 
516 float 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 
546 KSystemTimeZoneBackend::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 
551 KSystemTimeZoneBackend::~KSystemTimeZoneBackend()
552 {}
553 
554 KTimeZoneBackend *KSystemTimeZoneBackend::clone() const
555 {
556  return new KSystemTimeZoneBackend(*this);
557 }
558 
559 QByteArray KSystemTimeZoneBackend::type() const
560 {
561  return "KSystemTimeZone";
562 }
563 
564 int 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 
633 int KSystemTimeZoneBackend::offsetAtUtc(const KTimeZone *caller, const QDateTime &utcDateTime) const
634 {
635  return offset(caller, KTimeZone::toTime_t(utcDateTime));
636 }
637 
638 int 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 
668 bool KSystemTimeZoneBackend::isDstAtUtc(const KTimeZone *caller, const QDateTime &utcDateTime) const
669 {
670  return isDst(caller, KTimeZone::toTime_t(utcDateTime));
671 }
672 
673 bool 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 
694 KSystemTimeZone::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 
700 KSystemTimeZone::~KSystemTimeZone()
701 {
702 }
703 
704 
705 /******************************************************************************/
706 
707 class KSystemTimeZoneDataPrivate
708 {
709 public:
710  QByteArray TZ;
711  QList<QByteArray> abbreviations;
712 };
713 
714 
715 // N.B. KSystemTimeZoneSourcePrivate is also used by KSystemTimeZoneData
716 class KSystemTimeZoneSourcePrivate
717 {
718 public:
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 
727 QByteArray KSystemTimeZoneSourcePrivate::savedTZ;
728 QByteArray KSystemTimeZoneSourcePrivate::originalTZ;
729 bool KSystemTimeZoneSourcePrivate::TZIsSaved = false;
730 bool KSystemTimeZoneSourcePrivate::multiParse = false;
731 
732 
733 KSystemTimeZoneSource::KSystemTimeZoneSource()
734  : d(0)
735 // : d(new KSystemTimeZoneSourcePrivate)
736 {
737 }
738 
739 KSystemTimeZoneSource::~KSystemTimeZoneSource()
740 {
741 // delete d;
742 }
743 
744 KTimeZoneData* 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 
762 void KSystemTimeZoneSource::startParseBlock()
763 {
764  KSystemTimeZoneSourcePrivate::originalTZ = qgetenv("TZ"); // save the original local time zone
765  KSystemTimeZoneSourcePrivate::multiParse = true;
766 }
767 
768 void 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.
784 void 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()
803 void 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 
819 KSystemTimeZoneData::KSystemTimeZoneData()
820  : d(new KSystemTimeZoneDataPrivate)
821 { }
822 
823 KSystemTimeZoneData::KSystemTimeZoneData(const KSystemTimeZoneData &rhs)
824  : KTimeZoneData(),
825  d(new KSystemTimeZoneDataPrivate)
826 {
827  operator=(rhs);
828 }
829 
830 KSystemTimeZoneData::~KSystemTimeZoneData()
831 {
832  delete d;
833 }
834 
835 KSystemTimeZoneData &KSystemTimeZoneData::operator=(const KSystemTimeZoneData &rhs)
836 {
837  d->TZ = rhs.d->TZ;
838  d->abbreviations = rhs.d->abbreviations;
839  return *this;
840 }
841 
842 KTimeZoneData *KSystemTimeZoneData::clone() const
843 {
844  return new KSystemTimeZoneData(*this);
845 }
846 
847 QList<QByteArray> KSystemTimeZoneData::abbreviations() const
848 {
849  return d->abbreviations;
850 }
851 
852 QByteArray 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 
888 QList<int> KSystemTimeZoneData::utcOffsets() const
889 {
890  return QList<int>();
891 }
892 
KSystemTimeZones::isSimulated
static bool isSimulated()
Check whether there is a simulated local system time zone.
Definition: ksystemtimezone.cpp:219
QTime::minute
int minute() const
KSystemTimeZones::isTimeZoneDaemonAvailable
static bool isTimeZoneDaemonAvailable()
Return whether the KDE time zone daemon, ktimezoned, appears to be available and working.
Definition: ksystemtimezone.cpp:234
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
KSystemTimeZoneData::~KSystemTimeZoneData
virtual ~KSystemTimeZoneData()
Definition: ksystemtimezone.cpp:830
kdebug.h
KSystemTimeZoneData::abbreviation
virtual QByteArray abbreviation(const QDateTime &utcDateTime) const
Returns the time zone abbreviation current at a specified time.
Definition: ksystemtimezone.cpp:852
QByteArray
KSystemTimeZones::zone
static KTimeZone zone(const QString &name)
Returns the time zone with the given name.
Definition: ksystemtimezone.cpp:255
KMacroExpander::group
Definition: kmacroexpander_unix.cpp:34
QDBusReply
KTimeZoneData
Base class for the parsed data returned by a KTimeZoneSource class.
Definition: ktimezone.h:1302
KTimeZone::isValid
bool isValid() const
Checks whether the instance is valid.
Definition: ktimezone.cpp:644
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
QMap
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
KSystemTimeZoneData::clone
virtual KTimeZoneData * clone() const
Creates a new copy of this object.
Definition: ksystemtimezone.cpp:842
QByteArray::isEmpty
bool isEmpty() const
QFile::setFileName
void setFileName(const QString &name)
KSystemTimeZones::zones
static const KTimeZones::ZoneMap zones()
Returns all the time zones defined in this collection.
Definition: ksystemtimezone.cpp:250
KSystemTimeZones::zoneinfoDir
static QString zoneinfoDir()
Returns the location of the system time zone zoneinfo database.
Definition: ksystemtimezone.cpp:228
QDBusError::message
QString message() const
kError
static QDebug kError(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
Definition: kdebug.h:187
QDateTime::time
QTime time() const
QDBusConnection
QDBusReply::isValid
bool isValid() const
QDBusConnection::sessionBus
QDBusConnection sessionBus()
KSystemTimeZoneWindows
The KSystemTimeZoneWindows class represents a time zone defined in the Windows registry.
Definition: ktimezone_win.h:77
KSystemTimeZones::~KSystemTimeZones
~KSystemTimeZones()
Definition: ksystemtimezone.cpp:191
KSystemTimeZones::setLocalZone
static void setLocalZone(const KTimeZone &tz)
Set or clear the simulated local system time zone.
Definition: ksystemtimezone.cpp:211
QDate::month
int month() const
KTimeZones
The KTimeZones class represents a time zone database which consists of a collection of individual tim...
Definition: ktimezone.h:308
ktoolinvocation.h
klocale.h
QFile
QDBusAbstractInterface::call
QDBusMessage call(const QString &method, const QVariant &arg1, const QVariant &arg2, const QVariant &arg3, const QVariant &arg4, const QVariant &arg5, const QVariant &arg6, const QVariant &arg7, const QVariant &arg8)
QTime::second
int second() const
QTextStream
KGlobal::config
KSharedConfigPtr config()
Returns the general config object.
Definition: kglobal.cpp:139
KSystemTimeZones::timeZones
static KTimeZones * timeZones()
Returns the unique KTimeZones instance containing the system time zones collection.
Definition: ksystemtimezone.cpp:240
KSystemTimeZones::KSystemTimeZonesPrivate
friend class KSystemTimeZonesPrivate
Definition: ksystemtimezone.h:257
QRegExp
QObject::name
const char * name() const
kglobal.h
readConfig
TsConfig readConfig(const QString &fname)
Definition: ktranscript.cpp:390
KSystemTimeZoneData::operator=
KSystemTimeZoneData & operator=(const KSystemTimeZoneData &)
Assignment; no special ownership assumed.
Definition: ksystemtimezone.cpp:835
QList::count
int count(const T &value) const
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
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
KSystemTimeZoneBackend::isDstAtUtc
virtual bool isDstAtUtc(const KTimeZone *caller, const QDateTime &utcDateTime) const
Implements KSystemTimeZone::isDstAtUtc().
Definition: ksystemtimezone.cpp:668
KSystemTimeZoneBackend
Backend class for KSystemTimeZone class.
Definition: ksystemtimezone.h:321
QByteArray::prepend
QByteArray & prepend(char ch)
QString::toInt
int toInt(bool *ok, int base) const
QString::isEmpty
bool isEmpty() const
KSystemTimeZoneBackend::isDst
virtual bool isDst(const KTimeZone *caller, time_t t) const
Implements KSystemTimeZone::isDst().
Definition: ksystemtimezone.cpp:673
KTzfileTimeZone
The KTzfileTimeZone class represents a time zone defined in tzfile(5) format.
Definition: ktzfiletimezone.h:50
QDate::day
int day() const
QString::startsWith
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
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::utcOffsets
virtual QList< int > utcOffsets() const
Returns the complete list of UTC offsets for the time zone.
Definition: ksystemtimezone.cpp:888
KSystemTimeZones::local
static KTimeZone local()
Returns the current local system time zone.
Definition: ksystemtimezone.cpp:195
KTimeZone::InvalidTime_t
static const time_t InvalidTime_t
Indicates an invalid time_t value.
Definition: ktimezone.h:1077
gmtoff
int gmtoff(time_t t)
Definition: ksystemtimezone.cpp:70
KTIMEZONED_DBUS_IFACE
#define KTIMEZONED_DBUS_IFACE
Definition: ksystemtimezone.cpp:64
KSystemTimeZoneSource::endParseBlock
static void endParseBlock()
Definition: ksystemtimezone.cpp:768
QDate::year
int year() const
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
KSystemTimeZoneData::abbreviations
virtual QList< QByteArray > abbreviations() const
Returns the complete list of time zone abbreviations.
Definition: ksystemtimezone.cpp:847
QString
QList< QByteArray >
KTimeZone::InvalidOffset
static const int InvalidOffset
Indicates an invalid UTC offset.
Definition: ktimezone.h:1073
QFile::open
virtual bool open(QFlags< QIODevice::OpenModeFlag > mode)
KSystemTimeZoneSource
A class to read and parse system time zone data.
Definition: ksystemtimezone.h:441
QStringList
QDBusInterface
QTime::hour
int hour() const
KSystemTimeZoneSourceWindows
A class to read and parse the timezone information from the Windows registry.
Definition: ktimezone_win.h:43
KSystemTimeZones::realLocalZone
static KTimeZone realLocalZone()
Return the real (not simulated) local system time zone.
Definition: ksystemtimezone.cpp:205
QLatin1Char
QDateTime::timeSpec
Qt::TimeSpec timeSpec() const
KSystemTimeZoneSource::~KSystemTimeZoneSource
virtual ~KSystemTimeZoneSource()
Definition: ksystemtimezone.cpp:739
QFile::close
virtual void close()
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
KSystemTimeZoneBackend::offsetAtUtc
virtual int offsetAtUtc(const KTimeZone *caller, const QDateTime &utcDateTime) const
Implements KSystemTimeZone::offsetAtUtc().
Definition: ksystemtimezone.cpp:633
KTimeZone
Base class representing a time zone.
Definition: ktimezone.h:416
kstringhandler.h
QDateTime::toTime_t
uint toTime_t() const
KSystemTimeZoneBackend::~KSystemTimeZoneBackend
~KSystemTimeZoneBackend()
Definition: ksystemtimezone.cpp:551
QDateTime::isValid
bool isValid() const
KSystemTimeZoneData::KSystemTimeZoneData
KSystemTimeZoneData()
Definition: ksystemtimezone.cpp:819
KConfigGroup
A class for one specific group in a KConfig object.
Definition: kconfiggroup.h:53
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
KConfig
The central class of the KDE configuration data system.
Definition: kconfig.h:70
ktemporaryfile.h
QString::mid
QString mid(int position, int n) const
QDateTime::date
QDate date() const
QLatin1String
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
KSystemTimeZoneBackend::type
virtual QByteArray type() const
Returns the class name of the data represented by this instance.
Definition: ksystemtimezone.cpp:559
QString::length
int length() const
QString::fromLatin1
QString fromLatin1(const char *str, int size)
kDebug
#define kDebug
Definition: kdebug.h:316
QStringList::indexOf
int indexOf(const QRegExp &rx, int from) const
KTimeZone::name
QString name() const
Returns the name of the time zone.
Definition: ktimezone.cpp:669
kcodecs.h
KSystemTimeZoneBackend::clone
virtual KTimeZoneBackend * clone() const
Creates a copy of this instance.
Definition: ksystemtimezone.cpp:554
ktimezone_win.h
KSystemTimeZoneSource::KSystemTimeZoneSource
KSystemTimeZoneSource()
Constructs a system time zone source.
Definition: ksystemtimezone.cpp:733
KSystemTimeZoneBackend::offsetAtZoneTime
virtual int offsetAtZoneTime(const KTimeZone *caller, const QDateTime &zoneDateTime, int *secondOffset) const
Implements KSystemTimeZone::offsetAtZoneTime().
Definition: ksystemtimezone.cpp:564
QDBusConnection::connect
bool connect(const QString &service, const QString &path, const QString &interface, const QString &name, QObject *receiver, const char *slot)
QDBusReply::error
const QDBusError & error()
KSystemTimeZoneBackend::offset
virtual int offset(const KTimeZone *caller, time_t t) const
Implements KSystemTimeZone::offset().
Definition: ksystemtimezone.cpp:638
KTimeZone::utc
static KTimeZone utc()
Returns a standard UTC time zone, with name "UTC".
Definition: ktimezone.cpp:911
KSystemTimeZoneData
Parsed system time zone data.
Definition: ksystemtimezone.h:492
kconfiggroup.h
KSystemTimeZones
The KSystemTimeZones class represents the system time zone database, consisting of a collection of in...
Definition: ksystemtimezone.h:94
QDateTime
KSystemTimeZone::~KSystemTimeZone
~KSystemTimeZone()
Definition: ksystemtimezone.cpp:700
ktzfiletimezone.h
TZFILE time zone functions.
KTimeZoneBackend
Base backend class for KTimeZone classes.
Definition: ktimezone.h:1120
KTzfileTimeZoneSource
A class to read and parse tzfile time zone definition files.
Definition: ktzfiletimezone.h:138
KToolInvocation::klauncher
static OrgKdeKLauncherInterface * klauncher()
Returns the D-Bus interface of the service launcher.
QString::toUtf8
QByteArray toUtf8() const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:22:11 by doxygen 1.8.7 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 API Reference

Skip menu "kdelibs 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

Search



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