First commit
[anna.git] / include / anna / time / Date.hpp
1 // ANNA - Anna is Not 'N' Anymore
2 //
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
4 //
5 // https://bitbucket.org/testillano/anna
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 //
11 //     * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 //     * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
16 // distribution.
17 //     * Neither the name of Google Inc. nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 //
33 // Authors: eduardo.ramos.testillano@gmail.com
34 //          cisco.tierra@gmail.com
35
36
37 #ifndef anna_time_Date_hpp
38 #define anna_time_Date_hpp
39
40 #include <anna/core/RuntimeException.hpp>
41 #include <anna/core/mt/Mutex.hpp>
42
43 // Standard
44 #include <time.h>
45
46 // Local
47 #include <anna/time/internal/TZ.hpp>
48
49
50 namespace anna {
51 namespace xml {
52 class Node;
53 }
54 }
55
56 //------------------------------------------------------------------------------
57 //---------------------------------------------------------------------- #define
58 //------------------------------------------------------------------------------
59 #define _2K38_EFFECT_LIMIT "20380119031407" // UTC
60
61 // Era Unix:  01/01/1970 00:00:00 UTC
62 // Fecha NTP: 01/01/1900 00:00:00 UTC
63 // -> Segundos de 70 años ( de 1900 a 1970) : 2207520000
64 // -> Entre 1900 y 1970 hay 17años bisiestos, por lo que hay que sumar 17 días: 1468800 Segundos
65 // TOTAL = 2207520000 + 1468800 :
66 // Significa que debemos restar el anterior valor para obtener un valor unix, y sumarlo para tener un timestamp NTP:
67 #define TIMESTAMP_OFFSET_NTP1900_OVER_UNIX1970   2208988800U
68
69 // The NTP timestamp format represents seconds and fraction as a 64-bit unsigned fixed-point
70 // integer with decimal point to the left of bit 32 numbered from the left. The 32-bit seconds
71 // field spans about 136 years, while the 32-bit fraction field precision is about 232 picoseconds.
72
73 // Para un timestamp NTP me bastan 32 bits, es decir 'unsigned int'. El tipo time_t es realmente un int. Cojo
74 // el mayor entre ambos: unsigned int.
75
76
77 #define STRING_FORMAT_yyyymmddHHmmss         "%04d%02d%02d%02d%02d%02d"
78 #define STRPTIME_FORMAT_yyyy_mm_dd_HH_mm_ss  "%Y-%m-%d-%H-%M-%S"
79
80
81
82 namespace anna {
83
84 namespace time {
85
86
87 /**
88 * Absolute time representation structs class manager.
89 * Allow any time assignment/extraction regarding any timezone.
90 *
91 * Certain methods could launch runtime exception when trying to get TZ from shell.
92 *
93 * <pre>
94 *
95 * I.e., supose you have TZ="MET" on host (on Madrid):
96 *
97 *   resources::time::Date edu_birth("CET");
98 *   //resources::time::Date edu_birth; // if Context TZ = shell TZ = "CET"
99 *   edu_birth.store ("19741219101500");
100 *   std::cout << "'edu_birth.asString()' is: " << edu_birth.asString() << std::endl;
101 *   std::cout << "'Timestamp' edu_birth (Madrid:CET): " << edu_birth.getUnixTimestamp() << std::endl;
102 *   struct tm Tm = edu_birth.getTm();
103 *   std::cout << "'Tm' edu_birth (madrid:CET): " << "tm_mday = " << Tm.tm_mday << ", tm_mon (0-11) = " << Tm.tm_mon
104 *   << ", tm_year (since 1900) = " << Tm.tm_year << ", tm_hour = " << Tm.tm_hour
105 *   << ", tm_min = " << Tm.tm_min << ", tm_sec = " << Tm.tm_sec << std::endl;
106 *   resources::time::Date same_moment_canary_island("GMT");
107 *   same_moment_canary_island.store (edu_birth.getUnixTimestamp());
108 *   std::cout << "'yyyymmddHHmmss' for 'same_moment_canary_island': " << (same_moment_canary_island.yyyymmddHHmmss()).c_str() << std::endl;
109 *   edu_birth.setTzContext ("GMT");
110 *   std::cout << "'yyyymmddHHmmss' for edu_birth, Local time on Canary Island: " << (edu_birth.yyyymmddHHmmss()).c_str() << std::endl;
111 *   resources::time::Date birthday("EET");
112 *   birthday.store (same_moment_canary_island.getTm(), "GMT"); // TZ origin = "GMT"
113 *   if (birthday == edu_birth)
114 *   {
115 *   std::cout << "'birthday' same as 'edu_birth', and 'yyyymmddHHmmss' is: " << (birthday.yyyymmddHHmmss()).c_str()
116 *   << " in TZ = " << (birthday.getTzContext()).getValue().c_str() << std::endl;
117 *   }
118 *
119 *   std::cout << "'birthday': " << birthday.asString() << std::endl;
120 *   std::cout << "'edu_birth': " << edu_birth.asString() << std::endl;
121 *
122 *   edu_birth.setTzContext (resources::time::functions::getLocalTz().getValue().c_str());
123 *   std::cout << "'edu_birth' on local TZ: " << edu_birth.asString() << std::endl;
124 *
125 *   //birthday.setTzContext("CET");
126 *   birthday.setTzContext (resources::time::functions::getLocalTz().getValue().c_str()); // Go from "EET" to "CET"
127 *   std::cout << "'yyyymmddHHmmss' for 'birthday' on Local TZ: " << (birthday.yyyymmddHHmmss()).c_str() << std::endl;
128 *   // Adding 18 years to 'edu_birth':
129 *   Tm.tm_year += 18;
130 *   resources::time::Date eighteen("CET");
131 *   eighteen.store (Tm);
132 *   if (eighteen >= same_moment_canary_island) // same as compare to 'edu_birth'
133 *   {
134 *   std::cout << "'eighteen' is 'yyyymmddHHmmss' = " << (eighteen.yyyymmddHHmmss()).c_str() << std::endl;
135 *   std::cout << "'eighteen' is later than timestamp for 'same_moment_canary_island' = " << same_moment_canary_island.getUnixTimestamp() << std::endl;
136 *   std::cout << "'eighteen' is later than timestamp for 'edu_birth' = " << edu_birth.getUnixTimestamp() << std::endl;
137 *   }
138 *
139 *
140 * -----------------------------------------------------------------------------------------------------------------------------
141 * Program output:
142 *
143 *   'edu_birth.asString()' is: 19/12/1974 10:15:00 CET, isdst = 0 [Unix Timestamp: 156676500], Local TZ = EET
144 *   'Timestamp' edu_birth (Madrid:CET): 156676500
145 *   'Tm' edu_birth (madrid:CET): tm_mday = 19, tm_mon (0-11) = 11, tm_year (since 1900) = 74, tm_hour = 10, tm_min = 15, tm_sec = 0
146 *   'yyyymmddHHmmss' for 'same_moment_canary_island': 19741219091500
147 *   'yyyymmddHHmmss' for edu_birth, Local time on Canary Island: 19741219091500
148 *   'birthday' same as 'edu_birth', and 'yyyymmddHHmmss' is: 19741219111500 in TZ = EET
149 *   'birthday': 19/12/1974 11:15:00 EET, isdst = 0 [Unix Timestamp: 156676500], Local TZ = EET
150 *   'edu_birth': 19/12/1974 09:15:00 GMT, isdst = 0 [Unix Timestamp: 156676500], Local TZ = EET
151 *   'edu_birth' on local TZ: 19/12/1974 10:15:00 EET, isdst = 0 [Unix Timestamp: 156676500], Local TZ = EET
152 *   'yyyymmddHHmmss' for 'birthday' on Local TZ: 19741219101500
153 *   'eighteen' is 'yyyymmddHHmmss' = 19921219101500
154 *   'eighteen' is later than timestamp for 'same_moment_canary_island' = 156676500
155 *   'eighteen' is later than timestamp for 'edu_birth' = 156676500
156 *
157 * </pre>
158 */
159
160 class Date {
161   /////////////////////////////////////////////////
162   // Key: Keep coherent all time representations //
163   /////////////////////////////////////////////////
164
165   // Main data:
166   TZ a_TZ_context;          // timezone for current representation
167   time_t a_unix_timestamp;  // unix timestamp
168
169   // Secondary data:
170   struct tm a_tm_struct;
171   std::string _yyyymmddHHmmss;        // string representation for 'tm'
172
173   // Auxiliar:
174   TZ a_local_tz;          // local tz on host
175   TZ a_work_tz;           // auxiliar tz
176
177   void _putenv(const char * Tz) throw();
178   void set_tz_context(const char * TzContext) throw();
179   const TZ & get_TZ_context(void) const throw();
180   void _initialize(const char * TzContext) throw();
181
182   void check_yyyymmddHHmmss(const std::string & yyyymmddHHmmss) throw(anna::RuntimeException);
183   void refresh_regarding_unix_timestamp(void) throw();   // main refresh method
184
185   anna::Mutex a_mutex;
186 public:
187
188   /**
189   * Default Constructor
190   */
191   Date(const char * TzContext = NULL);
192
193   /**
194   * Copy Constructor
195   */
196   Date(const Date & d);
197
198   /**
199   * Destructor
200   */
201   ~Date();
202
203
204   // sets
205
206
207   /**
208   * Class initialization with current date/time (time(NULL)) and provided TimeZone (default is Local TimeZone)
209   *
210   * @param TzContext timezone for date/time representation. Default is Local timezone
211   *
212   * @see setTzContext()
213   * @see store()
214   */
215   void initialize(const char * TzContext = NULL) throw();
216
217
218   /**
219   * Same as initialize()
220   */
221   void setCurrent(const char * TzContext = NULL) throw() { initialize(TzContext); }
222
223
224   /**
225   * Sets the provided timezone for date/time representation. default is Local timezone.
226   *
227   * @param TzContext timezone for date/time representation. Default is Local timezone
228   *
229   * @see initialize()
230   * @see store()
231   */
232   void setTzContext(const char * TzContext = NULL) throw();
233
234
235   /**
236   * Sets date/time from string 'yyyymmddHHmmss' representation (HH is 24 hour format, and string must be 14 digits-length),
237   * and optional timezone (default is local)
238   *
239   * @param yyyymmddHHmmss 'yyyymmddHHmmss' date/time
240   * @param OriginTz timezone for date/time provided. Default is Local TZ
241   *
242   * @see initialize()
243   * @see setTzContext()
244   */
245   void store(const std::string & yyyymmddHHmmss, const char * OriginTz = NULL) throw(anna::RuntimeException);
246
247
248   /**
249   * Sets date/time from string representation with certain provided format, and optional timezone (default is local)
250   *
251   * @param dateTimeAsStringFormat Date/time string format
252   * @param dateTimeAsString Date/time string
253   * @param OriginTz timezone for date/time provided. Default is Local TZ
254   *
255   * @see initialize()
256   * @see setTzContext()
257   */
258   void store(const char* dateTimeAsStringFormat, const std::string & dateTimeAsString, const char * OriginTz = NULL) throw(anna::RuntimeException);
259
260
261   /**
262   * Sets date/time from standard (time.h) 'tm' struct and optional timezone (default is local)
263   *
264   * @param TmOrigen 'tm' struct date/time
265   * @param OriginTz timezone for date/time provided. Default is Local TZ
266   *
267   * @see initialize()
268   * @see setTzContext()
269   */
270   void store(const struct tm & TmOrigen, const char * OriginTz = NULL) throw(anna::RuntimeException);
271
272
273   /**
274   * Sets date/time providing unix timestamp (seconds since 01-Jan-1970 GMT)
275   *
276   * @param unixTimestamp Time since 01-Jan-1970 GMT
277   *
278   * @see initialize()
279   * @see setTzContext()
280   */
281   void store(const time_t & unixTimestamp) throw();
282   void storeUnix(const time_t & unixTimestamp) throw() { store(unixTimestamp); }
283
284
285   /**
286   * Sets date/time providing ntp timestamp (seconds since 01-Jan-1900 GMT)
287   *
288   * @param ntpTimestamp Time since 01-Jan-1900 GMT
289   *
290   * @see initialize()
291   * @see setTzContext()
292   */
293   void storeNtp(const unsigned int & ntpTimestamp) throw();
294
295
296   /**
297   * Copy Operator
298   *
299   * @param d Source class instance
300   *
301   * @return Retunrs copied reference
302   */
303   Date & operator = (const Date &d);
304
305   // gets
306
307   // Operators
308
309   /**
310   * Operator ==
311   *
312   * @param d1 First instance from Date class
313   * @param d2 Second instance from Date class
314   *
315   * @return Returns d1 == d2 comparison
316   */
317   friend bool operator == (const Date & d1, const Date & d2) {
318     return (d1.getUnixTimestamp() == d2.getUnixTimestamp());
319   }
320
321   /**
322   * Operator !=
323   *
324   * @param d1 First instance from Date class
325   * @param d2 Second instance from Date class
326   *
327   * @return Returns d1 != d2 comparison
328   */
329   friend bool operator != (const Date & d1, const Date & d2) {
330     return (d1.getUnixTimestamp() != d2.getUnixTimestamp());
331   }
332
333   /**
334   * Operator <=
335   *
336   * @param d1 First instance from Date class
337   * @param d2 Second instance from Date class
338   *
339   * @return Returns d1 <= d2 comparison (compare unix timestamp unix, ignore TZ)
340   */
341   friend bool operator <= (const Date & d1, const Date & d2) {
342     return (d1.getUnixTimestamp() <= d2.getUnixTimestamp());
343   }
344
345   /**
346   * Operator >=
347   *
348   * @param d1 First instance from Date class
349   * @param d2 Second instance from Date class
350   *
351   * @return Returns d1 >= d2 comparison (compare unix timestamp unix, ignore TZ)
352   */
353   friend bool operator >= (const Date & d1, const Date & d2) {
354     return (d1.getUnixTimestamp() >= d2.getUnixTimestamp());
355   }
356
357
358   /**
359   * Gets context representation TZ
360   *
361   * @return context representation TZ
362   *
363   * @see yyyymmddHHmmss()
364   * @see getUnixTimestamp()
365   * @see getTm()
366   * @see asString()
367   */
368   const std::string & getTzContext(void) const throw();
369
370
371   /**
372   * Gets 'yyyymmddHHmmss' stored data
373   *
374   * @return Time/date on format 'yyyymmddHHmmss'
375   *
376   * @see getTzContext()
377   * @see getUnixTimestamp()
378   * @see getTm()
379   * @see asString()
380   */
381   const std::string & yyyymmddHHmmss(void) const throw();
382
383
384   /**
385   * Gets unix timestamp (01-Jan-1970 GMT)
386   *
387   * @return Seconds since 01-Jan-1970 GMT
388   *
389   * @see getTzContext()
390   * @see yyyymmddHHmmss()
391   * @see getTm()
392   * @see asString()
393   */
394   const time_t & getUnixTimestamp(void) const throw();
395
396
397   /**
398   * Gets ntp timestamp (01-Jan-1900 GMT)
399   *
400   * @return Seconds since 01-Jan-1900 GMT
401   *
402   * @see getTzContext()
403   * @see yyyymmddHHmmss()
404   * @see getTm()
405   * @see asString()
406   */
407   unsigned int getNtpTimestamp(void) const throw();
408
409
410   /**
411   * Gets 'tm' struct on context representation TZ
412   *
413   * @return 'tm' struct on context representation TZ
414   *
415   * @see getTzContext()
416   * @see yyyymmddHHmmss()
417   * @see getUnixTimestamp()
418   * @see asString()
419   */
420   const struct tm & getTm(void) const throw();
421
422
423   /**
424   * Class string representation
425   *
426   * @return String with class content
427   *
428   * @see asXML()
429   */
430   std::string asString(void) const throw();
431
432
433   /**
434   * Class XML representation
435   *
436   * @return XML with class content
437   *
438   * @see asString()
439   */
440   anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
441
442 };
443
444 }
445 }
446
447 #endif
448