WSL/SLF GitLab Repository

Date.h 8.41 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/***********************************************************************************/
/*  Copyright 2009 WSL Institute for Snow and Avalanche Research    SLF-DAVOS      */
/***********************************************************************************/
/* This file is part of MeteoIO.
    MeteoIO is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    MeteoIO is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with MeteoIO.  If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __DATE_H__
#define __DATE_H__

#include <meteoio/IOExceptions.h>

#include <string>
#include <sstream>

26
//#define NEGATIVE_JULIAN
27
28
29
30
31
32
33
34
namespace mio {

/**
 * @class Date
 * @brief  A class to handle timestamps.
 * This class handles conversion between different time display formats (ISO, numeric) as well as different
 * time representation (julian date, modified julian date, etc). It also handles time zones as well as
 * very basic Daylight Saving Time (DST). Since the activation dates of DST are political and not technical,
35
 * it can not be automatically calculated. Therefore, it has to be provided by the caller: when the dst flag
36
37
 * is set, the dst time shift is automatically applied. When the dst flag ceases to be set, the dst time shift
 * is no longer applied. This is very crude, but please keep in mind that using DST for monitoring data is
38
39
 * usually a bad idea... Finally, we assume that dates are positive. If this would not be the case, this
 * class has to be recompiled with the proper define.
40
 *
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
 * Internally, the date is stored as true julian date in GMT.
 * The maximal precision is 1 minute (that can be easily brought to 1 seconds if
 * it would appear necessary/useful, with the limitation that leap seconds are currently not handled).
 *
 * Please see Date::FORMATS for supported display formats and http://en.wikipedia.org/wiki/Julian_day for
 * the various date representation definitions. The following data representation are currently supported:
 * - julian date, see Date::getJulianDate
 * - modified julian date, see Date::getModifiedJulianDate
 * - truncated julian date, see Date::getTruncatedJulianDate
 * - Unix date, see Date::getUnixDate
 * - Excel date, see Date::getExcelDate
 *
 * @ingroup data_str
 * @author Mathias Bavay
 * @date 2010-04-15
 */

class Date {
	public:
		///Keywords for selecting the date formats
		typedef enum {
			ISO, ///< ISO 8601 extended format combined date: YYYY-MM-DDTHH:mm:SS (fields might be dropped, in the least to the most significant order)
63
			ISO_TZ, ///< ISO 8601 format (same as ISO) but with time zone specification
64
65
66
67
68
69
70
71
72
73
74
75
			FULL, ///< ISO 8601 followed by the julian date (in parenthesis)
			NUM, ///< ISO 8601 basic format date: YYYYMMDDHHmmSS (fields might be dropped, in the least to the most significant order)
			DIN ///<DIN5008 format: DD.MM.YYYY HH:MM
		} FORMATS;

		///Keywords for selecting rounding strategy
		typedef enum RND_TYPE {
			UP, ///< rounding toward highest absolute value
			DOWN, ///< rounding toward smallest absolute value
			CLOSEST ///< rounding toward closest
		} RND;

76
77
		static const int daysLeapYear[];
		static const int daysNonLeapYear[];
78
79
80
81
		static const double DST_shift;
		static const float MJD_offset;
		static const float Unix_offset;
		static const float Excel_offset;
82
		static const float Matlab_offset;
83
84
85
86
87
88
89
90

		Date();
		Date(const double& julian_in, const double& in_timezone, const bool& in_dst=false);
		Date(const int& year, const int& month, const int& day, const int& hour, const int& minute, const double& in_timezone, const bool& in_dst=false);
		Date(const time_t&, const bool& in_dst=false);

		void setFromSys();
		void setTimeZone(const double& in_timezone, const bool& in_dst=false);
91
		void setDate(const Date& in_date);
92
		void setDate(const double& julian_in, const double& in_timezone, const bool& in_dst=false);
93
94
		void setDate(const int& year, const int& month, const int& day, const int& hour, const int& minute, const double& in_timezone, const bool& in_dst=false);
		void setDate(const int& year, const unsigned int& month, const unsigned int& day, const unsigned int& hour, const unsigned int& minute, const double& in_timezone, const bool& in_dst=false);
95
96
97
98
99
		void setDate(const time_t& in_time, const bool& in_dst=false);
		void setModifiedJulianDate(const double& julian_in, const double& in_timezone, const bool& in_dst=false);
		void setUnixDate(const time_t& in_time, const bool& in_dst=false);
		void setExcelDate(const double excel_in, const double& in_timezone, const bool& in_dst=false);
		void setMatlabDate(const double excel_in, const double& in_timezone, const bool& in_dst=false);
100
101
102
103
104
		void setUndef(const bool& flag);

		bool isUndef() const;
		double getTimeZone() const;
		bool getDST() const;
105
		double getJulian(const bool& gmt=false) const;
106
107
		double getModifiedJulianDate(const bool& gmt=false) const;
		double getTruncatedJulianDate(const bool& gmt=false) const;
108
		time_t getUnixDate() const;
109
		double getExcelDate(const bool& gmt=false) const;
110
		double getMatlabDate(const bool& gmt=false) const;
111
112
113
114
115

		void getDate(double& julian_out, const bool& gmt=false) const;
		void getDate(int& year, int& month, int& day, const bool& gmt=false) const;
		void getDate(int& year, int& month, int& day, int& hour, const bool& gmt=false) const;
		void getDate(int& year, int& month, int& day, int& hour, int& minute, const bool& gmt=false) const;
116
		void getTime(int& hour_out, int& minute_out, const bool& gmt=false) const;
117
118
		int getYear(const bool& gmt=false) const;

119
		int getJulianDayNumber(const bool& gmt=false) const;
120
121
		bool isLeapYear() const;

122
123
124
		static double rnd(const double& julian, const unsigned int& precision, const RND& type=CLOSEST);
		void rnd(const unsigned int& precision, const RND& type=CLOSEST);
		static const Date rnd(const Date& indate, const unsigned int& precision, const RND& type=CLOSEST);
125
		static double parseTimeZone(const std::string& timezone_iso);
126

127
		static std::string printFractionalDay(const double& fractional);
128
		const std::string toString(FORMATS type, const bool& gmt=false) const;
129
130
131
		const std::string toString() const;
		friend std::iostream& operator<<(std::iostream& os, const Date& date);
		friend std::iostream& operator>>(std::iostream& is, Date& date);
132
133
134
135
136
137
138
139

		//Operator Prototypes
		bool operator==(const Date&) const;
		bool operator!=(const Date&) const;
		bool operator<(const Date&) const;
		bool operator<=(const Date&) const;
		bool operator>(const Date&) const;
		bool operator>=(const Date&) const;
140

141
142
143
		///Intervals arithmetic
		///Can be used to add an interval to an existing Date object.
		///Construct a Date object representing the interval e.g. Date(1.0) for 1 day and add that to another Date object.
144
		///Please use the Duration type instead of Date for such calculations!
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
		Date& operator+=(const Date&);
		Date& operator-=(const Date&);
		Date& operator+=(const double&);
		Date& operator-=(const double&);
		Date& operator*=(const double&);
		Date& operator/=(const double&);

		const Date operator+(const Date&) const;
		const Date operator-(const Date&) const;
		const Date operator+(const double&) const;
		const Date operator-(const double&) const;
		const Date operator*(const double&) const;
		const Date operator/(const double&) const;

	protected:
160
		double localToGMT(const double& in_julian) const;
161
162
		double GMTToLocal(const double& in_gmt_julian) const;
		double calculateJulianDate(const int& in_year, const int& in_month, const int& in_day, const int& in_hour, const int& in_minute) const;
163
		void calculateValues(const double& i_julian, int& out_year, int& out_month, int& out_day, int& out_hour, int& out_minute) const;
164
165
166
167
		long getJulianDayNumber(const int&, const int&, const int&) const;
		bool isLeapYear(const int&) const;
		void plausibilityCheck(const int& in_year, const int& in_month, const int& in_day, const int& in_hour, const int& in_minute) const;

168
		static const double epsilon;
169
170
		double timezone;
		double gmt_julian;
171
		int gmt_year, gmt_month, gmt_day, gmt_hour, gmt_minute;
172
		bool dst;
173
174
175
176
177
178
179
180
		bool undef;
};

typedef Date Duration; //so that later, we can implement a true Interval/Duration class

} //end namespace

#endif