1/*
2 This file is part of the KDE libraries
3 Copyright (c) 2005-2007,2009-2012 David Jarvie <djarvie@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 Boston, MA 02110-1301, USA.
19*/
20
21/** @file
22 * System time zone functions
23 * @author David Jarvie <djarvie@kde.org>.
24 * @author S.R.Haque <srhaque@iee.org>.
25 */
26
27#ifndef _KSYSTEMTIMEZONE_H
28#define _KSYSTEMTIMEZONE_H
29
30#include <kdecore_export.h>
31#include "ktimezone.h"
32
33#include <QtCore/QObject>
34#include <QtCore/QDateTime>
35#include <QtCore/QList>
36#include <QtCore/QString>
37#include <QtCore/QByteArray>
38
39class KSystemTimeZoneSource;
40class KSystemTimeZonePrivate;
41class KSystemTimeZonesPrivate;
42class KSystemTimeZoneSourcePrivate;
43class KSystemTimeZoneDataPrivate;
44
45/**
46 * The KSystemTimeZones class represents the system time zone database, consisting
47 * of a collection of individual system time zone definitions, indexed by name.
48 * Each individual time zone is defined in a KSystemTimeZone or KTzfileTimeZone
49 * instance. Additional time zones (of any class derived from KTimeZone) may be
50 * added if desired.
51 *
52 * At initialisation, KSystemTimeZones on UNIX systems reads the zone.tab file
53 * to obtain the list of system time zones, and creates a KTzfileTimeZone
54 * instance for each one.
55 *
56 * @note KSystemTimeZones gets the system's time zone configuration, including
57 * the current local system time zone and the location of zone.tab, from the KDE
58 * time zone daemon, ktimezoned. If ktimezoned cannot be started, KSystemTimeZones
59 * will only know about the UTC time zone.
60 *
61 * Note that KSystemTimeZones is not derived from KTimeZones, but instead contains
62 * a KTimeZones instance which holds the system time zone database. Convenience
63 * static methods are defined to access its data, or alternatively you can access
64 * the KTimeZones instance directly via the timeZones() method.
65 *
66 * As an example, find the local time in Oman corresponding to the local system
67 * time of 12:15:00 on 13th November 1999:
68 * \code
69 * QDateTime sampleTime(QDate(1999,11,13), QTime(12,15,0), Qt::LocalTime);
70 * KTimeZone local = KSystemTimeZones::local();
71 * KTimeZone oman = KSystemTimeZones::zone("Asia/Muscat");
72 * QDateTime omaniTime = local.convert(oman, sampleTime);
73 * \endcode
74 *
75 * @note KTzfileTimeZone is used in preference to KSystemTimeZone on UNIX
76 * systems since use of the standard system libraries by KSystemTimeZone
77 * requires the use of tzset() in several methods. That function reads and
78 * parses the local system time zone definition file every time it is called,
79 * and this has been observed to make applications hang for many seconds when
80 * a large number of KSystemTimeZone calls are made in succession.
81 *
82 * @note This class provides a facility to simulate the local system time
83 * zone. This facility is provided for testing purposes only, and is only
84 * available if the library is compiled with debug enabled. In release mode,
85 * simulation is inoperative and the real local system time zone is used at all
86 * times.
87 *
88 * @short System time zone access
89 * @see KTimeZones, KSystemTimeZone, KSystemTimeZoneSource, KTzfileTimeZone
90 * @ingroup timezones
91 * @author David Jarvie <djarvie@kde.org>.
92 * @author S.R.Haque <srhaque@iee.org>.
93 */
94class KDECORE_EXPORT KSystemTimeZones : public QObject
95{
96 Q_OBJECT
97public:
98 ~KSystemTimeZones();
99
100 /**
101 * Returns the unique KTimeZones instance containing the system time zones
102 * collection. It is first created if it does not already exist.
103 *
104 * @return time zones.
105 */
106 static KTimeZones *timeZones();
107
108 /**
109 * Returns all the time zones defined in this collection.
110 *
111 * @return time zone collection
112 */
113 static const KTimeZones::ZoneMap zones();
114
115 /**
116 * Returns the time zone with the given name.
117 *
118 * The time zone definition is obtained using system library calls, and may
119 * not contain historical data. If you need historical time change data,
120 * use the potentially slower method readZone().
121 *
122 * @param name name of time zone
123 * @return time zone (usually a KSystemTimeZone instance), or invalid if not found
124 * @see readZone()
125 */
126 static KTimeZone zone(const QString &name);
127
128 /**
129 * Returns the time zone with the given name, containing the full time zone
130 * definition read directly from the system time zone database. This may
131 * incur a higher overhead than zone(), but will provide whatever historical
132 * data the system holds.
133 *
134 * @param name name of time zone
135 * @return time zone (usually a KTzfileTimeZone instance), or invalid if not found
136 * @see zone()
137 */
138 static KTimeZone readZone(const QString &name);
139
140 /**
141 * Returns the current local system time zone.
142 *
143 * The idea of this routine is to provide a robust lookup of the local time
144 * zone. On Unix systems, there are a variety of mechanisms for setting this
145 * information, and no well defined way of getting it. For example, if you
146 * set your time zone to "Europe/London", then the tzname[] maintained by
147 * tzset() typically returns { "GMT", "BST" }. The function of this routine
148 * is to actually return "Europe/London" (or rather, the corresponding
149 * KTimeZone).
150 *
151 * Note that depending on how the system stores its current time zone, this
152 * routine may return a synonym of the expected time zone. For example,
153 * "Europe/London", "Europe/Guernsey" and some other time zones are all
154 * identical and there may be no way for the routine to distinguish which
155 * of these is the correct zone name from the user's point of view.
156 *
157 * @warning For testing purposes, if the library is compiled with debug
158 * enabled, this method returns any simulated local system time
159 * zone set by setLocalZone(). If the library is compiled in
160 * release mode, it always returns the real local system time zone.
161 *
162 * @return local system time zone. If necessary, we will use a series of
163 * heuristics which end by returning UTC. We will never return NULL.
164 * Note that if UTC is returned as a default, it may not belong to the
165 * the collection returned by KSystemTimeZones::zones().
166 */
167 static KTimeZone local();
168
169 /**
170 * Return the real (not simulated) local system time zone.
171 *
172 * @warning This method is provided only for testing purposes, and should
173 * not be used in released code. If the library is compiled without
174 * debug enabled, local() and realLocalZone() both return the real
175 * local system time zone.
176 * To avoid confusion, it is recommended that calls to
177 * realLocalZone() should be conditionally compiled, e.g.:
178 * \code
179 * #ifndef NDEBUG
180 * tz = KSystemTimeZones::realLocalZone();
181 * #endif
182 * \endcode
183 *
184 * @see setLocalZone()
185 * @since 4.3
186 */
187 static KTimeZone realLocalZone();
188
189 /**
190 * Set or clear the simulated local system time zone.
191 *
192 * @warning This method is provided only for testing purposes, and should
193 * not be used in released code. If the library is compiled without
194 * debug enabled, setLocalZone() has no effect.
195 * To avoid confusion, it is recommended that calls to it should be
196 * conditionally compiled, e.g.:
197 * \code
198 * #ifndef NDEBUG
199 * KSystemTimeZones::setLocalZone(tz);
200 * #endif
201 * \endcode
202 *
203 * @param tz the time zone to simulate, or an invalid KTimeZone instance
204 * (i.e. \code tz.isValid() == false \endcode) to cancel
205 * simulation
206 * @since 4.3
207 */
208 static void setLocalZone(const KTimeZone& tz);
209
210 /**
211 * Check whether there is a simulated local system time zone.
212 *
213 * @warning This method is provided only for testing purposes, and should
214 * not be used in released code. If the library is compiled without
215 * debug enabled, isSimulated() always returns false.
216 * To avoid confusion, it is recommended that calls to it should be
217 * conditionally compiled, e.g.:
218 * \code
219 * #ifndef NDEBUG
220 * if (KSystemTimeZones::isSimulated())
221 * {
222 * ...
223 * }
224 * #endif
225 * \endcode
226 *
227 * @see setLocalZone()
228 * @since 4.3
229 */
230 static bool isSimulated();
231
232 /**
233 * Returns the location of the system time zone zoneinfo database.
234 *
235 * @return path of directory containing the zoneinfo database
236 */
237 static QString zoneinfoDir();
238
239 /**
240 * Return whether the KDE time zone daemon, ktimezoned, appears to be
241 * available and working. If not, UTC will be the only recognized time
242 * zone.
243 * @since 4.6
244 */
245 static bool isTimeZoneDaemonAvailable();
246
247private Q_SLOTS:
248 // Connected to D-Bus signals
249 void configChanged();
250 void zonetabChanged(const QString &zonetab);
251 void zoneDefinitionChanged(const QString &zone);
252
253private:
254 KSystemTimeZones();
255
256 KSystemTimeZonesPrivate * const d;
257 friend class KSystemTimeZonesPrivate;
258};
259
260/**
261 * The KSystemTimeZone class represents a time zone in the system database.
262 *
263 * It works in partnership with the KSystemTimeZoneSource class which reads and parses the
264 * time zone definition files.
265 *
266 * Typically, instances are created and accessed via the KSystemTimeZones class.
267 *
268 * @warning The KSystemTimeZone class uses the standard system libraries to
269 * access time zone data, and its functionality is limited to what these libraries
270 * provide. On many systems, dates earlier than 1970 are not handled, and on
271 * non-GNU systems there is no guarantee that the time zone abbreviation returned
272 * for a given date will be correct if the abbreviations applicable then were
273 * not those currently in use. Consider using KSystemTimeZones::readZone() or the
274 * KTzfileTimeZone class instead, which provide accurate information from the time
275 * zone definition files (but are likely to incur more overhead).
276 *
277 * @short System time zone
278 * @see KSystemTimeZones, KSystemTimeZoneSource, KSystemTimeZoneData, KTzfileTimeZone
279 * @ingroup timezones
280 * @author David Jarvie <djarvie@kde.org>.
281 */
282class KDECORE_EXPORT KSystemTimeZone : public KTimeZone //krazy:exclude=dpointer (no d-pointer for KTimeZone derived classes)
283{
284public:
285
286 /**
287 * Creates a time zone.
288 *
289 * @param source tzfile reader and parser
290 * @param name time zone's unique name
291 * @param countryCode ISO 3166 2-character country code, empty if unknown
292 * @param latitude in degrees (between -90 and +90), UNKNOWN if not known
293 * @param longitude in degrees (between -180 and +180), UNKNOWN if not known
294 * @param comment description of the time zone, if any
295 */
296 KSystemTimeZone(KSystemTimeZoneSource *source, const QString &name,
297 const QString &countryCode = QString(), float latitude = UNKNOWN, float longitude = UNKNOWN,
298 const QString &comment = QString());
299
300 ~KSystemTimeZone();
301
302private:
303 // d-pointer is in KSystemTimeZoneBackend.
304 // This is a requirement for classes inherited from KTimeZone.
305};
306
307
308/**
309 * Backend class for KSystemTimeZone class.
310 *
311 * This class implements KSystemTimeZone's constructors and virtual methods. A
312 * backend class is required for all classes inherited from KTimeZone to
313 * allow KTimeZone virtual methods to work together with reference counting of
314 * private data.
315 *
316 * @short Backend class for KSystemTimeZone class
317 * @see KTimeZoneBackend, KSystemTimeZone, KTimeZone
318 * @ingroup timezones
319 * @author David Jarvie <djarvie@kde.org>.
320 */
321class KDECORE_EXPORT KSystemTimeZoneBackend : public KTimeZoneBackend //krazy:exclude=dpointer (non-const d-pointer for KTimeZoneBackend-derived classes)
322{
323public:
324 /** Implements KSystemTimeZone::KSystemTimeZone(). */
325 KSystemTimeZoneBackend(KSystemTimeZoneSource *source, const QString &name,
326 const QString &countryCode, float latitude, float longitude, const QString &comment);
327
328 ~KSystemTimeZoneBackend();
329
330 /**
331 * Creates a copy of this instance.
332 *
333 * @return new copy
334 */
335 virtual KTimeZoneBackend *clone() const;
336
337 /**
338 * Returns the class name of the data represented by this instance.
339 *
340 * @return "KSystemTimeZone"
341 */
342 virtual QByteArray type() const;
343
344 /**
345 * Implements KSystemTimeZone::offsetAtZoneTime().
346 *
347 * Returns the offset of this time zone to UTC at the given local date/time.
348 * Because of daylight savings time shifts, the date/time may occur twice. Optionally,
349 * the offsets at both occurrences of @p dateTime are calculated.
350 *
351 * The offset is the number of seconds which you must add to UTC to get
352 * local time in this time zone.
353 *
354 * @param caller calling KSystemTimeZone object
355 * @param zoneDateTime the date/time at which the offset is to be calculated. This
356 * is interpreted as a local time in this time zone. An error
357 * occurs if @p zoneDateTime.timeSpec() is not Qt::LocalTime.
358 * @param secondOffset if non-null, and the @p zoneDateTime occurs twice, receives the
359 * UTC offset for the second occurrence. Otherwise, it is set
360 * the same as the return value.
361 * @return offset in seconds. If @p zoneDateTime occurs twice, it is the offset at the
362 * first occurrence which is returned.
363 */
364 virtual int offsetAtZoneTime(const KTimeZone *caller, const QDateTime &zoneDateTime, int *secondOffset) const;
365
366 /**
367 * Implements KSystemTimeZone::offsetAtUtc().
368 *
369 * Returns the offset of this time zone to UTC at the given UTC date/time.
370 *
371 * The offset is the number of seconds which you must add to UTC to get
372 * local time in this time zone.
373 *
374 * Note that system times are represented using time_t. An error occurs if the date
375 * falls outside the range supported by time_t.
376 *
377 * @param caller calling KSystemTimeZone object
378 * @param utcDateTime the UTC date/time at which the offset is to be calculated.
379 * An error occurs if @p utcDateTime.timeSpec() is not Qt::UTC.
380 * @return offset in seconds, or 0 if error
381 */
382 virtual int offsetAtUtc(const KTimeZone *caller, const QDateTime &utcDateTime) const;
383
384 /**
385 * Implements KSystemTimeZone::offset().
386 *
387 * Returns the offset of this time zone to UTC at a specified UTC time.
388 *
389 * The offset is the number of seconds which you must add to UTC to get
390 * local time in this time zone.
391 *
392 * @param caller calling KSystemTimeZone object
393 * @param t the UTC time at which the offset is to be calculated, measured in seconds
394 * since 00:00:00 UTC 1st January 1970 (as returned by time(2))
395 * @return offset in seconds, or 0 if error
396 */
397 virtual int offset(const KTimeZone *caller, time_t t) const;
398
399 /**
400 * Implements KSystemTimeZone::isDstAtUtc().
401 *
402 * Returns whether daylight savings time is in operation at the given UTC date/time.
403 *
404 * Note that system times are represented using time_t. An error occurs if the date
405 * falls outside the range supported by time_t.
406 *
407 * @param caller calling KSystemTimeZone object
408 * @param utcDateTime the UTC date/time. An error occurs if
409 * @p utcDateTime.timeSpec() is not Qt::UTC.
410 * @return @c true if daylight savings time is in operation, @c false otherwise
411 */
412 virtual bool isDstAtUtc(const KTimeZone *caller, const QDateTime &utcDateTime) const;
413
414 /**
415 * Implements KSystemTimeZone::isDst().
416 *
417 * Returns whether daylight savings time is in operation at a specified UTC time.
418 *
419 * @param caller calling KSystemTimeZone object
420 * @param t the UTC time, measured in seconds since 00:00:00 UTC 1st January 1970
421 * (as returned by time(2))
422 * @return @c true if daylight savings time is in operation, @c false otherwise
423 */
424 virtual bool isDst(const KTimeZone *caller, time_t t) const;
425
426private:
427 KSystemTimeZonePrivate *d; // non-const
428};
429
430
431/**
432 * A class to read and parse system time zone data.
433 *
434 * Access is performed via the system time zone library functions.
435 *
436 * @short Reads and parses system time zone data
437 * @see KSystemTimeZones, KSystemTimeZone, KSystemTimeZoneData
438 * @ingroup timezones
439 * @author David Jarvie <djarvie@kde.org>.
440 */
441class KDECORE_EXPORT KSystemTimeZoneSource : public KTimeZoneSource
442{
443public:
444 /**
445 * Constructs a system time zone source.
446 */
447 KSystemTimeZoneSource();
448 virtual ~KSystemTimeZoneSource();
449
450 /**
451 * Extract detailed information for one time zone, via the system time zone
452 * library functions.
453 *
454 * @param zone the time zone for which data is to be extracted
455 * @return a KSystemTimeZoneData instance containing the parsed data.
456 * The caller is responsible for deleting the KTimeZoneData instance.
457 * Null is returned on error.
458 */
459 virtual KTimeZoneData *parse(const KTimeZone &zone) const;
460
461 /**
462 * Use in conjunction with endParseBlock() to improve efficiency when calling parse()
463 * for a group of KSystemTimeZone instances in succession.
464 * Call startParseBlock() before the first parse(), and call endParseBlock() after the last.
465 *
466 * The effect of calling these methods is to save and restore the TZ environment variable
467 * only once before and after the group of parse() calls, rather than before and
468 * after every call. So, between calls to startParseBlock() and endParseBlock(), do not
469 * call any functions which rely directly or indirectly on the local time zone setting.
470 */
471 static void startParseBlock();
472
473 /**
474 * @see startParseBlock()
475 */
476 static void endParseBlock();
477
478private:
479 KSystemTimeZoneSourcePrivate * const d;
480};
481
482
483/**
484 * @internal
485 * The parsed system time zone data returned by KSystemTimeZoneSource.
486 *
487 * @short Parsed system time zone data
488 * @see KSystemTimeZoneSource, KSystemTimeZone
489 * @ingroup timezones
490 * @author David Jarvie <djarvie@kde.org>.
491 */
492class KSystemTimeZoneData : public KTimeZoneData
493{
494 friend class KSystemTimeZoneSource;
495
496public:
497 KSystemTimeZoneData();
498 /** Copy constructor; no special ownership assumed. */
499 KSystemTimeZoneData(const KSystemTimeZoneData &);
500 virtual ~KSystemTimeZoneData();
501
502 /** Assignment; no special ownership assumed. Everything is value based. */
503 KSystemTimeZoneData &operator=(const KSystemTimeZoneData &);
504
505 /**
506 * Creates a new copy of this object.
507 * The caller is responsible for deleting the copy.
508 * Derived classes must reimplement this method to return a copy of the
509 * calling instance
510 *
511 * @return copy of this instance. This is a KSystemTimeZoneData pointer.
512 */
513 virtual KTimeZoneData *clone() const;
514
515 /**
516 * Returns the complete list of time zone abbreviations.
517 *
518 * @return the list of abbreviations
519 */
520 virtual QList<QByteArray> abbreviations() const;
521 virtual QByteArray abbreviation(const QDateTime &utcDateTime) const;
522
523 /**
524 * Returns the complete list of UTC offsets for the time zone. For system
525 * time zones, significant processing would be required to obtain such a
526 * list, so instead an empty list is returned.
527 *
528 * @return empty list
529 */
530 virtual QList<int> utcOffsets() const;
531
532private:
533 KSystemTimeZoneDataPrivate * const d;
534};
535
536#endif
537