1 /*
2 *
3 * Copyright (C) 2002, OFFIS
4 *
5 * This software and supporting documentation were developed by
6 *
7 * Kuratorium OFFIS e.V.
8 * Healthcare Information and Communication Systems
9 * Escherweg 2
10 * D-26121 Oldenburg, Germany
11 *
12 * THIS SOFTWARE IS MADE AVAILABLE, AS IS, AND OFFIS MAKES NO WARRANTY
13 * REGARDING THE SOFTWARE, ITS PERFORMANCE, ITS MERCHANTABILITY OR
14 * FITNESS FOR ANY PARTICULAR USE, FREEDOM FROM ANY COMPUTER DISEASES OR
15 * ITS CONFORMITY TO ANY SPECIFICATION. THE ENTIRE RISK AS TO QUALITY AND
16 * PERFORMANCE OF THE SOFTWARE IS WITH THE USER.
17 *
18 * Module: ofstd
19 *
20 * Author: Joerg Riesmeier
21 *
22 * Purpose: Class for time functions (Source)
23 *
24 */
25
26
27 #include "osconfig.h"
28
29 #define INCLUDE_CSTDIO
30 #define INCLUDE_CTIME
31 #include "ofstdinc.h"
32
33 BEGIN_EXTERN_C
34 #ifndef HAVE_WINDOWS_H
35 #ifdef HAVE_SYS_TIME_H
36 #include <sys/time.h> /* for struct timeval on Linux */
37 #endif
38
39 #ifndef HAVE_PROTOTYPE_GETTIMEOFDAY
40 /* Ultrix has gettimeofday() but no prototype in the header files */
41 int gettimeofday(struct timeval *tp, void *);
42 #endif
43 #endif
44 END_EXTERN_C
45
46 #ifdef HAVE_WINDOWS_H
47 #include <windows.h> /* for Windows time functions */
48 #endif
49
50 #include "oftime.h"
51 #include "ofstd.h"
52
53 /*------------------*
54 * implementation *
55 *------------------*/
56
OFTime()57 OFTime::OFTime()
58 : Hour(0),
59 Minute(0),
60 Second(0),
61 TimeZone(0)
62 {
63 }
64
65
OFTime(const OFTime & timeVal)66 OFTime::OFTime(const OFTime &timeVal)
67 : Hour(timeVal.Hour),
68 Minute(timeVal.Minute),
69 Second(timeVal.Second),
70 TimeZone(timeVal.TimeZone)
71 {
72 }
73
74
OFTime(const unsigned int hour,const unsigned int minute,const double second,const double timeZone)75 OFTime::OFTime(const unsigned int hour,
76 const unsigned int minute,
77 const double second,
78 const double timeZone)
79 : Hour(hour),
80 Minute(minute),
81 Second(second),
82 TimeZone(timeZone)
83 {
84 }
85
86
~OFTime()87 OFTime::~OFTime()
88 {
89 }
90
91
operator =(const OFTime & timeVal)92 OFTime &OFTime::operator=(const OFTime &timeVal)
93 {
94 Hour = timeVal.Hour;
95 Minute = timeVal.Minute;
96 Second = timeVal.Second;
97 TimeZone = timeVal.TimeZone;
98 return *this;
99 }
100
101
operator ==(const OFTime & timeVal)102 OFBool OFTime::operator==(const OFTime &timeVal)
103 {
104 return (getTimeInSeconds(OFTrue /*useTimeZone*/) == timeVal.getTimeInSeconds(OFTrue /*useTimeZone*/));
105 }
106
107
operator !=(const OFTime & timeVal)108 OFBool OFTime::operator!=(const OFTime &timeVal)
109 {
110 return (getTimeInSeconds(OFTrue /*useTimeZone*/) != timeVal.getTimeInSeconds(OFTrue /*useTimeZone*/));
111 }
112
113
operator <(const OFTime & timeVal)114 OFBool OFTime::operator<(const OFTime &timeVal)
115 {
116 return (getTimeInSeconds(OFTrue /*useTimeZone*/) < timeVal.getTimeInSeconds(OFTrue /*useTimeZone*/));
117 }
118
119
operator <=(const OFTime & timeVal)120 OFBool OFTime::operator<=(const OFTime &timeVal)
121 {
122 return (getTimeInSeconds(OFTrue /*useTimeZone*/) <= timeVal.getTimeInSeconds(OFTrue /*useTimeZone*/));
123 }
124
125
operator >=(const OFTime & timeVal)126 OFBool OFTime::operator>=(const OFTime &timeVal)
127 {
128 return (getTimeInSeconds(OFTrue /*useTimeZone*/) >= timeVal.getTimeInSeconds(OFTrue /*useTimeZone*/));
129 }
130
131
operator >(const OFTime & timeVal)132 OFBool OFTime::operator>(const OFTime &timeVal)
133 {
134 return (getTimeInSeconds(OFTrue /*useTimeZone*/) > timeVal.getTimeInSeconds(OFTrue /*useTimeZone*/));
135 }
136
137
clear()138 void OFTime::clear()
139 {
140 Hour = 0;
141 Minute = 0;
142 Second = 0;
143 TimeZone = 0;
144 }
145
146
isValid() const147 OFBool OFTime::isValid() const
148 {
149 /* check current time settings */
150 return isTimeValid(Hour, Minute, Second, TimeZone);
151 }
152
153
isTimeValid(const unsigned int hour,const unsigned int minute,const double second,const double timeZone)154 OFBool OFTime::isTimeValid(const unsigned int hour,
155 const unsigned int minute,
156 const double second,
157 const double timeZone)
158 {
159 /* check whether given time is valid */
160 return (hour < 24) && (minute < 60) && (second >= 0) && (second < 60) && (timeZone >= -12) && (timeZone <= 12);
161 }
162
163
setTime(const unsigned int hour,const unsigned int minute,const double second,const double timeZone)164 OFBool OFTime::setTime(const unsigned int hour,
165 const unsigned int minute,
166 const double second,
167 const double timeZone)
168 {
169 OFBool status = OFFalse;
170 /* only change if the new time is valid */
171 if (isTimeValid(hour, minute, second, timeZone))
172 {
173 Hour = hour;
174 Minute = minute;
175 Second = second;
176 TimeZone = timeZone;
177 /* report that a new time has been set */
178 status = OFTrue;
179 }
180 return status;
181 }
182
183
setHour(const unsigned int hour)184 OFBool OFTime::setHour(const unsigned int hour)
185 {
186 OFBool status = OFFalse;
187 /* only change the currently stored value if the new hour is valid */
188 if (isTimeValid(hour, Minute, Second, TimeZone))
189 {
190 Hour = hour;
191 /* report that a new hour has been set */
192 status = OFTrue;
193 }
194 return status;
195 }
196
197
setMinute(const unsigned int minute)198 OFBool OFTime::setMinute(const unsigned int minute)
199 {
200 OFBool status = OFFalse;
201 /* only change the currently stored value if the new minute is valid */
202 if (isTimeValid(Hour, minute, Second, TimeZone))
203 {
204 Minute = minute;
205 /* report that a new minute has been set */
206 status = OFTrue;
207 }
208 return status;
209 }
210
211
setSecond(const double second)212 OFBool OFTime::setSecond(const double second)
213 {
214 OFBool status = OFFalse;
215 /* only change the currently stored value if the new second is valid */
216 if (isTimeValid(Hour, Minute, second, TimeZone))
217 {
218 Second = second;
219 /* report that a new second has been set */
220 status = OFTrue;
221 }
222 return status;
223 }
224
225
setTimeZone(const double timeZone)226 OFBool OFTime::setTimeZone(const double timeZone)
227 {
228 OFBool status = OFFalse;
229 /* only change the currently stored value if the new time zone is valid */
230 if (isTimeValid(Hour, Minute, Second, timeZone))
231 {
232 TimeZone = timeZone;
233 /* report that a new time zone has been set */
234 status = OFTrue;
235 }
236 return status;
237 }
238
239
setTimeZone(const signed int hour,const unsigned int minute)240 OFBool OFTime::setTimeZone(const signed int hour,
241 const unsigned int minute)
242 {
243 /* convert hour and minute values to one time zone value */
244 const double timeZone = (hour < 0) ? (double)hour - (double)minute / 60 : (double)hour + (double)minute / 60;
245 /* only change the currently stored value if the new time zone is valid */
246 return setTimeZone(timeZone);
247 }
248
249
setTimeInSeconds(const double seconds,const double timeZone,const OFBool normalize)250 OFBool OFTime::setTimeInSeconds(const double seconds,
251 const double timeZone,
252 const OFBool normalize)
253 {
254 OFBool status = OFFalse;
255 /* only change if the new time is valid */
256 if (normalize || ((seconds >= 0) && (seconds < 86400)))
257 {
258 /* first normalize the value first to the valid range of [0.0,86400.0[ */
259 const double normalSeconds = (normalize) ? seconds + (signed long)(seconds / 86400) * 86400 : seconds;
260 /* compute time from given number of seconds since "00:00:00" */
261 const unsigned int newHour = (unsigned int)(normalSeconds / 3600);
262 const unsigned int newMinute = (unsigned int)((normalSeconds - (double)newHour * 3600) / 60);
263 const double newSecond = normalSeconds - (double)newHour * 3600 - (double)newMinute * 60;
264 status = setTime(newHour, newMinute, newSecond, timeZone);
265 }
266 return status;
267 }
268
269
setTimeInHours(const double hours,const double timeZone,const OFBool normalize)270 OFBool OFTime::setTimeInHours(const double hours,
271 const double timeZone,
272 const OFBool normalize)
273 {
274 OFBool status = OFFalse;
275 /* only change if the new time is valid */
276 if (normalize || ((hours >= 0) && (hours < 24)))
277 {
278 /* first normalize the value to the valid range of [0.0,24.0[ */
279 const double normalHours = (normalize) ? hours + (signed long)(hours / 24) * 24 : hours;
280 /* compute time from given number of hours since "00:00:00" */
281 const unsigned int newHour = (unsigned int)normalHours;
282 const unsigned int newMinute = (unsigned int)((normalHours - (double)newHour) * 60);
283 const double newSecond = (normalHours - (double)newHour) * 3600 - (double)newMinute * 60;
284 status = setTime(newHour, newMinute, newSecond, timeZone);
285 }
286 return status;
287 }
288
289
setCurrentTime()290 OFBool OFTime::setCurrentTime()
291 {
292 /* get the current system time and call the "real" function */
293 return setCurrentTime(time(NULL));
294 }
295
296
setCurrentTime(const time_t & tt)297 OFBool OFTime::setCurrentTime(const time_t &tt)
298 {
299 OFBool status = OFFalse;
300 #if defined(_REENTRANT) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__hpux)
301 // use localtime_r instead of localtime
302 struct tm ltBuf;
303 struct tm *lt = <Buf;
304 localtime_r(&tt, lt);
305 #else
306 struct tm *lt = localtime(&tt);
307 #endif
308 if (lt != NULL)
309 {
310 /* store retrieved time */
311 Hour = lt->tm_hour;
312 Minute = lt->tm_min;
313 Second = lt->tm_sec;
314 #if defined(_REENTRANT) && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(__hpux)
315 // use gmtime_r instead of gmtime
316 struct tm gtBuf;
317 struct tm *gt = >Buf;
318 gmtime_r(&tt, gt);
319 #else
320 // avoid overwriting of local time structure by calling gmtime()
321 struct tm ltBuf = *lt;
322 lt = <Buf;
323 struct tm *gt = gmtime(&tt);
324 #endif
325 if (gt != NULL)
326 {
327 /* retrieve and store the time zone */
328 TimeZone = (lt->tm_hour - gt->tm_hour) + (double)(lt->tm_min - gt->tm_min) / 60;
329 } else {
330 /* could not retrieve the time zone */
331 TimeZone = 0;
332 }
333 #ifdef HAVE_WINDOWS_H
334 /* Windows: no microseconds available, use milliseconds instead */
335 SYSTEMTIME timebuf;
336 GetSystemTime(&timebuf);
337 Second += (double)timebuf.wMilliseconds / 1000;
338 #else /* Unix */
339 struct timeval tv;
340 if (gettimeofday(&tv, NULL) == 0)
341 Second += (double)tv.tv_usec / 1000000;
342 #endif
343 /* report that current system time has been set */
344 status = OFTrue;
345 }
346 return status;
347 }
348
349
getHour() const350 unsigned int OFTime::getHour() const
351 {
352 return Hour;
353 }
354
355
getMinute() const356 unsigned int OFTime::getMinute() const
357 {
358 return Minute;
359 }
360
361
getSecond() const362 double OFTime::getSecond() const
363 {
364 return Second;
365 }
366
367
getIntSecond() const368 unsigned int OFTime::getIntSecond() const
369 {
370 /* return integral value of seconds */
371 return (unsigned int)Second;
372 }
373
374
getMilliSecond() const375 unsigned int OFTime::getMilliSecond() const
376 {
377 return (unsigned int)((Second - (unsigned int)Second) * 1000);
378 }
379
380
getMicroSecond() const381 unsigned int OFTime::getMicroSecond() const
382 {
383 return (unsigned int)((Second - (unsigned int)Second) * 1000000);
384 }
385
386
getTimeZone() const387 double OFTime::getTimeZone() const
388 {
389 return TimeZone;
390 }
391
392
getTimeInSeconds(const OFBool useTimeZone) const393 double OFTime::getTimeInSeconds(const OFBool useTimeZone) const
394 {
395 return getTimeInSeconds(Hour, Minute, Second, (useTimeZone) ? TimeZone : 0);
396 }
397
398
getTimeInHours(const OFBool useTimeZone) const399 double OFTime::getTimeInHours(const OFBool useTimeZone) const
400 {
401 return getTimeInHours(Hour, Minute, Second, (useTimeZone) ? TimeZone : 0);
402 }
403
404
getTimeInSeconds(const unsigned int hour,const unsigned int minute,const double second,const double timeZone,const OFBool normalize)405 double OFTime::getTimeInSeconds(const unsigned int hour,
406 const unsigned int minute,
407 const double second,
408 const double timeZone,
409 const OFBool normalize)
410 {
411 /* compute number of seconds since 00:00:00 */
412 double result = ((double)(hour - timeZone) * 60 + (double)minute) * 60 + second;
413 /* normalize the result to the range [0.0,86400.0[ */
414 if (normalize)
415 result -= (unsigned long)(result / 86400) * 86400;
416 return result;
417 }
418
419
getTimeInHours(const unsigned int hour,const unsigned int minute,const double second,const double timeZone,const OFBool normalize)420 double OFTime::getTimeInHours(const unsigned int hour,
421 const unsigned int minute,
422 const double second,
423 const double timeZone,
424 const OFBool normalize)
425 {
426 /* compute number of hours since 00:00:00 (incl. fraction of hours) */
427 double result = (double)hour - timeZone + ((double)minute + second / 60) / 60;
428 /* normalize the result to the range [0.0,24.0[ */
429 if (normalize)
430 result -= (unsigned long)(result / 24) * 24;
431 return result;
432 }
433
434
getCoordinatedUniversalTime() const435 OFTime OFTime::getCoordinatedUniversalTime() const
436 {
437 /* create a new time object */
438 OFTime timeVal;
439 /* convert time to UTC */
440 timeVal.setTimeInHours(getTimeInHours(OFTrue /*useTimeZone*/), 0 /*timeZone*/);
441 /* return by-value */
442 return timeVal;
443 }
444
445
getLocalTime() const446 OFTime OFTime::getLocalTime() const
447 {
448 /* create a new time object */
449 OFTime timeVal;
450 const double localTimeZone = getLocalTimeZone();
451 /* convert time to local time */
452 if (TimeZone != localTimeZone)
453 timeVal.setTimeInHours(getTimeInHours(OFTrue /*useTimeZone*/) + localTimeZone, localTimeZone);
454 else
455 {
456 /* same time zone, return currently stored time */
457 timeVal = *this;
458 }
459 /* return by-value */
460 return timeVal;
461 }
462
463
getISOFormattedTime(OFString & formattedTime,const OFBool showSeconds,const OFBool showFraction,const OFBool showTimeZone,const OFBool showDelimiter) const464 OFBool OFTime::getISOFormattedTime(OFString &formattedTime,
465 const OFBool showSeconds,
466 const OFBool showFraction,
467 const OFBool showTimeZone,
468 const OFBool showDelimiter) const
469 {
470 OFBool status = OFFalse;
471 /* check for valid time first */
472 if (isValid())
473 {
474 char buf[32];
475 /* format: HH:MM */
476 if (showDelimiter)
477 sprintf(buf, "%02u:%02u", Hour, Minute);
478 /* format: HHMM */
479 else
480 sprintf(buf, "%02u%02u", Hour, Minute);
481 if (showSeconds)
482 {
483 if (showFraction)
484 {
485 char buf2[12];
486 OFStandard::ftoa(buf2, sizeof(buf2), Second,
487 OFStandard::ftoa_format_f | OFStandard::ftoa_zeropad, 9, 6);
488
489 if (showDelimiter)
490 strcat(buf, ":"); /* format: HH:MM:SS.FFFFFF */
491 strcat(buf, buf2);
492 } else {
493 /* format: HH:MM:SS*/
494 if (showDelimiter)
495 sprintf(strchr(buf, 0), ":%02u", (unsigned int)Second);
496 /* format: HHMMSS */
497 else
498 sprintf(strchr(buf, 0), "%02u", (unsigned int)Second);
499 }
500 }
501 if (showTimeZone)
502 {
503 /* convert time zone from hours and fraction of hours to hours and minutes */
504 const char zoneSign = (TimeZone < 0) ? '-' : '+';
505 const double zoneAbs = (TimeZone < 0) ? -TimeZone : TimeZone;
506 const unsigned int zoneHour = (unsigned int)zoneAbs;
507 const unsigned int zoneMinute = (unsigned int)((zoneAbs - zoneHour) * 60);
508 /* format: ...+HH:MM or -HH:MM */
509 if (showDelimiter)
510 sprintf(strchr(buf, 0), "%c%02u:%02u", zoneSign, zoneHour, zoneMinute);
511 /* format: ...+HHMM or -HHMM */
512 else
513 sprintf(strchr(buf, 0), "%c%02u%02u", zoneSign, zoneHour, zoneMinute);
514 }
515 formattedTime = buf;
516 status = OFTrue;
517 }
518 return status;
519 }
520
521
getCurrentTime()522 OFTime OFTime::getCurrentTime()
523 {
524 /* create a time object with the current system time set */
525 OFTime timeVal;
526 /* this call might fail! */
527 timeVal.setCurrentTime();
528 /* return by-value */
529 return timeVal;
530 }
531
532
getLocalTimeZone()533 double OFTime::getLocalTimeZone()
534 {
535 double result = 0;
536 /* determine local time zone */
537 OFTime timeVal;
538 if (timeVal.setCurrentTime())
539 result = timeVal.getTimeZone();
540 return result;
541 }
542
543
operator <<(ostream & stream,const OFTime & timeVal)544 ostream& operator<<(ostream& stream, const OFTime &timeVal)
545 {
546 OFString string;
547 /* print the given time in ISO format to the stream */
548 if (timeVal.getISOFormattedTime(string))
549 stream << string;
550 return stream;
551 }
552