1 #include "config.h"
2 
3 #include <iostream>
4 // #include <sstream>
5 #include <iomanip>
6 #include <string>
7 #include <cstring>
8 #include <cctype>
9 
10 #ifdef HAVE_TIME_H
11 #include <time.h>
12 #endif
13 #ifdef HAVE_SYS_TYPES_H
14 #include <sys/types.h>
15 #endif
16 
17 #include "asserts.h"
18 #include "error.h"
19 #include "estring.h"
20 #include "tstamp.h"
21 
22 /** C'tor */
timestamp()23 timestamp::timestamp()
24 {
25 	clear();
26 	set();
27 }
28 
29 /** C'tor */
timestamp(const timestamp & a_t)30 timestamp::timestamp(const timestamp& a_t)
31 {
32 	clear();
33 	assign(a_t);
34 }
35 
36 /** C'tor */
timestamp(const int a_year,const int a_month,const int a_day,const int a_hour,const int a_minute,const int a_second)37 timestamp::timestamp(
38 	const int a_year,
39 	const int a_month,
40 	const int a_day,
41 	const int a_hour,
42 	const int a_minute,
43 	const int a_second
44 	)
45 {
46 	clear();
47 	assign(a_year,a_month,a_day,a_hour,a_minute,a_second);
48 }
49 
50 /** C'tor */
timestamp(const std::string & a_s)51 timestamp::timestamp(const std::string& a_s)
52 {
53 	clear();
54 	assign(a_s);
55 }
56 
57 /** Set the timestamp to the current time and date */
set(void)58 void timestamp::set(void)
59 {
60 	time_t t = 0;
61 	struct tm* tm_ptr = 0;
62 
63 	t = time(0);
64 	if (t == -1)
65 		throw(ERROR(errno,"Could not retrieve current time"));
66 	tm_ptr = localtime(&t);
67 	if (tm_ptr == 0)
68 		throw(ERROR(errno,"Could not convert current time to local time"));
69 	m_year = tm_ptr->tm_year + 1900;
70 	m_month = tm_ptr->tm_mon + 1;
71 	m_day = tm_ptr->tm_mday;
72 	m_hour = tm_ptr->tm_hour;
73 	m_minute = tm_ptr->tm_min;
74 	m_second = tm_ptr->tm_sec;
75 	m_resolution = resolution_day;
76 }
77 
78 /** Set the timestamp to the value of another timestamp */
assign(const timestamp & a_t)79 void timestamp::assign(const timestamp& a_t)
80 {
81 	m_year = a_t.year();
82 	m_month = a_t.month();
83 	m_day = a_t.day();
84 	m_hour = a_t.hour();
85 	m_minute = a_t.minute();
86 	m_second = a_t.second();
87 	m_resolution = a_t.resolution();
88 }
89 
90 /** Set the timestamp */
assign(const int a_year,const int a_month,const int a_day,const int a_hour,const int a_minute,const int a_second)91 void timestamp::assign(
92 	const int a_year,
93 	const int a_month,
94 	const int a_day,
95 	const int a_hour,
96 	const int a_minute,
97 	const int a_second
98 	)
99 {
100 	std::string es;
101 
102 	if ((a_year < 0) || (a_year > 9999)) {
103 		TRY_nomem(es = "Invalid year: \"");
104 		TRY_nomem(es += estring(a_year));
105 		TRY_nomem(es += "\"");
106 
107 		throw(ERROR(0,es));
108 	}
109 	m_year = a_year;
110 
111 	if ((a_month > 12) || (a_month < 1)) {
112 		TRY_nomem(es = "Invalid month: \"");
113 		TRY_nomem(es += estring(a_month));
114 		TRY_nomem(es += "\"");
115 
116 		throw(ERROR(0,es));
117 	}
118 	m_month = a_month;
119 
120 	if ((a_day > 31) || (a_day < 1)) {
121 		TRY_nomem(es = "Invalid day: \"");
122 		TRY_nomem(es += estring(a_day));
123 		TRY_nomem(es += "\"");
124 
125 		throw(ERROR(0,es));
126 	}
127 	m_day = a_day;
128 
129 	if ((a_hour < 0) || (a_hour > 23)) {
130 		TRY_nomem(es = "Invalid hour: \"");
131 		TRY_nomem(es += estring(a_hour));
132 		TRY_nomem(es += "\"");
133 
134 		throw(ERROR(0,es));
135 	}
136 	m_hour = a_hour;
137 
138 	if ((a_minute < 0) || (a_minute > 59)) {
139 		TRY_nomem(es = "Invalid minute: \"");
140 		TRY_nomem(es += estring(a_minute));
141 		TRY_nomem(es += "\"");
142 
143 		throw(ERROR(0,es));
144 	}
145 	m_minute = a_minute;
146 
147 	if ((a_second < 0) || (a_second > 59)) {
148 		TRY_nomem(es = "Invalid second: \"");
149 		TRY_nomem(es += estring(a_second));
150 		TRY_nomem(es += "\"");
151 
152 		throw(ERROR(0,es));
153 	}
154 	m_second = a_second;
155 }
156 
157 /** Set the timestamp from a string */
assign(const std::string & a_s)158 void timestamp::assign(const std::string& a_s)
159 {
160 	std::string bes;
161 	std::string es;
162 	std::string ies;
163 
164 	int l_year = -1;
165 	int l_month = -1;
166 	int l_day = -1;
167 	int l_hour = -1;
168 	int l_minute = -1;
169 	int l_second = -1;
170 	resolution_type r = resolution_day;
171 
172 	TRY_nomem(es = "Invalid timestamp string: \"");
173 	TRY_nomem(es += a_s);
174 	TRY_nomem(es += "\"");
175 
176 	if (!is_timestamp(a_s))
177 		throw(ERROR(0,es));
178 
179 	TRY_nomem(bes = "Parse error converting string to timestamp: \"");
180 	TRY_nomem(bes += a_s);
181 	TRY_nomem(bes += "\" ");
182 
183 	TRY_nomem(es = bes + "Invalid year");
184 	if (a_s.size() >= 4)
185 	{
186 		estring str;
187 
188 		r = resolution_year;
189 		TRY_nomem(str = a_s.substr(0,4));
190 		TRY(l_year = str,ies);
191 	}
192 	else
193 		throw(ERROR(0,es));
194 
195 	if (a_s.size() == 4) {
196 		assign(l_year,1,1,0,0,0);
197 		resolution(r);
198 		return;
199 	}
200 
201 	TRY_nomem(es = bes + "Invalid month");
202 	if (a_s.size() >= 7)
203 	{
204 		estring str;
205 
206 		r = resolution_month;
207 		TRY_nomem(str = a_s.substr(5,2));
208 		TRY(l_month = str,ies);
209 	}
210 	else
211 		throw(ERROR(0,es));
212 
213 	if (a_s.size() == 7) {
214 		assign(l_year,l_month,1,0,0,0);
215 		resolution(r);
216 		return;
217 	}
218 
219 	TRY_nomem(es = bes + "Invalid day");
220 	if (a_s.size() >= 10)
221 	{
222 		estring str;
223 
224 		r = resolution_day;
225 		TRY_nomem(str = a_s.substr(8,2));
226 		TRY(l_day = str,ies);
227 	}
228 	else
229 		throw(ERROR(0,es));
230 
231 	if (a_s.size() == 10) {
232 		assign(l_year,l_month,l_day,0,0,0);
233 		resolution(r);
234 		return;
235 	}
236 
237 	TRY_nomem(es = bes + "Invalid hour");
238 	if (a_s.size() >= 13)
239 	{
240 		estring str;
241 
242 		r = resolution_hour;
243 		TRY_nomem(str = a_s.substr(11,2));
244 		TRY(l_hour = str,ies);
245 	}
246 	else
247 		throw(ERROR(0,es));
248 
249 	if (a_s.size() == 13) {
250 		assign(l_year,l_month,l_day,l_hour,0,0);
251 		resolution(r);
252 		return;
253 	}
254 
255 	TRY_nomem(es = bes + "Invalid minute");
256 	if (a_s.size() >= 15)
257 	{
258 		estring str;
259 
260 		r = resolution_minute;
261 		TRY_nomem(str = a_s.substr(13,2));
262 		TRY(l_minute = str,ies);
263 	}
264 	else
265 		throw(ERROR(0,es));
266 
267 	if (a_s.size() == 15) {
268 		assign(l_year,l_month,l_day,l_hour,l_minute,0);
269 		resolution(r);
270 		return;
271 	}
272 
273 	TRY_nomem(es = bes + "Invalid second");
274 	if (a_s.size() == 17)
275 	{
276 		estring str;
277 
278 		r = resolution_second;
279 		TRY_nomem(str = a_s.substr(15,2));
280 		TRY(l_second = str,ies);
281 	}
282 	else
283 		throw(ERROR(0,es));
284 
285 	assign(l_year,l_month,l_day,l_hour,l_minute,l_second);
286 	resolution(r);
287 }
288 
289 /** Clear the timestamp */
clear(void)290 void timestamp::clear(void)
291 {
292 	m_year = 0;
293 	m_month = 0;
294 	m_day = 0;
295 	m_hour = 0;
296 	m_minute = 0;
297 	m_second = 0;
298 	m_resolution = resolution_day;
299 }
300 
301 /** Set the timestamp resolution */
resolution(timestamp::resolution_type a_r)302 void timestamp::resolution(timestamp::resolution_type a_r)
303 {
304 	m_resolution = a_r;
305 }
306 
307 /** Generate a string */
make_str_(const int a_resolution) const308 const std::string timestamp::make_str_(const int a_resolution) const
309 {
310 	std::string bes;
311 	std::string es;
312 	std::string str;
313 	estring tmp_str;
314 
315 	TRY_nomem(es = "Could not create timestamp string");
316 
317 	if (a_resolution >= resolution_year) {
318 		tmp_str.width(4);
319 		tmp_str.align(estring::right);
320 		tmp_str.left_fillchar('0');
321 		TRY_nomem(es = bes + ", error converting year");
322 		TRY(tmp_str = year(),es);
323 		TRY_nomem(str += tmp_str.fmt_str());
324 		tmp_str.reset();
325 	}
326 
327 	if (a_resolution >= resolution_month) {
328 		TRY_nomem(es = bes);
329 		TRY(str += "-",es);
330 		tmp_str.width(2);
331 		tmp_str.align(estring::right);
332 		tmp_str.left_fillchar('0');
333 		TRY_nomem(es = bes + ", error converting month");
334 		TRY(tmp_str = month(),es);
335 		TRY_nomem(str += tmp_str.fmt_str());
336 		tmp_str.reset();
337 	}
338 
339 	if (a_resolution >= resolution_day) {
340 		TRY_nomem(es = bes);
341 		TRY(str += "-",es);
342 		tmp_str.width(2);
343 		tmp_str.align(estring::right);
344 		tmp_str.left_fillchar('0');
345 		TRY_nomem(es = bes + ", error converting day");
346 		TRY(tmp_str = day(),es);
347 		TRY_nomem(str += tmp_str.fmt_str());
348 		tmp_str.reset();
349 	}
350 
351 	if (a_resolution >= resolution_hour) {
352 		TRY_nomem(es = bes);
353 		TRY(str += ".",es);
354 		tmp_str.width(2);
355 		tmp_str.align(estring::right);
356 		tmp_str.left_fillchar('0');
357 		TRY_nomem(es = bes + ", error converting hour");
358 		TRY(tmp_str = hour(),es);
359 		TRY_nomem(str += tmp_str.fmt_str());
360 		tmp_str.reset();
361 	}
362 
363 	if (a_resolution >= resolution_minute) {
364 		tmp_str.width(2);
365 		tmp_str.align(estring::right);
366 		tmp_str.left_fillchar('0');
367 		TRY_nomem(es = bes + ", error converting minute");
368 		TRY(tmp_str = minute(),es);
369 		TRY_nomem(str += tmp_str.fmt_str());
370 		tmp_str.reset();
371 	}
372 
373 	if (a_resolution >= resolution_second) {
374 		tmp_str.width(2);
375 		tmp_str.align(estring::right);
376 		tmp_str.left_fillchar('0');
377 		TRY_nomem(es = bes + ", error converting second");
378 		TRY(tmp_str = second(),es);
379 		TRY_nomem(str += tmp_str.fmt_str());
380 		tmp_str.reset();
381 	}
382 
383 	return(str);
384 }
385 
386 /** Generate a string */
str(void) const387 const std::string timestamp::str(void) const
388 {
389 	std::string str;
390 
391 	TRY_nomem(str = make_str_(m_resolution));
392 
393 	return(str);
394 }
395 
396 /** Generate a string */
str(const timestamp::resolution_type a_resolution) const397 const std::string timestamp::str(
398 	const timestamp::resolution_type a_resolution) const
399 {
400 	std::string str;
401 
402 	TRY_nomem(str = make_str_(a_resolution));
403 
404 	return(str);
405 }
406 
407 /** Return the timestamp second */
second(void) const408 int timestamp::second(void) const
409 {
410 	return(m_second);
411 }
412 
413 /** Return the timestamp minute */
minute(void) const414 int timestamp::minute(void) const
415 {
416 	return(m_minute);
417 }
418 
419 /** Return the timestamp hour */
hour(void) const420 int timestamp::hour(void) const
421 {
422 	return(m_hour);
423 }
424 
425 /** Return the timestamp day */
day(void) const426 int timestamp::day(void) const
427 {
428 	return(m_day);
429 }
430 
431 /** Return the timestamp month */
month(void) const432 int timestamp::month(void) const
433 {
434 	return(m_month);
435 }
436 
437 /** Return the timestamp year */
year(void) const438 int timestamp::year(void) const
439 {
440 	return(m_year);
441 }
442 
443 /** Return the timestamp resolution */
resolution(void) const444 timestamp::resolution_type timestamp::resolution(void) const
445 {
446 	return(m_resolution);
447 }
448 
449 /** Assignment */
operator =(const timestamp & a_t)450 timestamp& timestamp::operator = (const timestamp& a_t)
451 {
452 	assign(a_t);
453 
454 	return(*this);
455 }
456 
457 /** Assignment */
operator =(const std::string & a_s)458 timestamp& timestamp::operator = (const std::string& a_s)
459 {
460 	assign(a_s);
461 
462 	return(*this);
463 }
464 
465 /** Comparison */
operator <(const timestamp & a_t) const466 bool timestamp::operator < (const timestamp& a_t) const
467 {
468 	resolution_type r;
469 	bool value;
470 
471 	r = std::min(m_resolution, a_t.resolution());
472 	value = (str(r) < a_t.str(r));
473 
474 	return(value);
475 }
476 
477 /** Comparison */
operator >(const timestamp & a_t) const478 bool timestamp::operator > (const timestamp& a_t) const
479 {
480 	resolution_type r;
481 	bool value;
482 
483 	r = std::min(m_resolution, a_t.resolution());
484 	value = (str(r) > a_t.str(r));
485 
486 	return(value);
487 }
488 
489 /** Comparison */
operator ==(const timestamp & a_t) const490 bool timestamp::operator == (const timestamp& a_t) const
491 {
492 	resolution_type r;
493 	bool value;
494 
495 	r = std::min(m_resolution, a_t.resolution());
496 	value = (str(r) == a_t.str(r));
497 
498 	return(value);
499 }
500 
501 /** Return true if the string is a valid timestamp */
is_timestamp(const std::string & a_s)502 bool is_timestamp(const std::string& a_s)
503 {
504 	estring str;
505 	int i;
506 
507 	if (a_s.size() < 4) {
508 		return(false);
509 	}
510 	if (!isdigit(a_s[0])) {
511 		return(false);
512 	}
513 	if (!isdigit(a_s[1])) {
514 		return(false);
515 	}
516 	if (!isdigit(a_s[2])) {
517 		return(false);
518 	}
519 	if (!isdigit(a_s[3])) {
520 		return(false);
521 	}
522 	TRY_nomem(str = a_s.substr(0,4));
523 	try {
524 		i = str;
525 	}
526 	catch(...) {
527 		return(false);
528 	}
529 	if ((i < 0) || (i > 9999)) {
530 		return(false);
531 	}
532 	if (a_s.size() == 4) {
533 		return(true);
534 	}
535 
536 	if (a_s.size() < 7) {
537 		return(false);
538 	}
539 	if (a_s[4] != '-') {
540 		return(false);
541 	}
542 	if (!isdigit(a_s[5])) {
543 		return(false);
544 	}
545 	if (!isdigit(a_s[6])) {
546 		return(false);
547 	}
548 	TRY_nomem(str = a_s.substr(5,2));
549 	try {
550 		i = str;
551 	}
552 	catch(...) {
553 		return(false);
554 	}
555 	if ((i < 1) || (i > 12)) {
556 		return(false);
557 	}
558 	if (a_s.size() == 7) {
559 		return(true);
560 	}
561 
562 	if (a_s.size() < 10) {
563 		return(false);
564 	}
565 	if (a_s[7] != '-') {
566 		return(false);
567 	}
568 	if (!isdigit(a_s[8])) {
569 		return(false);
570 	}
571 	if (!isdigit(a_s[9])) {
572 		return(false);
573 	}
574 	TRY_nomem(str = a_s.substr(8,2));
575 	try {
576 		i = str;
577 	}
578 	catch(...) {
579 		return(false);
580 	}
581 	if ((i < 1) || (i > 31)) {
582 		return(false);
583 	}
584 	if (a_s.size() == 10) {
585 		return(true);
586 	}
587 
588 	if (a_s.size() < 13) {
589 		return(false);
590 	}
591 	if (a_s[10] != '.') {
592 		return(false);
593 	}
594 	if (!isdigit(a_s[11])) {
595 		return(false);
596 	}
597 	if (!isdigit(a_s[12])) {
598 		return(false);
599 	}
600 	TRY_nomem(str = a_s.substr(11,2));
601 	try {
602 		i = str;
603 	}
604 	catch(...) {
605 		return(false);
606 	}
607 	if ((i < 0) || (i > 23)) {
608 		return(false);
609 	}
610 	if (a_s.size() == 13) {
611 		return(true);
612 	}
613 
614 	if (a_s.size() < 15) {
615 		return(false);
616 	}
617 	if (!isdigit(a_s[13])) {
618 		return(false);
619 	}
620 	if (!isdigit(a_s[14])) {
621 		return(false);
622 	}
623 	TRY_nomem(str = a_s.substr(13,2));
624 	try {
625 		i = str;
626 	}
627 	catch(...) {
628 		return(false);
629 	}
630 	if ((i < 0) || (i > 59)) {
631 		return(false);
632 	}
633 	if (a_s.size() == 15) {
634 		return(true);
635 	}
636 
637 	if (a_s.size() < 17) {
638 		return(false);
639 	}
640 	if (!isdigit(a_s[15])) {
641 		return(false);
642 	}
643 	if (!isdigit(a_s[16])) {
644 		return(false);
645 	}
646 	TRY_nomem(str = a_s.substr(15,2));
647 	try {
648 		i = str;
649 	}
650 	catch(...) {
651 		return(false);
652 	}
653 	if ((i < 0) || (i > 59)) {
654 		return(false);
655 	}
656 	if (a_s.size() == 17) {
657 		return(true);
658 	}
659 
660 	return(false);
661 }
662 
663