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 = &ltBuf;
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 = &gtBuf;
318         gmtime_r(&tt, gt);
319 #else
320         // avoid overwriting of local time structure by calling gmtime()
321         struct tm ltBuf = *lt;
322         lt = &ltBuf;
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