Coverage Report

Created: 2026-06-05 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dcmtk/ofstd/libsrc/oftime.cc
Line
Count
Source
1
/*
2
 *
3
 *  Copyright (C) 2002-2026, OFFIS e.V.
4
 *  All rights reserved.  See COPYRIGHT file for details.
5
 *
6
 *  This software and supporting documentation were developed by
7
 *
8
 *    OFFIS e.V.
9
 *    R&D Division Health
10
 *    Escherweg 2
11
 *    D-26121 Oldenburg, Germany
12
 *
13
 *
14
 *  Module:  ofstd
15
 *
16
 *  Author:  Joerg Riesmeier, Harald Roesen
17
 *
18
 *  Purpose: Class for time functions (Source)
19
 *
20
 */
21
22
23
#include "dcmtk/config/osconfig.h"
24
25
#include "dcmtk/ofstd/oftime.h"
26
#include "dcmtk/ofstd/ofstdinc.h"
27
#include "dcmtk/ofstd/ofstd.h"
28
#include "dcmtk/ofstd/oflimits.h"
29
#include "dcmtk/ofstd/ofmath.h"
30
31
#include <ctime>
32
#include <cmath>
33
34
BEGIN_EXTERN_C
35
#ifdef HAVE_SYS_TIME_H
36
#include <sys/time.h>     /* for struct timeval on Linux */
37
#endif
38
39
#ifndef HAVE_WINDOWS_H
40
#ifndef HAVE_PROTOTYPE_GETTIMEOFDAY
41
 /* Ultrix has gettimeofday() but no prototype in the header files */
42
 int gettimeofday(struct timeval *tp, void *);
43
#endif
44
#endif
45
END_EXTERN_C
46
47
#ifdef HAVE_WINDOWS_H
48
#define WIN32_LEAN_AND_MEAN
49
#include <windows.h>      /* for Windows time functions */
50
#endif
51
52
53
/*------------------------*
54
 *  constant definitions  *
55
 *------------------------*/
56
57
// use "Not a Number" (NaN) if available, an invalid value otherwise
58
#ifdef HAVE_CXX11
59
const double OFTime::unspecifiedSecond = OFnumeric_limits<double>::quiet_NaN();
60
const double OFTime::unspecifiedTimeZone = OFnumeric_limits<double>::quiet_NaN();
61
#else
62
const double OFTime::unspecifiedSecond = OFnumeric_limits<double>::max();
63
const double OFTime::unspecifiedTimeZone = OFnumeric_limits<double>::max();
64
#endif
65
66
67
/*------------------*
68
 *  implementation  *
69
 *------------------*/
70
71
OFTime::OFTime()
72
0
  : Hour(0),
73
0
    Minute(0),
74
0
    Second(unspecifiedSecond),
75
0
    TimeZone(unspecifiedTimeZone)
76
0
{
77
0
}
78
79
80
OFTime::OFTime(const OFTime &timeVal)
81
0
  : Hour(timeVal.Hour),
82
0
    Minute(timeVal.Minute),
83
0
    Second(timeVal.Second),
84
0
    TimeZone(timeVal.TimeZone)
85
0
{
86
0
}
87
88
89
OFTime::OFTime(const unsigned int hour,
90
               const unsigned int minute,
91
               const double second,
92
               const double timeZone)
93
0
  : Hour(hour),
94
0
    Minute(minute),
95
0
    Second(second),
96
0
    TimeZone(timeZone)
97
0
{
98
0
}
99
100
101
OFTime::~OFTime()
102
0
{
103
0
}
104
105
106
OFTime &OFTime::operator=(const OFTime &timeVal)
107
0
{
108
0
    Hour = timeVal.Hour;
109
0
    Minute = timeVal.Minute;
110
0
    Second = timeVal.Second;
111
0
    TimeZone = timeVal.TimeZone;
112
0
    return *this;
113
0
}
114
115
116
OFBool OFTime::operator==(const OFTime &timeVal) const
117
0
{
118
0
#ifndef __i386__
119
0
    return (getTimeInSeconds(OFTrue /*useTimeZone*/, OFFalse /*normalize*/) == timeVal.getTimeInSeconds(OFTrue /*useTimeZone*/, OFFalse /*normalize*/));
120
#else
121
    volatile double lhs = getTimeInSeconds(OFTrue /*useTimeZone*/, OFFalse /*normalize*/);
122
    volatile double rhs = timeVal.getTimeInSeconds(OFTrue /*useTimeZone*/, OFFalse /*normalize*/);
123
    return lhs == rhs;
124
#endif
125
0
}
126
127
128
OFBool OFTime::operator!=(const OFTime &timeVal) const
129
0
{
130
0
#ifndef __i386__
131
0
    return (getTimeInSeconds(OFTrue /*useTimeZone*/, OFFalse /*normalize*/) != timeVal.getTimeInSeconds(OFTrue /*useTimeZone*/, OFFalse /*normalize*/));
132
#else
133
    volatile double lhs = getTimeInSeconds(OFTrue /*useTimeZone*/, OFFalse /*normalize*/);
134
    volatile double rhs = timeVal.getTimeInSeconds(OFTrue /*useTimeZone*/, OFFalse /*normalize*/);
135
    return lhs != rhs;
136
#endif
137
0
}
138
139
140
OFBool OFTime::operator<(const OFTime &timeVal) const
141
0
{
142
0
#ifndef __i386__
143
0
    return (getTimeInSeconds(OFTrue /*useTimeZone*/, OFFalse /*normalize*/) < timeVal.getTimeInSeconds(OFTrue /*useTimeZone*/, OFFalse /*normalize*/));
144
#else
145
    volatile double lhs = getTimeInSeconds(OFTrue /*useTimeZone*/, OFFalse /*normalize*/);
146
    volatile double rhs = timeVal.getTimeInSeconds(OFTrue /*useTimeZone*/, OFFalse /*normalize*/);
147
    return lhs < rhs;
148
#endif
149
0
}
150
151
152
OFBool OFTime::operator<=(const OFTime &timeVal) const
153
0
{
154
0
#ifndef __i386__
155
0
    return (getTimeInSeconds(OFTrue /*useTimeZone*/, OFFalse /*normalize*/) <= timeVal.getTimeInSeconds(OFTrue /*useTimeZone*/, OFFalse /*normalize*/));
156
#else
157
    volatile double lhs = getTimeInSeconds(OFTrue /*useTimeZone*/, OFFalse /*normalize*/);
158
    volatile double rhs = timeVal.getTimeInSeconds(OFTrue /*useTimeZone*/, OFFalse /*normalize*/);
159
    return lhs <= rhs;
160
#endif
161
0
}
162
163
164
OFBool OFTime::operator>=(const OFTime &timeVal) const
165
0
{
166
0
#ifndef __i386__
167
0
    return (getTimeInSeconds(OFTrue /*useTimeZone*/, OFFalse /*normalize*/) >= timeVal.getTimeInSeconds(OFTrue /*useTimeZone*/, OFFalse /*normalize*/));
168
#else
169
    volatile double lhs = getTimeInSeconds(OFTrue /*useTimeZone*/, OFFalse /*normalize*/);
170
    volatile double rhs = timeVal.getTimeInSeconds(OFTrue /*useTimeZone*/, OFFalse /*normalize*/);
171
    return lhs >= rhs;
172
#endif
173
0
}
174
175
176
OFBool OFTime::operator>(const OFTime &timeVal) const
177
0
{
178
0
#ifndef __i386__
179
0
    return (getTimeInSeconds(OFTrue /*useTimeZone*/, OFFalse /*normalize*/) > timeVal.getTimeInSeconds(OFTrue /*useTimeZone*/, OFFalse /*normalize*/));
180
#else
181
    volatile double lhs = getTimeInSeconds(OFTrue /*useTimeZone*/, OFFalse /*normalize*/);
182
    volatile double rhs = timeVal.getTimeInSeconds(OFTrue /*useTimeZone*/, OFFalse /*normalize*/);
183
    return lhs > rhs;
184
#endif
185
0
}
186
187
188
void OFTime::clear()
189
0
{
190
0
    Hour = 0;
191
0
    Minute = 0;
192
0
    clearSecond();
193
0
    clearTimeZone();
194
0
}
195
196
197
void OFTime::clearSecond()
198
0
{
199
0
    Second = unspecifiedSecond;
200
0
}
201
202
203
void OFTime::clearTimeZone()
204
0
{
205
0
    TimeZone = unspecifiedTimeZone;
206
0
}
207
208
209
OFBool OFTime::isValid() const
210
0
{
211
    /* check current time settings */
212
0
    return isTimeValid(Hour, Minute, Second, TimeZone);
213
0
}
214
215
216
OFBool OFTime::hasSecond() const
217
0
{
218
0
    return isSecondSpecified(Second);
219
0
}
220
221
222
OFBool OFTime::hasFractionOfSecond() const
223
0
{
224
0
    return hasSecond() && (floor(Second) != Second);
225
0
}
226
227
228
OFBool OFTime::hasTimeZone() const
229
0
{
230
0
    return isTimeZoneSpecified(TimeZone);
231
0
}
232
233
234
OFBool OFTime::setTime(const unsigned int hour,
235
                       const unsigned int minute,
236
                       const double second,
237
                       const double timeZone)
238
0
{
239
0
    OFBool status = OFFalse;
240
    /* only change if the new time is valid */
241
0
    if (isTimeValid(hour, minute, second, timeZone))
242
0
    {
243
0
        Hour = hour;
244
0
        Minute = minute;
245
0
        Second = second;
246
0
        TimeZone = timeZone;
247
        /* report that a new time has been set */
248
0
        status = OFTrue;
249
0
    }
250
0
    return status;
251
0
}
252
253
254
OFBool OFTime::setHour(const unsigned int hour)
255
0
{
256
0
    OFBool status = OFFalse;
257
    /* only change the currently stored value if the new hour is valid */
258
0
    if (isTimeValid(hour, Minute, Second, TimeZone))
259
0
    {
260
0
        Hour = hour;
261
        /* report that a new hour has been set */
262
0
        status = OFTrue;
263
0
    }
264
0
    return status;
265
0
}
266
267
268
OFBool OFTime::setMinute(const unsigned int minute)
269
0
{
270
0
    OFBool status = OFFalse;
271
    /* only change the currently stored value if the new minute is valid */
272
0
    if (isTimeValid(Hour, minute, Second, TimeZone))
273
0
    {
274
0
        Minute = minute;
275
        /* report that a new minute has been set */
276
0
        status = OFTrue;
277
0
    }
278
0
    return status;
279
0
}
280
281
282
OFBool OFTime::setSecond(const double second)
283
0
{
284
0
    OFBool status = OFFalse;
285
    /* only change the currently stored value if the new second is valid */
286
0
    if (isTimeValid(Hour, Minute, second, TimeZone))
287
0
    {
288
0
        Second = second;
289
        /* report that a new second has been set */
290
0
        status = OFTrue;
291
0
    }
292
0
    return status;
293
0
}
294
295
296
OFBool OFTime::setTimeZone(const double timeZone)
297
0
{
298
0
    OFBool status = OFFalse;
299
    /* only change the currently stored value if the new time zone is valid */
300
0
    if (isTimeZoneValid(timeZone, OFFalse /*acceptUnspecified*/))
301
0
    {
302
0
        TimeZone = timeZone;
303
        /* report that a new time zone has been set */
304
0
        status = OFTrue;
305
0
    }
306
0
    return status;
307
0
}
308
309
310
OFBool OFTime::setTimeZone(const signed int hour,
311
                           const unsigned int minute)
312
0
{
313
    /* convert hour and minute values to one time zone value */
314
0
    const double timeZone = (hour < 0) ? OFstatic_cast(double, hour) - OFstatic_cast(double, minute) / 60 : OFstatic_cast(double, hour) + OFstatic_cast(double, minute) / 60;
315
    /* only change the currently stored value if the new time zone is valid */
316
0
    return setTimeZone(timeZone);
317
0
}
318
319
320
OFBool OFTime::setLocalTimeZone()
321
0
{
322
    /* set local time zone (if available) */
323
0
    return setTimeZone(getLocalTimeZone());
324
0
}
325
326
327
OFBool OFTime::setTimeInSeconds(const double seconds,
328
                                const double timeZone,
329
                                const OFBool normalize)
330
0
{
331
0
    OFBool status = OFFalse;
332
    /* only change if the new time is valid (leap second is not supported!) */
333
0
    if (normalize || ((seconds >= 0) && (seconds < 86400)))
334
0
    {
335
        /* first normalize the value first to the valid range of [0.0,86400.0[ */
336
0
        const double normalSeconds = (normalize) ? seconds - OFstatic_cast(double, OFstatic_cast(signed long, seconds / 86400) * 86400) : seconds;
337
        /* compute time from given number of seconds since "00:00:00" */
338
0
        const unsigned int newHour = OFstatic_cast(unsigned int, normalSeconds / 3600);
339
0
        const unsigned int newMinute = OFstatic_cast(unsigned int, (normalSeconds - OFstatic_cast(double, newHour) * 3600) / 60);
340
0
        const double newSecond = normalSeconds - OFstatic_cast(double, newHour) * 3600 - OFstatic_cast(double, newMinute) * 60;
341
0
        status = setTime(newHour, newMinute, newSecond, timeZone);
342
0
    }
343
0
    return status;
344
0
}
345
346
347
OFBool OFTime::setTimeInHours(const double hours,
348
                              const double timeZone,
349
                              const OFBool normalize)
350
0
{
351
0
    OFBool status = OFFalse;
352
    /* only change if the new time is valid */
353
0
    if (normalize || ((hours >= 0) && (hours < 24)))
354
0
    {
355
        /* first normalize the value to the valid range of [0.0,24.0[ */
356
0
        const double normalHours = (normalize) ? hours - OFstatic_cast(double, OFstatic_cast(signed long, hours / 24) * 24) : hours;
357
        /* compute time from given number of hours since "00:00:00" */
358
0
        const unsigned int newHour = OFstatic_cast(unsigned int, normalHours);
359
0
        const unsigned int newMinute = OFstatic_cast(unsigned int, (normalHours - OFstatic_cast(double, newHour)) * 60);
360
0
        const double newSecond = (normalHours - OFstatic_cast(double, newHour)) * 3600 - OFstatic_cast(double, newMinute) * 60;
361
0
        status = setTime(newHour, newMinute, newSecond, timeZone);
362
0
    }
363
0
    return status;
364
0
}
365
366
367
OFBool OFTime::setCurrentTime()
368
0
{
369
    /* get the current system time and call the "real" function */
370
0
    return setCurrentTime(time(NULL));
371
0
}
372
373
374
OFBool OFTime::setCurrentTime(const time_t &tt)
375
0
{
376
0
    OFBool status = OFFalse;
377
0
#ifdef HAVE_LOCALTIME_R
378
    /* use localtime_r instead of localtime */
379
0
    struct tm ltBuf;
380
0
    struct tm *lt = &ltBuf;
381
0
    localtime_r(&tt, lt);
382
#else
383
    struct tm *lt = localtime(&tt);
384
#endif
385
0
    if (lt != NULL)
386
0
    {
387
        /* store retrieved time */
388
0
        Hour = lt->tm_hour;
389
0
        Minute = lt->tm_min;
390
0
        Second = lt->tm_sec;
391
0
#ifdef HAVE_GMTIME_R
392
        /* use gmtime_r instead of gmtime */
393
0
        struct tm gtBuf;
394
0
        struct tm *gt = &gtBuf;
395
0
        gmtime_r(&tt, gt);
396
#else
397
        /* avoid overwriting of local time structure by calling gmtime() */
398
        struct tm ltBuf = *lt;
399
        lt = &ltBuf;
400
        struct tm *gt = gmtime(&tt);
401
#endif
402
0
        if (gt != NULL)
403
0
        {
404
            /* retrieve and store the time zone */
405
0
            TimeZone = (lt->tm_hour - gt->tm_hour) + OFstatic_cast(double, lt->tm_min - gt->tm_min) / 60;
406
            /* correct for "day overflow" */
407
0
            if (TimeZone < -12)
408
0
                TimeZone += 24;
409
0
            else if (TimeZone > 12)   // cannot detect time zones in the range ]+12.0,+14.0]
410
0
                TimeZone -= 24;
411
0
        } else {
412
            /* could not retrieve the time zone */
413
0
            TimeZone = unspecifiedTimeZone;
414
0
        }
415
#ifdef HAVE_WINDOWS_H
416
        /* Windows: no microseconds available, use milliseconds instead */
417
        SYSTEMTIME timebuf;
418
        GetSystemTime(&timebuf);
419
        Second += OFstatic_cast(double, timebuf.wMilliseconds) / 1000;
420
#else /* Unix */
421
0
        struct timeval tv;
422
0
        if (gettimeofday(&tv, NULL) == 0)
423
0
            Second += OFstatic_cast(double, tv.tv_usec) / 1000000;
424
0
#endif
425
        /* report that current system time has been set */
426
0
        status = OFTrue;
427
0
    }
428
0
    return status;
429
0
}
430
431
432
OFBool OFTime::setISOFormattedTime(const OFString &formattedTime)
433
0
{
434
0
    const size_t length = formattedTime.length();
435
0
    if (length < 3) {
436
        /* not enough input to scan */
437
0
        return OFFalse;
438
0
    }
439
440
0
    size_t pos = 0;
441
0
    const char delim = formattedTime.at(pos + 2);
442
0
    const OFBool delimsUsed = !isdigit(OFstatic_cast(unsigned char, delim));
443
444
0
    unsigned int hours = 0;
445
0
    unsigned int minutes = 0;
446
0
    double seconds = OFTime::unspecifiedSecond;
447
0
    double timeZone = OFTime::unspecifiedTimeZone;
448
449
0
    {
450
        /* scan for HHMM or HH:MM - hours and minutes */
451
0
        OFString hhmmFormat("%2u");
452
0
        if (delimsUsed)
453
0
        {
454
0
            hhmmFormat += delim;
455
0
        }
456
0
        hhmmFormat += "%2u%n";
457
458
0
        const int nCharactersExpected = (delimsUsed ? 5 : 4);
459
0
        int nCharactersRead = 0;
460
0
        const int nReceivedArgs = sscanf(formattedTime.c_str() + pos, hhmmFormat.c_str(), &hours, &minutes, &nCharactersRead);
461
0
        if ((nReceivedArgs == 2) && (nCharactersRead == nCharactersExpected))
462
0
        {
463
0
            pos += nCharactersRead;
464
0
        }
465
0
        else
466
0
        {
467
            /* found no valid HH[:]MM 'pattern' */
468
0
            return OFFalse;
469
0
        }
470
0
    }
471
472
    /* is there still input available that starts with a digit or a delimiter (if used)? */
473
0
    if ((pos < length) && (isdigit(OFstatic_cast(unsigned char, formattedTime.at(pos))) || (delimsUsed && (formattedTime.at(pos) == delim))))
474
0
    {
475
        /* scan for SS or :SS - seconds */
476
0
        OFString ssFormat;
477
0
        if (delimsUsed)
478
0
        {
479
0
            ssFormat += delim;
480
0
        }
481
0
        ssFormat += "%2u%n";
482
483
0
        unsigned int secondsInt = 0;
484
0
        const int nCharactersExpected = (delimsUsed ? 3 : 2);
485
0
        int nCharactersRead = 0;
486
0
        const int nReceivedArgs = sscanf(formattedTime.c_str() + pos, ssFormat.c_str(), &secondsInt, &nCharactersRead);
487
0
        if ((nReceivedArgs == 1) && (nCharactersRead == nCharactersExpected))
488
0
        {
489
0
            pos += nCharactersRead;
490
0
            seconds = secondsInt;
491
0
        }
492
0
        else
493
0
        {
494
            /* found no valid [:]SS 'pattern' */
495
0
            return OFFalse;
496
0
        }
497
0
    }
498
499
    /* if seconds are used, is there still input available that starts with a dot ('.') character? */
500
0
    if (isSecondSpecified(seconds) && (pos < length) && (formattedTime.at(pos) == '.'))
501
0
    {
502
        /* scan for .FFFFFF - fractional seconds */
503
0
        char buffer[8] = {'\0'};
504
0
        buffer[0] = '.';
505
0
        ++pos; /* overread the dot ('.') character at front */
506
0
        int nCharactersRead = 0;
507
0
        const int nReceivedArgs = sscanf(formattedTime.c_str() + pos, "%6[0123456789]%n", (buffer + 1), &nCharactersRead);
508
0
        OFBool fsSuccess = OFFalse;
509
0
        const double fractionalSeconds = OFStandard::atof(buffer, &fsSuccess);
510
0
        if ((nReceivedArgs == 1) && fsSuccess)
511
0
        {
512
0
            pos += nCharactersRead;
513
0
            seconds += fractionalSeconds;
514
0
        }
515
0
        else
516
0
        {
517
            /* found no valid .FFFFFF 'pattern' */
518
0
            return OFFalse;
519
0
        }
520
0
    }
521
522
    /* skip whitespaces in case delimiter character has been used */
523
0
    if ((pos < length) && delimsUsed)
524
0
    {
525
0
        const OFBool hasSpaceBeenSkipped = isspace(formattedTime.at(pos));
526
0
        while ((pos < length) && isspace(formattedTime.at(pos)))
527
0
        {
528
0
           ++pos;
529
0
        }
530
0
        if ((pos == length) && hasSpaceBeenSkipped)
531
0
        {
532
          /* we have skipped trailing spaces but reached end of input,
533
           * this means that the input is/was malformed in the first place
534
           */
535
0
          return OFFalse;
536
0
        }
537
0
    }
538
539
    /* is there still input available that also starts with a plus ('+') or minus ('-') character?
540
     */
541
0
    if ((pos < length) && ((formattedTime.at(pos) == '+') || (formattedTime.at(pos) == '-')))
542
0
    {
543
        /* scan for &ZZZZ or &ZZ:ZZ - time zone */
544
0
        OFString tzFormat("%3d");
545
0
        if (delimsUsed)
546
0
        {
547
0
            tzFormat += delim;
548
0
        }
549
0
        tzFormat += "%2u%n";
550
551
0
        int tzHours;
552
0
        unsigned int tzMinutes;
553
0
        int nCharactersRead = 0;
554
0
        const int nReceivedArgs = sscanf(formattedTime.c_str() + pos, tzFormat.c_str(), &tzHours, &tzMinutes, &nCharactersRead);
555
0
        if (nReceivedArgs == 2)
556
0
        {
557
0
            timeZone = (tzHours < 0) ? tzHours - OFstatic_cast(double, tzMinutes) / 60
558
0
                                     : tzHours + OFstatic_cast(double, tzMinutes) / 60;
559
0
            pos += nCharactersRead;
560
0
        }
561
0
        else
562
0
        {
563
            /* found no valid &ZZ[:]ZZ 'pattern' */
564
0
            return OFFalse;
565
0
        }
566
0
    }
567
568
    /* is there still input available? */
569
0
    if (pos < length)
570
0
    {
571
        /* too much input */
572
0
        return OFFalse;
573
0
    }
574
575
    /* all 'eaten up' */
576
0
    return setTime(hours, minutes, seconds, timeZone);
577
0
}
578
579
580
OFBool OFTime::setISOFormattedTimeZone(const OFString &formattedTimeZone)
581
0
{
582
0
    OFBool status = OFFalse;
583
0
    const size_t length = formattedTimeZone.length();
584
0
    const OFBool hasDelimiter = (formattedTimeZone.find_first_not_of("0123456789", 1) != OFString_npos);
585
    /* format: +HHMM or -HHMM */
586
0
    if ((length == 5) && ((formattedTimeZone[0] == '+') || (formattedTimeZone[0] == '-')))
587
0
    {
588
0
        int tzHours;
589
0
        unsigned int tzMinutes;
590
        /* extract "HH", "MM" from time zone string */
591
0
        if (sscanf(formattedTimeZone.c_str(), "%03d%02u", &tzHours, &tzMinutes) == 2)
592
0
            status = setTimeZone(tzHours, tzMinutes);
593
0
    }
594
    /* format: +HH:MM or -HH:MM */
595
0
    else if ((length == 6) && hasDelimiter && ((formattedTimeZone[0] == '+') || (formattedTimeZone[0] == '-')))
596
0
    {
597
0
       int tzHours;
598
0
       unsigned int tzMinutes;
599
       /* ignore the delimiter "%c" */
600
0
       if (sscanf(formattedTimeZone.c_str(), "%03d%*c%02u", &tzHours, &tzMinutes) == 2)
601
0
          status = setTimeZone(tzHours, tzMinutes);
602
0
    }
603
    /* empty value */
604
0
    else if (length == 0)
605
0
    {
606
0
        TimeZone = unspecifiedTimeZone;
607
0
        status = OFTrue;
608
0
    }
609
0
    return status;
610
0
}
611
612
613
unsigned int OFTime::getHour() const
614
0
{
615
0
    return Hour;
616
0
}
617
618
619
unsigned int OFTime::getMinute() const
620
0
{
621
0
    return Minute;
622
0
}
623
624
625
double OFTime::getSecond() const
626
0
{
627
0
    return Second;
628
0
}
629
630
631
unsigned int OFTime::getIntSecond() const
632
0
{
633
    /* return integral value of seconds */
634
0
    return (hasSecond() ? OFstatic_cast(unsigned int, Second) : 0);
635
0
}
636
637
638
unsigned int OFTime::getMilliSecond() const
639
0
{
640
0
    return (hasSecond() ? OFstatic_cast(unsigned int, (Second - OFstatic_cast(unsigned int, Second)) * 1000) : 0);
641
0
}
642
643
644
unsigned int OFTime::getMicroSecond() const
645
0
{
646
0
    return (hasSecond() ? OFstatic_cast(unsigned int, (Second - OFstatic_cast(unsigned int, Second)) * 1000000) : 0);
647
0
}
648
649
650
double OFTime::getTimeZone() const
651
0
{
652
    // tbc: check for valid value?
653
0
    return TimeZone;
654
0
}
655
656
657
double OFTime::getTimeInSeconds(const OFBool useTimeZone,
658
                                const OFBool normalize) const
659
0
{
660
0
    return getTimeInSeconds(Hour, Minute, Second, (useTimeZone) ? TimeZone : unspecifiedTimeZone, normalize);
661
0
}
662
663
664
double OFTime::getTimeInHours(const OFBool useTimeZone,
665
                              const OFBool normalize) const
666
0
{
667
0
    return getTimeInHours(Hour, Minute, Second, (useTimeZone) ? TimeZone : unspecifiedTimeZone, normalize);
668
0
}
669
670
671
double OFTime::getTimeInSeconds(const unsigned int hour,
672
                                const unsigned int minute,
673
                                const double second,
674
                                const double timeZone,
675
                                const OFBool normalize)
676
0
{
677
0
    const double secondValue = isSecondSpecified(second) ? second : 0;
678
0
    const double timeZoneOffset = isTimeZoneSpecified(timeZone) ? timeZone : 0;
679
    /* compute number of seconds since 00:00:00 */
680
0
    double result = ((OFstatic_cast(double, hour) - timeZoneOffset) * 60 + OFstatic_cast(double, minute)) * 60 + secondValue;
681
    /* normalize the result to the range [0.0,86400.0[ */
682
0
    if (normalize)
683
0
        result -= OFstatic_cast(double, OFstatic_cast(unsigned long, result / 86400) * 86400);
684
0
    return result;
685
0
}
686
687
688
double OFTime::getTimeInHours(const unsigned int hour,
689
                              const unsigned int minute,
690
                              const double second,
691
                              const double timeZone,
692
                              const OFBool normalize)
693
0
{
694
0
    const double secondValue = isSecondSpecified(second) ? second : 0;
695
0
    const double timeZoneOffset = isTimeZoneSpecified(timeZone) ? timeZone : 0;
696
    /* compute number of hours since 00:00:00 (incl. fraction of hours) */
697
0
    double result = OFstatic_cast(double, hour) - timeZoneOffset + (OFstatic_cast(double, minute) + secondValue / 60) / 60;
698
    /* normalize the result to the range [0.0,24.0[ */
699
0
    if (normalize)
700
0
        result -= OFstatic_cast(double, OFstatic_cast(unsigned long, result / 24) * 24);
701
0
    return result;
702
0
}
703
704
705
OFTime OFTime::getCoordinatedUniversalTime() const
706
0
{
707
    /* create a new time object */
708
0
    OFTime timeVal;
709
    /* convert time to UTC */
710
0
    timeVal.setTimeInHours(getTimeInHours(OFTrue /*useTimeZone*/), 0 /*timeZone*/);
711
    /* return by-value */
712
0
    return timeVal;
713
0
}
714
715
716
OFTime OFTime::getLocalTime() const
717
0
{
718
    /* create a new time object */
719
0
    OFTime timeVal;
720
0
    const double localTimeZone = getLocalTimeZone();
721
    /* convert time to local time */
722
0
    if (TimeZone != localTimeZone)
723
0
        timeVal.setTimeInHours(getTimeInHours(OFTrue /*useTimeZone*/) + localTimeZone, localTimeZone);
724
0
    else
725
0
    {
726
        /* same time zone, return currently stored time */
727
0
        timeVal = *this;
728
0
    }
729
    /* return by-value */
730
0
    return timeVal;
731
0
}
732
733
734
OFBool OFTime::getISOFormattedTime(OFString &formattedTime,
735
                                   const OFBool showSeconds,
736
                                   const OFBool showFraction,
737
                                   const OFBool showTimeZone,
738
                                   const OFBool showDelimiter,
739
                                   const OFBool createMissingPart,
740
                                   const OFString &timeZoneSeparator) const
741
0
{
742
0
    OFBool status = OFFalse;
743
    /* check for valid time first */
744
0
    if (isValid())
745
0
    {
746
0
        char buf[32];
747
        /* format: HH:MM */
748
0
        if (showDelimiter)
749
0
            OFStandard::snprintf(buf, sizeof(buf), "%02u:%02u", Hour, Minute);
750
        /* format: HHMM */
751
0
        else
752
0
            OFStandard::snprintf(buf, sizeof(buf), "%02u%02u", Hour, Minute);
753
        /* only show seconds if requested and a value is specified (or should be created) */
754
0
        if (showSeconds && (hasSecond() || createMissingPart))
755
0
        {
756
0
            const double secondValue = isSecondSpecified(Second) ? Second : 0;
757
            /* only show fractional part of a second if requested and a value is specified (or should be created) */
758
0
            if (showFraction && (hasFractionOfSecond() || createMissingPart))
759
0
            {
760
0
                char buf2[12];
761
0
                OFStandard::ftoa(buf2, sizeof(buf2), secondValue, OFStandard::ftoa_format_f | OFStandard::ftoa_zeropad, 9, 6);
762
                /* format: HH:MM:SS.FFFFFF */
763
0
                if (showDelimiter)
764
0
                    OFStandard::strlcat(buf, ":", sizeof(buf));
765
0
                OFStandard::strlcat(buf, buf2, sizeof(buf));
766
0
            } else {
767
0
                char buf2[12];
768
                /* format: HH:MM:SS */
769
0
                if (showDelimiter)
770
0
                    OFStandard::snprintf(buf2, sizeof(buf2), ":%02u", OFstatic_cast(unsigned int, secondValue));
771
                /* format: HHMMSS */
772
0
                else
773
0
                    OFStandard::snprintf(buf2, sizeof(buf2), "%02u", OFstatic_cast(unsigned int, secondValue));
774
0
                OFStandard::strlcat(buf, buf2, sizeof(buf));
775
0
            }
776
0
        }
777
        /* copy converted part so far to the result variable */
778
0
        formattedTime.assign(buf);
779
        /* only add the time zone if requested _and_ a value is specified */
780
0
        if (showTimeZone)
781
0
        {
782
0
            OFString formattedTimeZone;
783
0
            if (getISOFormattedTimeZone(formattedTimeZone, showDelimiter))
784
0
            {
785
0
                if (!formattedTimeZone.empty())
786
0
                {
787
0
                    if (showDelimiter)
788
0
                        formattedTime += timeZoneSeparator;
789
                    /* append time zone part to the result variable */
790
0
                    formattedTime += formattedTimeZone;
791
0
                }
792
0
            }
793
0
        }
794
0
        status = OFTrue;
795
0
    }
796
0
    return status;
797
0
}
798
799
800
OFBool OFTime::getISOFormattedTimeZone(OFString &formattedTimeZone,
801
                                       const OFBool showDelimiter) const
802
0
{
803
0
    OFBool status = OFFalse;
804
    /* first, check for valid time zone (either specified or unspecified) */
805
0
    if (isTimeZoneValid(TimeZone, OFTrue /*acceptUnspecified*/))
806
0
    {
807
        /* check whether time zone is specified */
808
0
        if (isTimeZoneSpecified(TimeZone))
809
0
        {
810
0
            char buf[32];
811
            /* convert time zone from hours and fraction of hours to hours and minutes */
812
0
            const char tzSign = (TimeZone < 0) ? '-' : '+';
813
0
            const double tzAbs = (TimeZone < 0) ? -TimeZone : TimeZone;
814
0
            const unsigned int tzHours = OFstatic_cast(unsigned int, tzAbs);
815
0
            const unsigned int tzMinutes = OFstatic_cast(unsigned int, (tzAbs - tzHours) * 60);
816
            /* format: +HH:MM or -HH:MM */
817
0
            if (showDelimiter)
818
0
                OFStandard::snprintf(buf, sizeof(buf), "%c%02u:%02u", tzSign, tzHours, tzMinutes);
819
            /* format: +HHMM or -HHMM */
820
0
            else
821
0
                OFStandard::snprintf(buf, sizeof(buf), "%c%02u%02u", tzSign, tzHours, tzMinutes);
822
            /* assign value to the result variable */
823
0
            formattedTimeZone.assign(buf);
824
0
        } else {
825
            /* clear result variable if time zone is unspecified */
826
0
            formattedTimeZone.clear();
827
0
        }
828
0
        status = OFTrue;
829
0
    }
830
0
    return status;
831
0
}
832
833
834
// -- static helper functions --
835
836
OFTime OFTime::getCurrentTime()
837
0
{
838
    /* create a time object with the current system time set */
839
0
    OFTime timeVal;
840
    /* this call might fail! */
841
0
    timeVal.setCurrentTime();
842
    /* return by-value */
843
0
    return timeVal;
844
0
}
845
846
847
double OFTime::getLocalTimeZone()
848
0
{
849
0
    double result = unspecifiedTimeZone;
850
    /* determine local time zone */
851
0
    OFTime timeVal;
852
0
    if (timeVal.setCurrentTime())
853
0
        result = timeVal.getTimeZone();
854
0
    return result;
855
0
}
856
857
858
OFBool OFTime::isTimeValid(const unsigned int hour,
859
                           const unsigned int minute,
860
                           const double second,
861
                           const double timeZone)
862
0
{
863
    /* check whether given time is valid (also support leap second) */
864
0
    return (hour < 24) && (minute < 60) && (!isSecondSpecified(second) || ((second >= 0) &&  (second <= 60))) &&
865
0
        isTimeZoneValid(timeZone, OFTrue /*acceptUnspecified*/);
866
0
}
867
868
869
OFBool OFTime::isSecondSpecified(const double second)
870
0
{
871
0
#ifdef HAVE_CXX11
872
0
    return !(OFMath::isnan)(second);
873
#else
874
    return (second != unspecifiedSecond);
875
#endif
876
0
}
877
878
879
OFBool OFTime::isTimeZoneValid(const double timeZone,
880
                               const OFBool acceptUnspecified)
881
0
{
882
0
    const OFBool timeZoneSpecified = isTimeZoneSpecified(timeZone);
883
    /* check whether given time zone is unspecified and/or within the valid range */
884
0
    return (acceptUnspecified && !timeZoneSpecified) || (timeZoneSpecified && (timeZone >= -12) && (timeZone <= 14));
885
0
}
886
887
888
OFBool OFTime::isTimeZoneSpecified(const double timeZone)
889
0
{
890
0
#ifdef HAVE_CXX11
891
0
    return !(OFMath::isnan)(timeZone);
892
#else
893
    return (timeZone != unspecifiedTimeZone);
894
#endif
895
0
}
896
897
898
// -- output operator --
899
900
STD_NAMESPACE ostream &operator<<(STD_NAMESPACE ostream &stream,
901
                                  const OFTime &timeVal)
902
0
{
903
0
    OFString tmpString;
904
    /* print the given time in ISO format to the stream */
905
0
    if (timeVal.getISOFormattedTime(tmpString, OFTrue /*showSeconds*/, OFTrue /*showFraction*/, OFTrue /*showTimeZone*/))
906
0
        stream << tmpString;
907
0
    return stream;
908
0
}