Remove dynamic exceptions
[anna.git] / source / time / Date.cpp
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 #include <anna/core/tracing/Logger.hpp>
10 #include <anna/core/tracing/TraceWriter.hpp>
11 #include <anna/config/defines.hpp>
12 #include <anna/core/functions.hpp>
13 #include <anna/core/mt/Guard.hpp>
14 #include <anna/xml/xml.hpp>
15
16 // Local
17 #include <anna/time/Date.hpp>
18 #include <anna/time/functions.hpp>
19 #include <anna/time/internal/sccs.hpp>
20
21 // Standard
22 #include <stdlib.h> // putenv
23 #include <iostream>
24
25
26 using namespace anna;
27 using namespace anna::time;
28
29
30
31 //******************************************************************************
32 //------------------------------------------------------------------------- Date
33 //******************************************************************************
34
35 // private:
36
37 //------------------------------------------------------------------------------
38 //----------------------------------------------------------- Date::initialize()
39 //------------------------------------------------------------------------------
40 void Date::initialize(const char * TZ) {
41   a_timestamp = ::time(NULL);
42   setTz(TZ);
43 }
44
45
46 //------------------------------------------------------------------------------
47 //-------------------------------------------------------------- Date::refresh()
48 //------------------------------------------------------------------------------
49 void Date::refresh(void) {
50   anna::Guard guard(a_mutex);
51
52   // Set current/programmed timezone
53   a_tz.apply();
54
55   // Rescue info:
56   struct tm *ptrTm = localtime(&a_timestamp);
57   a_tm = *ptrTm;
58 }
59
60
61
62 // public:
63
64 //------------------------------------------------------------------------------
65 //----------------------------------------------------------------- Date::Date()
66 //------------------------------------------------------------------------------
67 Date::Date(const char *TZ) {
68   time::sccs::activate();
69
70   if(!functions::initialized()) {
71     std::cerr << std::endl << "Develop ERROR: you should firstly invoke anna::time::functions::initialize() before using time module" << std::endl;
72   }
73
74   initialize(TZ);
75 };
76
77
78 //------------------------------------------------------------------------------
79 //---------------------------------------------------------------- Date::setTz()
80 //------------------------------------------------------------------------------
81 void Date::setTz(const char * TZ) {
82   if (TZ) a_tz.set(TZ);
83   else a_tz = functions::getSystemTimezone(); 
84
85   refresh();
86 }
87
88
89 //------------------------------------------------------------------------------
90 //---------------------------------------------------- Date::setSystemTimezone()
91 //------------------------------------------------------------------------------
92 void Date::setSystemTimezone() {
93   a_tz = functions::getSystemTimezone();
94   // Refresh the other data:
95   refresh();
96 }
97
98
99 //------------------------------------------------------------------------------
100 //---------------------------------------------------------------- Date::store()
101 //------------------------------------------------------------------------------
102 void Date::store(const time_t & unixTimestamp) {
103   a_timestamp = unixTimestamp;
104   // Refresh the other data:
105   refresh();
106 }
107
108
109 //------------------------------------------------------------------------------
110 //------------------------------------------------------------- Date::storeNtp()
111 //------------------------------------------------------------------------------
112 void Date::storeNtp(const unsigned int & ntpTimestamp) {
113   a_timestamp = ntpTimestamp - TIMESTAMP_OFFSET_NTP1900_OVER_UNIX1970;
114   // Refresh the other data:
115   refresh();
116 }
117
118
119 //------------------------------------------------------------------------------
120 //---------------------------------------------------------------- Date::store()
121 //------------------------------------------------------------------------------
122 void Date::store(const struct tm &date, const char *TZ)
123
124 noexcept(false)
125
126 {
127   if (TZ) {
128     Timezone aux;
129     aux.set(TZ);
130     aux.apply();
131   }
132   else {
133     functions::getSystemTimezone().apply();
134   }
135
136   // Set '-1' on 'tm_isdst', or it could be an ambiguity on tranformation
137   //  returning inexact timestamp. This setting force system to check the correct flag:
138   struct tm dateIsdst_1 = date;
139   dateIsdst_1.tm_isdst = -1;
140   time_t unixTimestamp = mktime((struct tm*) & dateIsdst_1);
141
142   if(unixTimestamp == (time_t) - 1)
143     throw anna::RuntimeException("Error during mktime() conversion !!", ANNA_FILE_LOCATION);
144
145   a_timestamp = unixTimestamp;
146
147   // Refresh the othr data:
148   refresh();
149 }
150
151
152 //------------------------------------------------------------------------------
153 //---------------------------------------------------------------- Date::store()
154 //------------------------------------------------------------------------------
155 void Date::store(const std::string &stringDate, const char *TZ, const char *strptimeFormat)
156 noexcept(false)
157 {
158   if(strptimeFormat == NULL)
159     throw anna::RuntimeException("Invalid NULL strptimeFormat !!", ANNA_FILE_LOCATION);
160
161   // Get equivalent 'tm':
162   struct tm tmOrigin;
163   memset(&tmOrigin, 0, sizeof(tmOrigin));
164
165   if(strptime(stringDate.c_str(), strptimeFormat, &tmOrigin) == NULL) {
166     std::string msg("Error during strptime() conversion: '");
167     msg += stringDate;
168     msg += "' can't be interpreted as '";
169     msg += strptimeFormat;
170     msg += "'";
171     throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
172   }
173
174   store(tmOrigin, TZ);
175 }
176
177
178 //------------------------------------------------------------------------------
179 //-------------------------------------------------------------- Date::operator=
180 //------------------------------------------------------------------------------
181 Date & Date::operator = (const Date & d) {
182   // avoid itself copy: i.e., Date a,b; a=&b; a=b; b=a;
183   if(this == &d) return (*this);
184
185   a_timestamp = d.getUnixTimestamp();
186   a_tz.set(d.getTz());
187   a_tm = d.getTm();
188   return (*this);
189 }
190
191
192 // gets
193
194
195 //------------------------------------------------------------------------------
196 //--------------------------------------------------------------- Date::getDay()
197 //------------------------------------------------------------------------------
198 const char *Date::getDay(void) const {
199
200   static const char *weekdayname[] = {"Sunday", "Monday", "Tuesday",
201     "Wednesday", "Thursday", "Friday", "Saturday"};
202
203   return weekdayname[a_tm.tm_wday];
204 }
205
206
207 //------------------------------------------------------------------------------
208 //------------------------------------------------------- Date::yyyymmddHHmmss()
209 //------------------------------------------------------------------------------
210 std::string Date::yyyymmddHHmmss(void) const {
211   return anna::functions::asString("%04d%02d%02d%02d%02d%02d",
212      1900 + a_tm.tm_year, 1 + (a_tm.tm_mon), a_tm.tm_mday,
213      a_tm.tm_hour, a_tm.tm_min, a_tm.tm_sec);
214 }
215
216
217 //------------------------------------------------------------------------------
218 //------------------------------------------------------------- Date::asString()
219 //------------------------------------------------------------------------------
220 std::string Date::asString(void) const {
221
222   std::string result = anna::functions::asString("%s %02d/%02d/%04d %02d:%02d:%02d ", getDay(),
223                           getTm().tm_mday, 1 + (getTm().tm_mon), 1900 + getTm().tm_year,
224                           getTm().tm_hour, getTm().tm_min, getTm().tm_sec);
225   result += getTzAsString();
226   result += anna::functions::asString(", isdst = %d [Unix Timestamp: %ld, Ntp Timestamp: %u]", getTm().tm_isdst, getUnixTimestamp(), getNtpTimestamp());
227   result += ", System Timezone: ";
228   result += functions::getSystemTimezone().asString();
229
230   return result;
231 }
232
233
234 //------------------------------------------------------------------------------
235 //---------------------------------------------------------------- Date::asXML()
236 //------------------------------------------------------------------------------
237 anna::xml::Node* Date::asXML(anna::xml::Node* parent) const {
238   //anna::xml::Node* result = parent->createChild("anna.time.Date");
239   parent->createAttribute("Date", anna::functions::asString("%02d/%02d/%04d", getTm().tm_mday, 1 + (getTm().tm_mon), 1900 + getTm().tm_year));
240   parent->createAttribute("Day", getDay());
241   parent->createAttribute("Time", anna::functions::asString("%02d:%02d:%02d", getTm().tm_hour, getTm().tm_min, getTm().tm_sec));
242   parent->createAttribute("TZ", getTzAsString());
243   parent->createAttribute("Isdst", (getTm().tm_isdst) ? "yes" : "no");
244   parent->createAttribute("UnixTimestamp", anna::functions::asString((const int)getUnixTimestamp()));
245   parent->createAttribute("NtpTimestamp", anna::functions::asString(getNtpTimestamp()));
246   parent->createAttribute("SystemTimezone", functions::getSystemTimezone().asString());
247
248   return parent;
249 }
250