File indexing completed on 2024-04-21 14:55:41

0001 /*
0002    This file is part of the KDE libraries
0003    Copyright (c) 2005-2007,2009-2012 David Jarvie <djarvie@kde.org>
0004 
0005    This library is free software; you can redistribute it and/or
0006    modify it under the terms of the GNU Library General Public
0007    License as published by the Free Software Foundation; either
0008    version 2 of the License, or (at your option) any later version.
0009 
0010    This library is distributed in the hope that it will be useful,
0011    but WITHOUT ANY WARRANTY; without even the implied warranty of
0012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013    Library General Public License for more details.
0014 
0015    You should have received a copy of the GNU Library General Public License
0016    along with this library; see the file COPYING.LIB.  If not, write to
0017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018    Boston, MA 02110-1301, USA.
0019 */
0020 
0021 /** @file
0022  * System time zone functions
0023  * @author David Jarvie <djarvie@kde.org>.
0024  * @author S.R.Haque <srhaque@iee.org>.
0025  */
0026 
0027 #ifndef _KSYSTEMTIMEZONE_H
0028 #define _KSYSTEMTIMEZONE_H
0029 
0030 #include <kdelibs4support_export.h>
0031 #include "ktimezone.h"
0032 
0033 #include <QObject>
0034 #include <QDateTime>
0035 #include <QList>
0036 #include <QString>
0037 #include <QByteArray>
0038 
0039 class KSystemTimeZoneSource;
0040 class KSystemTimeZonePrivate;
0041 class KSystemTimeZonesPrivate;
0042 class KSystemTimeZoneSourcePrivate;
0043 class KSystemTimeZoneDataPrivate;
0044 
0045 /**
0046  * The KSystemTimeZones class represents the system time zone database, consisting
0047  * of a collection of individual system time zone definitions, indexed by name.
0048  * Each individual time zone is defined in a KSystemTimeZone or KTzfileTimeZone
0049  * instance. Additional time zones (of any class derived from KTimeZone) may be
0050  * added if desired.
0051  *
0052  * At initialisation, KSystemTimeZones on UNIX systems reads the zone.tab file
0053  * to obtain the list of system time zones, and creates a KTzfileTimeZone
0054  * instance for each one.
0055  *
0056  * @note KSystemTimeZones gets the system's time zone configuration, including
0057  * the current local system time zone and the location of zone.tab, from the KDE
0058  * time zone daemon, ktimezoned. If ktimezoned cannot be started, KSystemTimeZones
0059  * will only know about the UTC time zone.
0060  *
0061  * Note that KSystemTimeZones is not derived from KTimeZones, but instead contains
0062  * a KTimeZones instance which holds the system time zone database. Convenience
0063  * static methods are defined to access its data, or alternatively you can access
0064  * the KTimeZones instance directly via the timeZones() method.
0065  *
0066  * As an example, find the local time in Oman corresponding to the local system
0067  * time of 12:15:00 on 13th November 1999:
0068  * \code
0069  * QDateTime sampleTime(QDate(1999,11,13), QTime(12,15,0), Qt::LocalTime);
0070  * KTimeZone local = KSystemTimeZones::local();
0071  * KTimeZone oman  = KSystemTimeZones::zone("Asia/Muscat");
0072  * QDateTime omaniTime = local.convert(oman, sampleTime);
0073  * \endcode
0074  *
0075  * @note KTzfileTimeZone is used in preference to KSystemTimeZone on UNIX
0076  * systems since use of the standard system libraries by KSystemTimeZone
0077  * requires the use of tzset() in several methods. That function reads and
0078  * parses the local system time zone definition file every time it is called,
0079  * and this has been observed to make applications hang for many seconds when
0080  * a large number of KSystemTimeZone calls are made in succession.
0081  *
0082  * @note This class provides a facility to simulate the local system time
0083  * zone. This facility is provided for testing purposes only, and is only
0084  * available if the library is compiled with debug enabled. In release mode,
0085  * simulation is inoperative and the real local system time zone is used at all
0086  * times.
0087  *
0088  * @short System time zone access
0089  * @see KTimeZones, KSystemTimeZone, KSystemTimeZoneSource, KTzfileTimeZone
0090  * @ingroup timezones
0091  * @author David Jarvie <djarvie@kde.org>.
0092  * @author S.R.Haque <srhaque@iee.org>.
0093  */
0094 class KDELIBS4SUPPORT_EXPORT KSystemTimeZones : public QObject
0095 {
0096     Q_OBJECT
0097 public:
0098     ~KSystemTimeZones() override;
0099 
0100     /**
0101      * Returns the unique KTimeZones instance containing the system time zones
0102      * collection. It is first created if it does not already exist.
0103      *
0104      * @return time zones.
0105      */
0106     static  KTimeZones *timeZones();
0107 
0108     /**
0109      * Returns all the time zones defined in this collection.
0110      *
0111      * @return time zone collection
0112      */
0113     static const KTimeZones::ZoneMap zones();
0114 
0115     /**
0116      * Returns the time zone with the given name.
0117      *
0118      * The time zone definition is obtained using system library calls, and may
0119      * not contain historical data. If you need historical time change data,
0120      * use the potentially slower method readZone().
0121      *
0122      * @param name name of time zone
0123      * @return time zone (usually a KSystemTimeZone instance), or invalid if not found
0124      * @see readZone()
0125      */
0126     static KTimeZone zone(const QString &name);
0127 
0128     /**
0129      * Returns the time zone with the given name, containing the full time zone
0130      * definition read directly from the system time zone database. This may
0131      * incur a higher overhead than zone(), but will provide whatever historical
0132      * data the system holds.
0133      *
0134      * @param name name of time zone
0135      * @return time zone (usually a KTzfileTimeZone instance), or invalid if not found
0136      * @see zone()
0137      */
0138     static KTimeZone readZone(const QString &name);
0139 
0140     /**
0141      * Returns the current local system time zone.
0142      *
0143      * The idea of this routine is to provide a robust lookup of the local time
0144      * zone. On Unix systems, there are a variety of mechanisms for setting this
0145      * information, and no well defined way of getting it. For example, if you
0146      * set your time zone to "Europe/London", then the tzname[] maintained by
0147      * tzset() typically returns { "GMT", "BST" }. The function of this routine
0148      * is to actually return "Europe/London" (or rather, the corresponding
0149      * KTimeZone).
0150      *
0151      * Note that depending on how the system stores its current time zone, this
0152      * routine may return a synonym of the expected time zone. For example,
0153      * "Europe/London", "Europe/Guernsey" and some other time zones are all
0154      * identical and there may be no way for the routine to distinguish which
0155      * of these is the correct zone name from the user's point of view.
0156      *
0157      * @warning For testing purposes, if the library is compiled with debug
0158      *          enabled, this method returns any simulated local system time
0159      *          zone set by setLocalZone(). If the library is compiled in
0160      *          release mode, it always returns the real local system time zone.
0161      *
0162      * @return local system time zone. If necessary, we will use a series of
0163      *         heuristics which end by returning UTC. We will never return NULL.
0164      *         Note that if UTC is returned as a default, it may not belong to the
0165      *         the collection returned by KSystemTimeZones::zones().
0166      */
0167     static KTimeZone local();
0168 
0169     /**
0170      * Return the real (not simulated) local system time zone.
0171      *
0172      * @warning This method is provided only for testing purposes, and should
0173      *          not be used in released code. If the library is compiled without
0174      *          debug enabled, local() and realLocalZone() both return the real
0175      *          local system time zone.
0176      *          To avoid confusion, it is recommended that calls to
0177      *          realLocalZone() should be conditionally compiled, e.g.:
0178      *          \code
0179      *          #ifndef NDEBUG
0180      *             tz = KSystemTimeZones::realLocalZone();
0181      *          #endif
0182      *          \endcode
0183      *
0184      * @see setLocalZone()
0185      * @since 4.3
0186      */
0187     static KTimeZone realLocalZone();
0188 
0189     /**
0190      * Set or clear the simulated local system time zone.
0191      *
0192      * @warning This method is provided only for testing purposes, and should
0193      *          not be used in released code. If the library is compiled without
0194      *          debug enabled, setLocalZone() has no effect.
0195      *          To avoid confusion, it is recommended that calls to it should be
0196      *          conditionally compiled, e.g.:
0197      *          \code
0198      *          #ifndef NDEBUG
0199      *             KSystemTimeZones::setLocalZone(tz);
0200      *          #endif
0201      *          \endcode
0202      *
0203      * @param tz the time zone to simulate, or an invalid KTimeZone instance
0204      *           (i.e. \code tz.isValid() == false \endcode) to cancel
0205      *           simulation
0206      * @since 4.3
0207      */
0208     static void setLocalZone(const KTimeZone &tz);
0209 
0210     /**
0211      * Check whether there is a simulated local system time zone.
0212      *
0213      * @warning This method is provided only for testing purposes, and should
0214      *          not be used in released code. If the library is compiled without
0215      *          debug enabled, isSimulated() always returns false.
0216      *          To avoid confusion, it is recommended that calls to it should be
0217      *          conditionally compiled, e.g.:
0218      *          \code
0219      *          #ifndef NDEBUG
0220      *             if (KSystemTimeZones::isSimulated())
0221      *             {
0222      *                 ...
0223      *             }
0224      *          #endif
0225      *          \endcode
0226      *
0227      * @see setLocalZone()
0228      * @since 4.3
0229      */
0230     static bool isSimulated();
0231 
0232     /**
0233      * Returns the location of the system time zone zoneinfo database.
0234      *
0235      * @return path of directory containing the zoneinfo database
0236      */
0237     static QString zoneinfoDir();
0238 
0239     /**
0240      * Return whether the KDE time zone daemon, ktimezoned, appears to be
0241      * available and working. If not, UTC will be the only recognized time
0242      * zone.
0243      * @since 4.6
0244      */
0245     static bool isTimeZoneDaemonAvailable();
0246 
0247 private Q_SLOTS:
0248     // Connected to D-Bus signals
0249     void configChanged();
0250     void zonetabChanged(const QString &zonetab);
0251     void zoneDefinitionChanged(const QString &zone);
0252 
0253 private:
0254     KSystemTimeZones();
0255 
0256     KSystemTimeZonesPrivate *const d;
0257     friend class KSystemTimeZonesPrivate;
0258 };
0259 
0260 /**
0261  * The KSystemTimeZone class represents a time zone in the system database.
0262  *
0263  * It works in partnership with the KSystemTimeZoneSource class which reads and parses the
0264  * time zone definition files.
0265  *
0266  * Typically, instances are created and accessed via the KSystemTimeZones class.
0267  *
0268  * @warning The KSystemTimeZone class uses the standard system libraries to
0269  * access time zone data, and its functionality is limited to what these libraries
0270  * provide. On many systems, dates earlier than 1970 are not handled, and on
0271  * non-GNU systems there is no guarantee that the time zone abbreviation returned
0272  * for a given date will be correct if the abbreviations applicable then were
0273  * not those currently in use. Consider using KSystemTimeZones::readZone() or the
0274  * KTzfileTimeZone class instead, which provide accurate information from the time
0275  * zone definition files (but are likely to incur more overhead).
0276  *
0277  * @short System time zone
0278  * @see KSystemTimeZones, KSystemTimeZoneSource, KSystemTimeZoneData, KTzfileTimeZone
0279  * @ingroup timezones
0280  * @author David Jarvie <djarvie@kde.org>.
0281  */
0282 class KDELIBS4SUPPORT_EXPORT KSystemTimeZone : public KTimeZone  //krazy:exclude=dpointer (no d-pointer for KTimeZone derived classes)
0283 {
0284 public:
0285 
0286     /**
0287      * Creates a time zone.
0288      *
0289      * @param source      tzfile reader and parser
0290      * @param name        time zone's unique name
0291      * @param countryCode ISO 3166 2-character country code, empty if unknown
0292      * @param latitude    in degrees (between -90 and +90), UNKNOWN if not known
0293      * @param longitude   in degrees (between -180 and +180), UNKNOWN if not known
0294      * @param comment     description of the time zone, if any
0295      */
0296     KSystemTimeZone(KSystemTimeZoneSource *source, const QString &name,
0297                     const QString &countryCode = QString(), float latitude = UNKNOWN, float longitude = UNKNOWN,
0298                     const QString &comment = QString());
0299 
0300     ~KSystemTimeZone() override;
0301 
0302 private:
0303     // d-pointer is in KSystemTimeZoneBackend.
0304     // This is a requirement for classes inherited from KTimeZone.
0305 };
0306 
0307 /**
0308  * Backend class for KSystemTimeZone class.
0309  *
0310  * This class implements KSystemTimeZone's constructors and virtual methods. A
0311  * backend class is required for all classes inherited from KTimeZone to
0312  * allow KTimeZone virtual methods to work together with reference counting of
0313  * private data.
0314  *
0315  * @short Backend class for KSystemTimeZone class
0316  * @see KTimeZoneBackend, KSystemTimeZone, KTimeZone
0317  * @ingroup timezones
0318  * @author David Jarvie <djarvie@kde.org>.
0319  */
0320 class KDELIBS4SUPPORT_EXPORT KSystemTimeZoneBackend : public KTimeZoneBackend  //krazy:exclude=dpointer (non-const d-pointer for KTimeZoneBackend-derived classes)
0321 {
0322 public:
0323     /** Implements KSystemTimeZone::KSystemTimeZone(). */
0324     KSystemTimeZoneBackend(KSystemTimeZoneSource *source, const QString &name,
0325                            const QString &countryCode, float latitude, float longitude, const QString &comment);
0326 
0327     ~KSystemTimeZoneBackend() override;
0328 
0329     /**
0330      * Creates a copy of this instance.
0331      *
0332      * @return new copy
0333      */
0334     KTimeZoneBackend *clone() const override;
0335 
0336     /**
0337      * Returns the class name of the data represented by this instance.
0338      *
0339      * @return "KSystemTimeZone"
0340      */
0341     QByteArray type() const override;
0342 
0343     /**
0344      * Implements KSystemTimeZone::offsetAtZoneTime().
0345      *
0346      * Returns the offset of this time zone to UTC at the given local date/time.
0347      * Because of daylight savings time shifts, the date/time may occur twice. Optionally,
0348      * the offsets at both occurrences of @p dateTime are calculated.
0349      *
0350      * The offset is the number of seconds which you must add to UTC to get
0351      * local time in this time zone.
0352      *
0353      * @param caller calling KSystemTimeZone object
0354      * @param zoneDateTime the date/time at which the offset is to be calculated. This
0355      *                     is interpreted as a local time in this time zone. An error
0356      *                     occurs if @p zoneDateTime.timeSpec() is not Qt::LocalTime.
0357      * @param secondOffset if non-null, and the @p zoneDateTime occurs twice, receives the
0358      *                     UTC offset for the second occurrence. Otherwise, it is set
0359      *                     the same as the return value.
0360      * @return offset in seconds. If @p zoneDateTime occurs twice, it is the offset at the
0361      *         first occurrence which is returned.
0362      */
0363     int offsetAtZoneTime(const KTimeZone *caller, const QDateTime &zoneDateTime, int *secondOffset) const override;
0364 
0365     /**
0366      * Implements KSystemTimeZone::offsetAtUtc().
0367      *
0368      * Returns the offset of this time zone to UTC at the given UTC date/time.
0369      *
0370      * The offset is the number of seconds which you must add to UTC to get
0371      * local time in this time zone.
0372      *
0373      * Note that system times are represented using time_t. An error occurs if the date
0374      * falls outside the range supported by time_t.
0375      *
0376      * @param caller calling KSystemTimeZone object
0377      * @param utcDateTime the UTC date/time at which the offset is to be calculated.
0378      *                    An error occurs if @p utcDateTime.timeSpec() is not Qt::UTC.
0379      * @return offset in seconds, or 0 if error
0380      */
0381     int offsetAtUtc(const KTimeZone *caller, const QDateTime &utcDateTime) const override;
0382 
0383     /**
0384      * Implements KSystemTimeZone::offset().
0385      *
0386      * Returns the offset of this time zone to UTC at a specified UTC time.
0387      *
0388      * The offset is the number of seconds which you must add to UTC to get
0389      * local time in this time zone.
0390      *
0391      * @param caller calling KSystemTimeZone object
0392      * @param t the UTC time at which the offset is to be calculated, measured in seconds
0393      *          since 00:00:00 UTC 1st January 1970 (as returned by time(2))
0394      * @return offset in seconds, or 0 if error
0395      */
0396     int offset(const KTimeZone *caller, time_t t) const override;
0397 
0398     /**
0399      * Implements KSystemTimeZone::isDstAtUtc().
0400      *
0401      * Returns whether daylight savings time is in operation at the given UTC date/time.
0402      *
0403      * Note that system times are represented using time_t. An error occurs if the date
0404      * falls outside the range supported by time_t.
0405      *
0406      * @param caller calling KSystemTimeZone object
0407      * @param utcDateTime the UTC date/time. An error occurs if
0408      *                    @p utcDateTime.timeSpec() is not Qt::UTC.
0409      * @return @c true if daylight savings time is in operation, @c false otherwise
0410      */
0411     bool isDstAtUtc(const KTimeZone *caller, const QDateTime &utcDateTime) const override;
0412 
0413     /**
0414      * Implements KSystemTimeZone::isDst().
0415      *
0416      * Returns whether daylight savings time is in operation at a specified UTC time.
0417      *
0418      * @param caller calling KSystemTimeZone object
0419      * @param t the UTC time, measured in seconds since 00:00:00 UTC 1st January 1970
0420      *          (as returned by time(2))
0421      * @return @c true if daylight savings time is in operation, @c false otherwise
0422      */
0423     bool isDst(const KTimeZone *caller, time_t t) const override;
0424 
0425 private:
0426     KSystemTimeZonePrivate *d;   // non-const
0427 };
0428 
0429 /**
0430  * A class to read and parse system time zone data.
0431  *
0432  * Access is performed via the system time zone library functions.
0433  *
0434  * @short Reads and parses system time zone data
0435  * @see KSystemTimeZones, KSystemTimeZone, KSystemTimeZoneData
0436  * @ingroup timezones
0437  * @author David Jarvie <djarvie@kde.org>.
0438  */
0439 class KDELIBS4SUPPORT_EXPORT KSystemTimeZoneSource : public KTimeZoneSource
0440 {
0441 public:
0442     /**
0443      * Constructs a system time zone source.
0444      */
0445     KSystemTimeZoneSource();
0446     ~KSystemTimeZoneSource() override;
0447 
0448     /**
0449      * Extract detailed information for one time zone, via the system time zone
0450      * library functions.
0451      *
0452      * @param zone the time zone for which data is to be extracted
0453      * @return a KSystemTimeZoneData instance containing the parsed data.
0454      *         The caller is responsible for deleting the KTimeZoneData instance.
0455      *         Null is returned on error.
0456      */
0457     KTimeZoneData *parse(const KTimeZone &zone) const override;
0458 
0459     /**
0460      * Use in conjunction with endParseBlock() to improve efficiency when calling parse()
0461      * for a group of KSystemTimeZone instances in succession.
0462      * Call startParseBlock() before the first parse(), and call endParseBlock() after the last.
0463      *
0464      * The effect of calling these methods is to save and restore the TZ environment variable
0465      * only once before and after the group of parse() calls, rather than before and
0466      * after every call. So, between calls to startParseBlock() and endParseBlock(), do not
0467      * call any functions which rely directly or indirectly on the local time zone setting.
0468      */
0469     static void startParseBlock();
0470 
0471     /**
0472      * @see startParseBlock()
0473      */
0474     static void endParseBlock();
0475 
0476 private:
0477     KSystemTimeZoneSourcePrivate *const d;
0478 };
0479 
0480 /**
0481  * @internal
0482  * The parsed system time zone data returned by KSystemTimeZoneSource.
0483  *
0484  * @short Parsed system time zone data
0485  * @see KSystemTimeZoneSource, KSystemTimeZone
0486  * @ingroup timezones
0487  * @author David Jarvie <djarvie@kde.org>.
0488  */
0489 class KSystemTimeZoneData : public KTimeZoneData
0490 {
0491     friend class KSystemTimeZoneSource;
0492 
0493 public:
0494     KSystemTimeZoneData();
0495     /** Copy constructor; no special ownership assumed. */
0496     KSystemTimeZoneData(const KSystemTimeZoneData &);
0497     ~KSystemTimeZoneData() override;
0498 
0499     /** Assignment; no special ownership assumed. Everything is value based. */
0500     KSystemTimeZoneData &operator=(const KSystemTimeZoneData &);
0501 
0502     /**
0503      * Creates a new copy of this object.
0504      * The caller is responsible for deleting the copy.
0505      * Derived classes must reimplement this method to return a copy of the
0506      * calling instance
0507      *
0508      * @return copy of this instance. This is a KSystemTimeZoneData pointer.
0509      */
0510     KTimeZoneData *clone() const override;
0511 
0512     /**
0513      * Returns the complete list of time zone abbreviations.
0514      *
0515      * @return the list of abbreviations
0516      */
0517     QList<QByteArray> abbreviations() const override;
0518     QByteArray abbreviation(const QDateTime &utcDateTime) const override;
0519 
0520     /**
0521      * Returns the complete list of UTC offsets for the time zone. For system
0522      * time zones, significant processing would be required to obtain such a
0523      * list, so instead an empty list is returned.
0524      *
0525      * @return empty list
0526      */
0527     QList<int> utcOffsets() const override;
0528 
0529 private:
0530     KSystemTimeZoneDataPrivate *const d;
0531 };
0532 
0533 #endif