1 // ANNA - Anna is Not 'N' Anymore
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
5 // https://bitbucket.org/testillano/anna
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
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
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.
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.
33 // Authors: eduardo.ramos.testillano@gmail.com
34 // cisco.tierra@gmail.com
37 #ifndef anna_time_Date_hpp
38 #define anna_time_Date_hpp
40 #include <anna/core/RuntimeException.hpp>
41 #include <anna/core/mt/Mutex.hpp>
47 #include <anna/time/internal/TZ.hpp>
56 //------------------------------------------------------------------------------
57 //---------------------------------------------------------------------- #define
58 //------------------------------------------------------------------------------
59 #define _2K38_EFFECT_LIMIT "20380119031407" // UTC
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
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.
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.
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"
88 * Absolute time representation structs class manager.
89 * Allow any time assignment/extraction regarding any timezone.
91 * Certain methods could launch runtime exception when trying to get TZ from shell.
95 * I.e., supose you have TZ="MET" on host (on Madrid):
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)
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;
119 * std::cout << "'birthday': " << birthday.asString() << std::endl;
120 * std::cout << "'edu_birth': " << edu_birth.asString() << std::endl;
122 * edu_birth.setTzContext (resources::time::functions::getLocalTz().getValue().c_str());
123 * std::cout << "'edu_birth' on local TZ: " << edu_birth.asString() << std::endl;
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':
130 * resources::time::Date eighteen("CET");
131 * eighteen.store (Tm);
132 * if (eighteen >= same_moment_canary_island) // same as compare to 'edu_birth'
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;
140 * -----------------------------------------------------------------------------------------------------------------------------
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
161 /////////////////////////////////////////////////
162 // Key: Keep coherent all time representations //
163 /////////////////////////////////////////////////
166 TZ a_TZ_context; // timezone for current representation
167 time_t a_unix_timestamp; // unix timestamp
170 struct tm a_tm_struct;
171 std::string _yyyymmddHHmmss; // string representation for 'tm'
174 TZ a_local_tz; // local tz on host
175 TZ a_work_tz; // auxiliar tz
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();
182 void check_yyyymmddHHmmss(const std::string & yyyymmddHHmmss) throw(anna::RuntimeException);
183 void refresh_regarding_unix_timestamp(void) throw(); // main refresh method
189 * Default Constructor
191 Date(const char * TzContext = NULL);
196 Date(const Date & d);
208 * Class initialization with current date/time (time(NULL)) and provided TimeZone (default is Local TimeZone)
210 * @param TzContext timezone for date/time representation. Default is Local timezone
212 * @see setTzContext()
215 void initialize(const char * TzContext = NULL) throw();
219 * Same as initialize()
221 void setCurrent(const char * TzContext = NULL) throw() { initialize(TzContext); }
225 * Sets the provided timezone for date/time representation. default is Local timezone.
227 * @param TzContext timezone for date/time representation. Default is Local timezone
232 void setTzContext(const char * TzContext = NULL) throw();
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)
239 * @param yyyymmddHHmmss 'yyyymmddHHmmss' date/time
240 * @param OriginTz timezone for date/time provided. Default is Local TZ
243 * @see setTzContext()
245 void store(const std::string & yyyymmddHHmmss, const char * OriginTz = NULL) throw(anna::RuntimeException);
249 * Sets date/time from string representation with certain provided format, and optional timezone (default is local)
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
256 * @see setTzContext()
258 void store(const char* dateTimeAsStringFormat, const std::string & dateTimeAsString, const char * OriginTz = NULL) throw(anna::RuntimeException);
262 * Sets date/time from standard (time.h) 'tm' struct and optional timezone (default is local)
264 * @param TmOrigen 'tm' struct date/time
265 * @param OriginTz timezone for date/time provided. Default is Local TZ
268 * @see setTzContext()
270 void store(const struct tm & TmOrigen, const char * OriginTz = NULL) throw(anna::RuntimeException);
274 * Sets date/time providing unix timestamp (seconds since 01-Jan-1970 GMT)
276 * @param unixTimestamp Time since 01-Jan-1970 GMT
279 * @see setTzContext()
281 void store(const time_t & unixTimestamp) throw();
282 void storeUnix(const time_t & unixTimestamp) throw() { store(unixTimestamp); }
286 * Sets date/time providing ntp timestamp (seconds since 01-Jan-1900 GMT)
288 * @param ntpTimestamp Time since 01-Jan-1900 GMT
291 * @see setTzContext()
293 void storeNtp(const unsigned int & ntpTimestamp) throw();
299 * @param d Source class instance
301 * @return Retunrs copied reference
303 Date & operator = (const Date &d);
312 * @param d1 First instance from Date class
313 * @param d2 Second instance from Date class
315 * @return Returns d1 == d2 comparison
317 friend bool operator == (const Date & d1, const Date & d2) {
318 return (d1.getUnixTimestamp() == d2.getUnixTimestamp());
324 * @param d1 First instance from Date class
325 * @param d2 Second instance from Date class
327 * @return Returns d1 != d2 comparison
329 friend bool operator != (const Date & d1, const Date & d2) {
330 return (d1.getUnixTimestamp() != d2.getUnixTimestamp());
336 * @param d1 First instance from Date class
337 * @param d2 Second instance from Date class
339 * @return Returns d1 <= d2 comparison (compare unix timestamp unix, ignore TZ)
341 friend bool operator <= (const Date & d1, const Date & d2) {
342 return (d1.getUnixTimestamp() <= d2.getUnixTimestamp());
348 * @param d1 First instance from Date class
349 * @param d2 Second instance from Date class
351 * @return Returns d1 >= d2 comparison (compare unix timestamp unix, ignore TZ)
353 friend bool operator >= (const Date & d1, const Date & d2) {
354 return (d1.getUnixTimestamp() >= d2.getUnixTimestamp());
359 * Gets context representation TZ
361 * @return context representation TZ
363 * @see yyyymmddHHmmss()
364 * @see getUnixTimestamp()
368 const std::string & getTzContext(void) const throw();
372 * Gets 'yyyymmddHHmmss' stored data
374 * @return Time/date on format 'yyyymmddHHmmss'
376 * @see getTzContext()
377 * @see getUnixTimestamp()
381 const std::string & yyyymmddHHmmss(void) const throw();
385 * Gets unix timestamp (01-Jan-1970 GMT)
387 * @return Seconds since 01-Jan-1970 GMT
389 * @see getTzContext()
390 * @see yyyymmddHHmmss()
394 const time_t & getUnixTimestamp(void) const throw();
398 * Gets ntp timestamp (01-Jan-1900 GMT)
400 * @return Seconds since 01-Jan-1900 GMT
402 * @see getTzContext()
403 * @see yyyymmddHHmmss()
407 unsigned int getNtpTimestamp(void) const throw();
411 * Gets 'tm' struct on context representation TZ
413 * @return 'tm' struct on context representation TZ
415 * @see getTzContext()
416 * @see yyyymmddHHmmss()
417 * @see getUnixTimestamp()
420 const struct tm & getTm(void) const throw();
424 * Class string representation
426 * @return String with class content
430 std::string asString(void) const throw();
434 * Class XML representation
436 * @return XML with class content
440 anna::xml::Node* asXML(anna::xml::Node* parent) const throw();