1 /*
2 * Copyright 2005-2014 Fabrice Colin
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 #include "config.h"
20 #include <stdio.h>
21 #include <stdlib.h>
22 #ifdef HAVE_TIMEGM
23 #ifndef _XOPEN_SOURCE
24 #define _XOPEN_SOURCE
25 #include <time.h>
26 #undef _XOPEN_SOURCE
27 #else
28 #include <time.h>
29 #endif
30 #else
31 #include <time.h>
32 /* This comment and function are taken from Wget's mktime_from_utc()
33 Converts struct tm to time_t, assuming the data in tm is UTC rather
34 than local timezone.
35
36 mktime is similar but assumes struct tm, also known as the
37 "broken-down" form of time, is in local time zone. mktime_from_utc
38 uses mktime to make the conversion understanding that an offset
39 will be introduced by the local time assumption.
40
41 mktime_from_utc then measures the introduced offset by applying
42 gmtime to the initial result and applying mktime to the resulting
43 "broken-down" form. The difference between the two mktime results
44 is the measured offset which is then subtracted from the initial
45 mktime result to yield a calendar time which is the value returned.
46
47 tm_isdst in struct tm is set to 0 to force mktime to introduce a
48 consistent offset (the non DST offset) since tm and tm+o might be
49 on opposite sides of a DST change.
50
51 Some implementations of mktime return -1 for the nonexistent
52 localtime hour at the beginning of DST. In this event, use
53 mktime(tm - 1hr) + 3600.
54
55 Schematically
56 mktime(tm) --> t+o
57 gmtime(t+o) --> tm+o
58 mktime(tm+o) --> t+2o
59 t+o - (t+2o - t+o) = t
60
61 Note that glibc contains a function of the same purpose named
62 `timegm' (reverse of gmtime). But obviously, it is not universally
63 available, and unfortunately it is not straightforwardly
64 extractable for use here. Perhaps configure should detect timegm
65 and use it where available.
66
67 Contributed by Roger Beeman <beeman@cisco.com>, with the help of
68 Mark Baushke <mdb@cisco.com> and the rest of the Gurus at CISCO.
69 Further improved by Roger with assistance from Edward J. Sabol
70 based on input by Jamie Zawinski. */
mktime_from_utc(struct tm * t)71 static time_t mktime_from_utc (struct tm *t)
72 {
73 time_t tl, tb;
74 struct tm *tg;
75
76 tl = mktime (t);
77 if (tl == -1)
78 {
79 t->tm_hour--;
80 tl = mktime (t);
81 if (tl == -1)
82 return -1; /* can't deal with output from strptime */
83 tl += 3600;
84 }
85 tg = gmtime (&tl);
86 tg->tm_isdst = 0;
87 tb = mktime (tg);
88 if (tb == -1)
89 {
90 tg->tm_hour--;
91 tb = mktime (tg);
92 if (tb == -1)
93 return -1; /* can't deal with output from gmtime */
94 tb += 3600;
95 }
96 return (tl - (tb - tl));
97 }
98 #endif
99 #ifdef USE_NEON
100 #include <neon/ne_dates.h>
101 #else
102 #ifdef USE_CURL
103 #include <curl/curl.h>
104 #endif
105 #endif
106
107 #include <iostream>
108
109 #include "TimeConverter.h"
110
111 using std::clog;
112 using std::endl;
113 using std::string;
114
TimeConverter()115 TimeConverter::TimeConverter()
116 {
117 }
118
119 // Inverse of gmtime().
timegm(struct tm * tm)120 time_t TimeConverter::timegm(struct tm *tm)
121 {
122 #ifdef HAVE_TIMEGM
123 return ::timegm(tm);
124 #else
125 return mktime_from_utc(tm);
126 #endif
127 }
128
129 /// Converts into an RFC 822 timestamp.
toTimestamp(time_t aTime,bool inGMTime)130 string TimeConverter::toTimestamp(time_t aTime, bool inGMTime)
131 {
132 struct tm *pTimeTm = new struct tm;
133
134 if (((inGMTime == true) &&
135 #ifdef HAVE_GMTIME_R
136 (gmtime_r(&aTime, pTimeTm) != NULL)
137 #else
138 ((pTimeTm = gmtime(&aTime)) != NULL)
139 #endif
140 ) ||
141 #ifdef HAVE_LOCALTIME_R
142 (localtime_r(&aTime, pTimeTm) != NULL)
143 #else
144 ((pTimeTm = localtime(&aTime)) != NULL)
145 #endif
146 )
147 {
148 char timeStr[64];
149 size_t formattedSize = 0;
150
151 if (inGMTime == true)
152 {
153 formattedSize = strftime(timeStr, 64, "%a, %d %b %Y %H:%M:%S GMT", pTimeTm);
154 }
155 else
156 {
157 // FIXME: don't use this extension ?
158 #if defined(__GNU_LIBRARY__)
159 // %z is a GNU extension
160 formattedSize = strftime(timeStr, 64, "%a, %d %b %Y %H:%M:%S %z", pTimeTm);
161 #else
162 formattedSize = strftime(timeStr, 64, "%a, %d %b %Y %H:%M:%S %Z", pTimeTm);
163 #endif
164 }
165 if (formattedSize > 0)
166 {
167 delete pTimeTm;
168
169 return timeStr;
170 }
171 }
172 delete pTimeTm;
173
174 return "";
175 }
176
177 /// Converts from a RFC 822 timestamp.
fromTimestamp(const string & timestamp)178 time_t TimeConverter::fromTimestamp(const string ×tamp)
179 {
180 if (timestamp.empty() == true)
181 {
182 return 0;
183 }
184
185 #ifdef USE_NEON
186 return ne_rfc1123_parse(timestamp.c_str());
187 #else
188 #ifdef USE_CURL
189 return curl_getdate(timestamp.c_str(), NULL);
190 #else
191 return time(NULL);
192 #endif
193 #endif
194 }
195
196 /// Converts to a YYYYMMDD-formatted string.
toYYYYMMDDString(int year,int month,int day)197 string TimeConverter::toYYYYMMDDString(int year, int month, int day)
198 {
199 char dateStr[64];
200
201 if (year < 0)
202 {
203 year = 0;
204 }
205 else if (year > 9999)
206 {
207 year = 9999;
208 }
209 if (month < 1)
210 {
211 month = 1;
212 }
213 else if (month > 12)
214 {
215 month = 12;
216 }
217 if (day < 1)
218 {
219 day = 1;
220 }
221 else if (day > 31)
222 {
223 day = 31;
224 }
225
226 if (snprintf(dateStr, 63, "%04d%02d%02d", year, month, day) > 0)
227 {
228 return dateStr;
229 }
230
231 return "";
232 }
233
234 /// Converts from a YYYYMMDD-formatted string.
fromYYYYMMDDString(const string & yyyymmdd,bool inGMTime)235 time_t TimeConverter::fromYYYYMMDDString(const string &yyyymmdd, bool inGMTime)
236 {
237 struct tm timeTm;
238 time_t gmTime = 0;
239
240 // Initialize the structure
241 timeTm.tm_sec = timeTm.tm_min = timeTm.tm_hour = timeTm.tm_mday = 0;
242 timeTm.tm_mon = timeTm.tm_year = timeTm.tm_wday = timeTm.tm_yday = timeTm.tm_isdst = 0;
243
244 #ifdef HAVE_STRPTIME
245 strptime(yyyymmdd.c_str(), "%Y%m%d", &timeTm);
246 #else
247 timeTm.tm_year = atoi(yyyymmdd.substr(0, 4).c_str());
248 timeTm.tm_mon = atoi(yyyymmdd.substr(4, 2).c_str());
249 timeTm.tm_mday = atoi(yyyymmdd.substr(6, 2).c_str());
250 #endif
251 #ifdef DEBUG
252 clog << "TimeConverter::fromYYYYMMDDString: " << timeTm.tm_year << " " << timeTm.tm_mon << " " << timeTm.tm_mday << endl;
253 #endif
254 if (inGMTime == true)
255 {
256 gmTime = timegm(&timeTm);
257 }
258 else
259 {
260 gmTime = mktime(&timeTm);
261 }
262
263 return gmTime;
264 }
265
266 /// Converts to a HHMMSS-formatted string.
toHHMMSSString(int hours,int minutes,int seconds)267 string TimeConverter::toHHMMSSString(int hours, int minutes, int seconds)
268 {
269 char timeStr[64];
270
271 if (hours < 0)
272 {
273 hours = 0;
274 }
275 else if (hours > 23)
276 {
277 hours = 23;
278 }
279 if (minutes < 0)
280 {
281 minutes = 0;
282 }
283 else if (minutes > 59)
284 {
285 minutes = 59;
286 }
287 if (seconds < 0)
288 {
289 seconds = 0;
290 }
291 else if (seconds > 59)
292 {
293 seconds = 59;
294 }
295
296 if (snprintf(timeStr, 63, "%02d%02d%02d", hours, minutes, seconds) > 0)
297 {
298 return timeStr;
299 }
300
301 return "";
302 }
303
304 /// Converts from a HHMMSS-formatted string.
fromHHMMSSString(const string & hhmmss,bool inGMTime)305 time_t TimeConverter::fromHHMMSSString(const string &hhmmss, bool inGMTime)
306 {
307 struct tm timeTm;
308 time_t gmTime = 0;
309
310 // Initialize the structure
311 timeTm.tm_sec = timeTm.tm_min = timeTm.tm_hour = timeTm.tm_mday = 0;
312 timeTm.tm_mon = timeTm.tm_year = timeTm.tm_wday = timeTm.tm_yday = timeTm.tm_isdst = 0;
313
314 #ifdef HAVE_STRPTIME
315 strptime(hhmmss.c_str(), "%H%M%S", &timeTm);
316 #else
317 timeTm.tm_hour = atoi(hhmmss.substr(0, 2).c_str());
318 timeTm.tm_min = atoi(hhmmss.substr(2, 2).c_str());
319 timeTm.tm_sec = atoi(hhmmss.substr(4, 2).c_str());
320 #endif
321 #ifdef DEBUG
322 clog << "TimeConverter::fromHHMMSSString: " << timeTm.tm_hour << " " << timeTm.tm_min << " " << timeTm.tm_sec << endl;
323 #endif
324 if (inGMTime == true)
325 {
326 gmTime = timegm(&timeTm);
327 }
328 else
329 {
330 gmTime = mktime(&timeTm);
331 }
332
333 return gmTime;
334 }
335
toNormalDate(time_t aTime,DateFormat format)336 string TimeConverter::toNormalDate(time_t aTime, DateFormat format)
337 {
338 struct tm *pTimeTm = new struct tm;
339
340 if (
341 #ifdef HAVE_LOCALTIME_R
342 (localtime_r(&aTime, pTimeTm) != NULL)
343 #else
344 ((pTimeTm = localtime(&aTime)) != NULL)
345 #endif
346 )
347 {
348 char timeStr[64];
349 size_t formattedSize = 0;
350
351 if (format == DATE_EUROPE)
352 {
353 // FIXME: don't use this extension ?
354 #if defined(__GNU_LIBRARY__)
355 // %z is a GNU extension
356 formattedSize = strftime(timeStr, 64, "%A, %d %B %Y %H:%M:%S %z", pTimeTm);
357 #else
358 formattedSize = strftime(timeStr, 64, "%A, %d %B %Y %H:%M:%S %Z", pTimeTm);
359 #endif
360 }
361 else
362 {
363 // FIXME: don't use this extension ?
364 #if defined(__GNU_LIBRARY__)
365 // %z is a GNU extension
366 formattedSize = strftime(timeStr, 64, "%Y-%m-%d %a %H:%M:%S %z", pTimeTm);
367 #else
368 formattedSize = strftime(timeStr, 64, "%Y-%m-%d %a %H:%M:%S %Z", pTimeTm);
369 #endif
370 }
371 if (formattedSize > 0)
372 {
373 delete pTimeTm;
374
375 return timeStr;
376 }
377 }
378 delete pTimeTm;
379
380 return "";
381 }
382
383