Remove dynamic exceptions
[anna.git] / include / anna / time / Date.hpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite                           //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
7
8
9 #ifndef anna_time_Date_hpp
10 #define anna_time_Date_hpp
11
12 #include <anna/core/RuntimeException.hpp>
13 #include <anna/core/mt/Mutex.hpp>
14
15 // Standard
16 #include <time.h>
17
18 // Local
19 #include <anna/time/internal/Timezone.hpp>
20
21
22 namespace anna {
23 namespace xml {
24 class Node;
25 }
26 }
27
28 //------------------------------------------------------------------------------
29 //---------------------------------------------------------------------- #define
30 //------------------------------------------------------------------------------
31
32 // Unix time reference:  01/01/1970 00:00:00 UTC
33 // NTP time reference:   01/01/1900 00:00:00 UTC
34 // -> 70 years have 2207520000 seconds.
35 // -> Between 1900 and 1970 there are 17 leap years: 1468800 seconds more (17 days)
36 // TOTAL DIFFERENCE = 2207520000 + 1468800 = 2208988800
37 #define TIMESTAMP_OFFSET_NTP1900_OVER_UNIX1970   2208988800U
38 //#define _2K38_EFFECT_LIMIT                       "20380119031407" // UTC
39
40
41 namespace anna {
42
43 namespace time {
44
45
46 /**
47 * Absolute time representation structs class manager.
48 * Allow any time assignment/extraction regarding any timezone.
49 * Uses shell TZ assignment or rely on system timezone configuration (in ubuntu, /etc/timezone
50 * stores the abbreviation and /etc/localtime keeps the timezone file from /usr/share/zoneinfo).
51 *
52 * The internal unix timestamp reamain constant and thedate representation depends on the
53 * configured timezone. Some store methods could specify a certain origin timezone, but the
54 * instance inner timezone won't be changed until the user want to do that.
55 *
56 * <pre>
57 *
58 *  Sample code:
59 *
60 *  anna::time::functions::initialize();
61 *  std::cout << "SystemTimezone: " << anna::time::functions::getSystemTimezone().asString() << std::endl;
62 *
63 *  anna::time::Date myBirth ("CET");
64 *  myBirth.store("19741219111500", "EET");
65 *  std::cout << "myBirth: " << myBirth.asString() << std::endl;
66 *
67 *  anna::time::Date same_moment_canary_island("GMT");
68 *  same_moment_canary_island.store(myBirth.getUnixTimestamp());
69 *  std::cout << "same_moment_canary_island: " << same_moment_canary_island.asString() << std::endl;
70 *  myBirth.setTz("GMT");
71 *  std::cout << "myBirth on GMT: " << myBirth.asString() << std::endl;
72 *  std::cout << "EQUAL: same_moment_canary_island = " << same_moment_canary_island.yyyymmddHHmmss() << "; myBirth in context GMT = " << myBirth.yyyymmddHHmmss() << std::endl;
73 *  same_moment_canary_island.setTz("CET");
74 *  std::cout << "same_moment_canary_island on CET: " << same_moment_canary_island.asString() << std::endl;
75 *  anna::time::Date birthday("EET");
76 *  birthday.store(same_moment_canary_island.getTm(), "CET");
77 *  std::cout << "EQUAL: birthday TS = " << birthday.getUnixTimestamp() << "; myBirth TS = " << myBirth.getUnixTimestamp() << std::endl;
78 *  std::cout << "birthday EET = " << birthday.asString() << std::endl;
79 *
80 *  std::cout << "Setting Local timezone ..." << std::endl;
81 *  myBirth.setSystemTimezone();
82 *  birthday.setSystemTimezone();
83 *  std::cout << "EQUAL: birthday " << birthday.asString() << "; myBirth " << myBirth.asString() << std::endl;
84 *  std::cout << "EQUAL: birthday (Local Timezone)= " << birthday.yyyymmddHHmmss() << "; myBirth (Local Timezone)= " << myBirth.yyyymmddHHmmss() << std::endl;
85 *  std::cout << "myBirth TZ  = " << myBirth.getTzAsString() << std::endl;
86 *  std::cout << "birthday TZ  = " << myBirth.getTzAsString() << std::endl;
87 *
88 *  myBirth.setTz("GMT");
89 *  std::cout << "myBirth in GMT = " << myBirth.yyyymmddHHmmss() << std::endl;
90 *
91 *  Program output:
92 *
93 *  SystemTimezone: <TZ unset\>
94 *  myBirth: Thursday 19/12/1974 10:15:00 CET, isdst = 0 [Unix Timestamp: 156676500, Ntp Timestamp: 2365665300], System Timezone: <TZ unset\>
95 *  same_moment_canary_island: Thursday 19/12/1974 09:15:00 GMT, isdst = 0 [Unix Timestamp: 156676500, Ntp Timestamp: 2365665300], System Timezone: <TZ unset\>
96 *  myBirth on GMT: Thursday 19/12/1974 09:15:00 GMT, isdst = 0 [Unix Timestamp: 156676500, Ntp Timestamp: 2365665300], System Timezone: <TZ unset\>
97 *  EQUAL: same_moment_canary_island = 19741219091500; myBirth in context GMT = 19741219091500
98 *  same_moment_canary_island on CET: Thursday 19/12/1974 10:15:00 CET, isdst = 0 [Unix Timestamp: 156676500, Ntp Timestamp: 2365665300], System Timezone: <TZ unset\>
99 *  EQUAL: birthday TS = 156676500; myBirth TS = 156676500
100 *  birthday EET = Thursday 19/12/1974 11:15:00 EET, isdst = 0 [Unix Timestamp: 156676500, Ntp Timestamp: 2365665300], System Timezone: <TZ unset\>
101 *  Setting Local timezone ...
102 *  EQUAL: birthday Thursday 19/12/1974 10:15:00 <TZ unset\>, isdst = 0 [Unix Timestamp: 156676500, Ntp Timestamp: 2365665300], System Timezone: <TZ unset\>; myBirth Thursday 19/12/1974 10:15:00 <TZ unset\>, isdst = 0 [Unix Timestamp: 156676500, Ntp Timestamp: 2365665300], System Timezone: <TZ unset\>
103 *  EQUAL: birthday (Local Timezone)= 19741219101500; myBirth (Local Timezone)= 19741219101500
104 *  myBirth TZ  = <TZ unset\>
105 *  birthday TZ  = <TZ unset\>
106 *  myBirth in GMT = 19741219091500
107 *
108 * </pre>
109 */
110
111 class Date {
112   /////////////////////////////////////////////////
113   // Key: Keep coherent all time representations //
114   /////////////////////////////////////////////////
115
116   // Main data:
117   Timezone a_tz;            // timezone for this instance context
118   time_t a_timestamp; // unix timestamp
119
120   // Secondary data:
121   struct tm a_tm;
122
123
124   // sets the current date/time (time(NULL)) and provided TimeZone as described in constructor
125   void initialize(const char *TZ = NULL) ;
126
127   // main refresh method regarding timestamp
128   void refresh(void) ;
129
130   anna::Mutex a_mutex;
131
132 public:
133
134   /**
135   * Default Constructor
136   * @param TZ timezone for date/time representation. Default (NULL) assumes the system
137   * timezone configuration. Empty string will be interpreted as UTC timezone.
138   */
139   Date(const char *TZ = NULL);
140
141   /**
142   * Copy Constructor
143   */
144   Date(const Date & d) { *this = d; }
145
146   /**
147   * Destructor
148   */
149   ~Date() {;}
150
151
152   // setters
153
154   /**
155   * Sets the current date/time (time(NULL)) and provided TimeZone as described in constructor
156   */
157   void setNow(const char *TZ = NULL) { initialize(TZ); }
158
159
160   /**
161   * Sets the provided timezone for date/time representation of the class instance.
162   * This method keeps invariant the unix timestamp, thus, the date representation
163   *  will evolve depending on the configured timezone.
164   * @warning Be careful with incorrect TZ values because no error will be shown but
165   * dates could be misleading. The valid TZ could be seen with tzselect tool or
166   * directly looking at /usr/share/zoneinfo hierarchy.
167   *
168   * @param TZ timezone for date/time representation.
169   * Default (NULL) is the local host (user-supplied) timezone
170   * Empty string sets UTC0 (GMT, Greenwich)
171   * Use available timezones in /usr/share/zoneinfo; i.e.: Europe/Madrid, CET, etc.
172   * You can also use 'tzselect' helper, but that tool don't change the system
173   * timezone, only helps to know the valid TZ values and shows how to change
174   * the timezone settings if you would want to do that).
175   */
176   void setTz(const char *TZ = NULL) ;
177
178
179   /**
180    Sets the local host timezone (even if it is based on TZ or in /usr/share/zoneinfo)
181   */
182   void setSystemTimezone() ;
183
184
185   /**
186   * Sets date/time providing unix timestamp (seconds since 01-Jan-1970 GMT)
187   *
188   * @param unixTimestamp Time since 01-Jan-1970 GMT
189   */
190   void store(const time_t & unixTimestamp) ;
191   void storeUnix(const time_t & unixTimestamp) { store(unixTimestamp); }
192
193
194   /**
195   * Sets date/time providing ntp timestamp (seconds since 01-Jan-1900 GMT)
196   *
197   * @param ntpTimestamp Time since 01-Jan-1900 GMT
198   */
199   void storeNtp(const unsigned int &ntpTimestamp) ;
200
201
202   /**
203   * Sets date/time from standard 'tm' struct and optional timezone
204   *
205   * @param date 'tm' struct date/time
206   * @param TZ timezone for date/time provided. Default (NULL) assumes the system
207   * timezone configuration. Empty string will be interpreted as UTC timezone.
208   */
209   void store(const struct tm &date, const char *TZ = NULL) noexcept(false);
210
211
212   /**
213   * Sets date/time from string representation with certain provided format,
214   * and optional timezone
215   *
216   * @param stringDate Date/time string
217   * @param TZ timezone for date/time provided. Default (NULL) assumes the system
218   * timezone configuration. Empty string will be interpreted as UTC timezone.
219   * @param strptimeFormat Date/time string format for strptime primitive.
220   * See format syntax at http://man7.org/linux/man-pages/man3/strptime.3.html
221   */
222   void store(const std::string &stringDate, const char *TZ = NULL, const char *strptimeFormat = "%Y%m%d%H%M%S") noexcept(false);
223   //void store(const std::string &stringDate, const char *tz = NULL, const char *strptimeFormat = "%Y-%m-%d-%H-%M-%S") noexcept(false);
224
225
226   /**
227   * Copy Operator
228   *
229   * @param d Source class instance
230   *
231   * @return Returns copied reference
232   */
233   Date & operator = (const Date &d);
234
235   // gets
236
237   // Operators
238
239   /**
240   * Operator ==
241   *
242   * @param d1 First instance from Date class
243   * @param d2 Second instance from Date class
244   *
245   * @return Returns d1 == d2 comparison
246   */
247   friend bool operator == (const Date & d1, const Date & d2) {
248     return (d1.getUnixTimestamp() == d2.getUnixTimestamp());
249   }
250
251   /**
252   * Operator !=
253   *
254   * @param d1 First instance from Date class
255   * @param d2 Second instance from Date class
256   *
257   * @return Returns d1 != d2 comparison
258   */
259   friend bool operator != (const Date & d1, const Date & d2) {
260     return (d1.getUnixTimestamp() != d2.getUnixTimestamp());
261   }
262
263   /**
264   * Operator <=
265   *
266   * @param d1 First instance from Date class
267   * @param d2 Second instance from Date class
268   *
269   * @return Returns d1 <= d2 comparison (compare unix timestamp unix, ignore TZ)
270   */
271   friend bool operator <= (const Date & d1, const Date & d2) {
272     return (d1.getUnixTimestamp() <= d2.getUnixTimestamp());
273   }
274
275   /**
276   * Operator >=
277   *
278   * @param d1 First instance from Date class
279   * @param d2 Second instance from Date class
280   *
281   * @return Returns d1 >= d2 comparison (compare unix timestamp unix, ignore TZ)
282   */
283   friend bool operator >= (const Date & d1, const Date & d2) {
284     return (d1.getUnixTimestamp() >= d2.getUnixTimestamp());
285   }
286
287
288   /**
289   * Gets context instance timezone information
290   *
291   * @return  NULL if TZ is unset, or string for TZ environment variable
292   * (empty is allowed and use to be understood as UTC.
293   */
294   const char *getTz(void) const { return (a_tz.unsetTZ() ? NULL:a_tz.getValue().c_str()); }
295
296
297   /**
298   * Gets the context timezone as string
299   */
300   std::string getTzAsString() const { return a_tz.asString(); }
301
302
303   /**
304   * Gets 'tm' struct on the current timezone
305   *
306   * @return 'tm' struct on the current timezone
307   */
308   const struct tm & getTm(void) const { return a_tm; }
309
310   /**
311   * Gets the week day abbreviation: Sun, Mon, Tue, Wed, Thu, Fri, Sat
312   *
313   * @return Day of the week
314   */
315   const char *getDay(void) const ;
316
317
318   /**
319   * Gets 'yyyymmddHHmmss' representation for the current timezone
320   *
321   * @return Time/date on format 'yyyymmddHHmmss'
322   *
323   * @see getTz
324   */
325   std::string yyyymmddHHmmss(void) const ;
326
327
328   /**
329   * Gets unix timestamp (01-Jan-1970 GMT)
330   *
331   * @return Seconds since 01-Jan-1970 GMT
332   */
333   const time_t & getUnixTimestamp(void) const { return a_timestamp; }
334
335
336   /**
337   * Gets ntp timestamp (01-Jan-1900 GMT)
338   *
339   * @return Seconds since 01-Jan-1900 GMT
340   */
341   unsigned int getNtpTimestamp(void) const {
342     unsigned int ntp_timestamp = a_timestamp + TIMESTAMP_OFFSET_NTP1900_OVER_UNIX1970;
343     return ntp_timestamp;
344   }
345
346
347   /**
348   * Class string representation
349   *
350   * @return String with class content
351   */
352   std::string asString(void) const ;
353
354
355   /**
356   * Class XML representation
357   *
358   * @return XML with class content
359   */
360   anna::xml::Node* asXML(anna::xml::Node* parent) const ;
361
362 };
363
364 }
365 }
366
367 #endif
368