File indexing completed on 2024-04-21 14:46:48

0001 /*
0002     SPDX-FileCopyrightText: 2002 Jason Harris <kstars@30doradus.org>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #pragma once
0008 
0009 #include "kstarsdatetime.h"
0010 
0011 #include <QTime>
0012 
0013 class QString;
0014 
0015 /** @class TimeZoneRule
0016     *This class provides the information needed to determine whether Daylight
0017     *Savings Time (DST; a.k.a. "Summer Time") is currently active at a given
0018     *location.  There are (at least) 25 different "rules" which govern DST
0019     *around the world; a string identifying the appropriate rule is attached
0020     *to each city in citydb.sqlite.
0021     *
0022     *The rules themselves are stored in the TZrulebook.dat file, which is read
0023     *on startup; each line in the file creates a TimeZoneRule object.
0024     *
0025     *TimeZoneRule consists of QStrings identifying the months and days on which
0026     *DST starts and ends, QTime objects identifying the time at which the
0027     *changes occur, and a double indicating the size of the offset in hours
0028     *(probably always 1.00).
0029     *
0030     *Month names should be the English three-letter abbreviation, uncapitalized.
0031     *Day names are either an integer indicating the calendar date (i.e., "15" is
0032     *the fifteenth of the month), or a number paired with a three-letter
0033     *abbreviation for a weekday.  This indicates the Nth weekday of the month
0034     *(i.e., "2sun" is the second Sunday of the Month).  Finally, the weekday
0035     *string on its own indicates the last weekday of the month (i.e.,
0036     *"mon" is the last Monday of the month).
0037     *
0038     *The isDSTActive(KStarsDateTime) function returns true if DST is active for the
0039     *DateTime given as an argument.
0040     *
0041     *The nextDSTChange(KStarsDateTime) function returns the KStarsDateTime of the moment
0042     *at which the next DST change will occur for the current location.
0043     *@author Jason Harris
0044     *@version 1.0
0045     */
0046 
0047 class TimeZoneRule
0048 {
0049   public:
0050     /** Default Constructor. Makes the "empty" time zone rule (i.e., no DST correction)*/
0051     TimeZoneRule();
0052 
0053     /** Constructor. Create a TZ rule according to the arguments.
0054             *@param smonth the three-letter code for the month in which DST starts
0055             *@param sday a string encoding the day on which DST starts (see the class description)
0056             *@param stime the time at which DST starts
0057             *@param rmonth the three-letter code for the month in which DST reverts
0058             *@param rday a string encoding the day on which DST reverts (see the class description)
0059             *@param rtime the time at which DST reverts
0060             *@param offset the offset between normal time and DS time (always 1.00?)
0061             */
0062     TimeZoneRule(const QString &smonth, const QString &sday, const QTime &stime, const QString &rmonth,
0063                  const QString &rday, const QTime &rtime, const double &offset = 1.00);
0064 
0065     /** Determine whether DST is in effect for the given DateTime, according to this rule
0066             *@param date the date/time to test for DST
0067             */
0068     bool isDSTActive(const KStarsDateTime &date);
0069 
0070     /** @return true if the rule is the "empty" TZ rule. */
0071     bool isEmptyRule() const { return (HourOffset == 0.0); }
0072 
0073     /** Toggle DST on/off.  The @p activate argument should probably be isDSTActive()
0074             *@param activate if true, then set DST active; otherwise, deactivate DST
0075             */
0076     void setDST(bool activate = true);
0077 
0078     /** @return the current Timezone offset, compared to the timezone's Standard Time.
0079             *This is typically 0.0 if DST is inactive, and 1.0 if DST is active. */
0080     double deltaTZ() const { return dTZ; }
0081 
0082     /** Recalculate next dst change and if DST is active by a given local time with
0083             *timezone offset and time direction.
0084             *@param ltime the time to be tested
0085             *@param time_runs_forward time direction
0086             *@param TZoffset offset of timezone in some fictional unit
0087             *@param automaticDSTchange is automatic DST change?
0088             *
0089             * @todo Check dox for TZoffset
0090             */
0091     void reset_with_ltime(KStarsDateTime &ltime, const double TZoffset, const bool time_runs_forward,
0092                           const bool automaticDSTchange = false);
0093 
0094     /** @return computed value for next DST change in universal time. */
0095     KStarsDateTime nextDSTChange() const { return next_change_utc; }
0096 
0097     /** @return computed value for next DST change in local time. */
0098     KStarsDateTime nextDSTChange_LTime() const { return next_change_ltime; }
0099 
0100     /** @return true if this rule is the same as the argument.
0101          * @param r the rule to check for equivalence
0102          */
0103     bool equals(TimeZoneRule *r);
0104 
0105   private:
0106     /** @return the KStarsDateTime of the moment when the next DST change will occur in local time
0107             *This is useful because DST change times are saved in local times*/
0108     void nextDSTChange_LTime(const KStarsDateTime &date);
0109 
0110     /** @return the KStarsDateTime of the moment when the last DST change occurred in local time
0111             *This is useful because DST change times are saved in local times
0112             *We need this in case time is running backwards. */
0113     void previousDSTChange_LTime(const KStarsDateTime &date);
0114 
0115     /** calculate the next DST change in universal time for current location */
0116     void nextDSTChange(const KStarsDateTime &local_date, const double TZoffset);
0117 
0118     /** calculate the previous DST change in universal time for current location */
0119     void previousDSTChange(const KStarsDateTime &local_date, const double TZoffset);
0120 
0121     /** Interpret the string as a month of the year;
0122             *@return the month integer (1=jan ... 12=dec)
0123             */
0124     int initMonth(const QString &m);
0125 
0126     /** Set up empty time zone rule */
0127     void setEmpty();
0128 
0129     /** Interpret the day string as a week ID and a day-of-week ID.  The day-of-week
0130             *is an integer between 1 (sunday) and 7 (saturday); the week integer can
0131             *be 1-3 (1st/2nd/third weekday of the month), or 5 (last weekday of the month)
0132             *@param day the day integer is returned by reference through this value
0133             *@param week the week integer is returned by reference through this value
0134             *@return true if the day string was successfully parsed
0135             */
0136     bool initDay(const QString &d, int &day, int &week);
0137 
0138     /** Find the calendar date on which DST starts for the calendar year
0139             *of the given KStarsDateTime.
0140             *@param d the date containing the year to be tested
0141             *@return the calendar date, an integer between 1 and 31. */
0142     int findStartDay(const KStarsDateTime &d);
0143 
0144     /** Find the calendar date on which DST ends for the calendar year
0145             *of the given KStarsDateTime.
0146             *@param d the date containing the year to be tested
0147             *@return the calendar date, an integer between 1 and 31. */
0148     int findRevertDay(const KStarsDateTime &d);
0149 
0150     int StartDay { 0 };
0151     int RevertDay { 0 };
0152     int StartMonth { 0 };
0153     int RevertMonth { 0 };
0154     int StartWeek { 0 };
0155     int RevertWeek { 0 };
0156     QTime StartTime, RevertTime;
0157     KStarsDateTime next_change_utc;
0158     KStarsDateTime next_change_ltime;
0159     double dTZ { 0 };
0160     double HourOffset { 0 };
0161 };