Coverage Report

Created: 2026-09-28 07:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/dcmtk/ofstd/libsrc/ofdatime.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 date and time functions (Source)
19
 *
20
 */
21
22
23
#include "dcmtk/config/osconfig.h"
24
25
BEGIN_EXTERN_C
26
#include <sys/types.h>    /* for struct time_t */
27
END_EXTERN_C
28
29
#include "dcmtk/ofstd/ofdatime.h"
30
#include "dcmtk/ofstd/ofstdinc.h"
31
#include <ctime>
32
33
34
/*------------------*
35
 *  implementation  *
36
 *------------------*/
37
38
OFDateTime::OFDateTime()
39
0
  : Date(),
40
0
    Time()
41
0
{
42
0
}
43
44
45
OFDateTime::OFDateTime(const OFDateTime &dateTime)
46
0
  : Date(dateTime.Date),
47
0
    Time(dateTime.Time)
48
0
{
49
0
}
50
51
52
OFDateTime::OFDateTime(const OFDate &dateVal,
53
                       const OFTime &timeVal)
54
0
  : Date(dateVal),
55
0
    Time(timeVal)
56
0
{
57
0
}
58
59
60
OFDateTime::OFDateTime(const unsigned int year,
61
                       const unsigned int month,
62
                       const unsigned int day,
63
                       const unsigned int hour,
64
                       const unsigned int minute,
65
                       const double second,
66
                       const double timeZone)
67
0
  : Date(year, month, day),
68
0
    Time(hour, minute, second, timeZone)
69
0
{
70
0
}
71
72
73
OFDateTime::~OFDateTime()
74
0
{
75
0
}
76
77
78
OFDateTime &OFDateTime::operator=(const OFDateTime &dateTime)
79
0
{
80
0
    Date = dateTime.Date;
81
0
    Time = dateTime.Time;
82
0
    return *this;
83
0
}
84
85
86
OFBool OFDateTime::operator==(const OFDateTime &dateTime) const
87
0
{
88
    /* note that the "overflow" from one day to another is currently not handled */
89
0
    return (Date == dateTime.Date) && (Time == dateTime.Time);
90
0
}
91
92
93
OFBool OFDateTime::operator!=(const OFDateTime &dateTime) const
94
0
{
95
    /* note that the "overflow" from one day to another is currently not handled */
96
0
    return (Date != dateTime.Date) || (Time != dateTime.Time);
97
0
}
98
99
100
OFBool OFDateTime::operator<(const OFDateTime &dateTime) const
101
0
{
102
    /* note that the "overflow" from one day to another is currently not handled */
103
0
    return (Date < dateTime.Date) || ((Date == dateTime.Date) && (Time < dateTime.Time));
104
0
}
105
106
107
OFBool OFDateTime::operator<=(const OFDateTime &dateTime) const
108
0
{
109
    /* note that the "overflow" from one day to another is currently not handled */
110
0
    return (Date < dateTime.Date) || ((Date == dateTime.Date) && (Time <= dateTime.Time));
111
0
}
112
113
114
OFBool OFDateTime::operator>(const OFDateTime &dateTime) const
115
0
{
116
0
    return (dateTime < *this);
117
0
}
118
119
120
OFBool OFDateTime::operator>=(const OFDateTime &dateTime) const
121
0
{
122
0
    return (dateTime <= *this);
123
0
}
124
125
126
void OFDateTime::clear()
127
0
{
128
0
    Date.clear();
129
0
    Time.clear();
130
0
}
131
132
133
OFBool OFDateTime::isValid() const
134
0
{
135
    /* check current date settings */
136
0
    return Date.isValid() && Time.isValid();
137
0
}
138
139
140
OFBool OFDateTime::setDateTime(const unsigned int year,
141
                               const unsigned int month,
142
                               const unsigned int day,
143
                               const unsigned int hour,
144
                               const unsigned int minute,
145
                               const double second,
146
                               const double timeZone)
147
0
{
148
0
    OFBool result = OFFalse;
149
    /* check whether new date and time are valid */
150
0
    if (OFDate::isDateValid(year, month, day) && OFTime::isTimeValid(hour, minute, second, timeZone))
151
0
        result = Date.setDate(year, month, day) && Time.setTime(hour, minute, second, timeZone);
152
0
    return result;
153
0
}
154
155
156
OFBool OFDateTime::setDate(const OFDate &dateVal)
157
0
{
158
0
    OFBool result = OFFalse;
159
    /* check whether new date is valid */
160
0
    if (dateVal.isValid())
161
0
    {
162
0
        Date = dateVal;
163
0
        result = OFTrue;
164
0
    }
165
0
    return result;
166
0
}
167
168
169
OFBool OFDateTime::setTime(const OFTime &timeVal)
170
0
{
171
0
    OFBool result = OFFalse;
172
    /* check whether new time is valid */
173
0
    if (timeVal.isValid())
174
0
    {
175
0
        Time = timeVal;
176
0
        result = OFTrue;
177
0
    }
178
0
    return result;
179
0
}
180
181
182
OFBool OFDateTime::setDateTime(const OFDate &dateVal,
183
                               const OFTime &timeVal)
184
0
{
185
0
    const OFBool result = setDate(dateVal);
186
    /* make sure that time value is set even if date is invalid */
187
0
    return setTime(timeVal) && result;
188
0
}
189
190
191
OFBool OFDateTime::setCurrentDateTime()
192
0
{
193
    /* set current system date and time, use the same "time_t" struct to avoid inconsistencies */
194
0
    time_t tt = time(NULL);
195
0
    return Date.setCurrentDate(tt) && Time.setCurrentTime(tt);
196
0
}
197
198
199
OFBool OFDateTime::setISOFormattedDateTime(const OFString &formattedDateTime)
200
0
{
201
    /* try to split 'formattedDateTime' into a 'formattedDate' and a 'formattedTime' */
202
0
    const size_t length = formattedDateTime.length();
203
204
    /* a 'formattedDate' is at least eight characters long: YYYYMMDD */
205
0
    if (length < 8)
206
0
    {
207
0
        return OFFalse;
208
0
    }
209
210
    /* (Weak) check if a delimiter is used. If so, we'll assert that it
211
     * is always the same one, i.e. 'delim'.
212
     */
213
0
    const char delim = formattedDateTime.at(4);
214
0
    const OFBool delimsUsed = !isdigit(OFstatic_cast(unsigned char, delim));
215
216
    /* where will 'formattedTime' start within 'formattedDateTime'? */
217
0
    size_t pos = 0;
218
0
    if (delimsUsed && (length >= 10))
219
0
    {
220
        /* a 'formattedDate' with delimiters is at least ten characters long: YYYY-MM-DD */
221
0
        pos = 10;
222
0
    }
223
0
    else if (!delimsUsed && (length >= 8))
224
0
    {
225
        /* a 'formattedDate' without delimiters is at least eight characters long: YYYYMMDD */
226
0
        pos = 8;
227
0
    }
228
0
    else
229
0
    {
230
0
        return OFFalse;
231
0
    }
232
233
    /* remember the current date in case setting the formatted time will fail */
234
0
    const OFDate preDate = getDate();
235
236
    /* try to set the formatted date */
237
0
    const OFString formattedDate = formattedDateTime.substr(0, pos);
238
0
    const OFBool setDateStatus = Date.setISOFormattedDate(formattedDate);
239
    /* setting the formatted date failed, time to return */
240
0
    if (!setDateStatus)
241
0
    {
242
0
        return OFFalse;
243
0
    }
244
245
    /* skip non digits in case delimiter character has been used */
246
0
    if (delimsUsed)
247
0
    {
248
0
        while ((pos < length) && !isdigit(OFstatic_cast(unsigned char, formattedDateTime.at(pos))))
249
0
        {
250
0
            ++pos;
251
0
        }
252
0
    }
253
0
    const OFString formattedTime = formattedDateTime.substr(pos);
254
0
    const OFBool setTimeStatus = Time.setISOFormattedTime(formattedTime);
255
0
    if (!setTimeStatus)
256
0
    {
257
        /* setting the time failed, restore the former date */
258
0
        if (preDate.isValid())
259
0
        {
260
0
            setDate(preDate);
261
0
        }
262
0
        else
263
0
        {
264
0
            Date.clear();
265
0
        }
266
0
    }
267
268
0
    return setTimeStatus;
269
0
}
270
271
272
const OFDate &OFDateTime::getDate() const
273
0
{
274
0
    return Date;
275
0
}
276
277
278
const OFTime &OFDateTime::getTime() const
279
0
{
280
0
    return Time;
281
0
}
282
283
284
OFBool OFDateTime::getISOFormattedDateTime(OFString &formattedDateTime,
285
                                           const OFBool showSeconds,
286
                                           const OFBool showFraction,
287
                                           const OFBool showTimeZone,
288
                                           const OFBool showDelimiter,
289
                                           const OFBool createMissingPart,
290
                                           const OFString &dateTimeSeparator,
291
                                           const OFString &timeZoneSeparator) const
292
0
{
293
    /* get formatted date first component */
294
0
    OFBool result = Date.getISOFormattedDate(formattedDateTime, showDelimiter);
295
0
    if (result)
296
0
    {
297
        /* ... then get the formatted time component */
298
0
        OFString timeString;
299
0
        if (Time.getISOFormattedTime(timeString, showSeconds, showFraction, showTimeZone, showDelimiter, createMissingPart, timeZoneSeparator))
300
0
        {
301
0
            if (showDelimiter)
302
0
                formattedDateTime += dateTimeSeparator;
303
0
            formattedDateTime += timeString;
304
0
        }
305
0
    } else {
306
        /* clear result variable in case of error */
307
0
        formattedDateTime.clear();
308
0
    }
309
0
    return result;
310
0
}
311
312
313
// -- static helper functions --
314
315
OFDateTime OFDateTime::getCurrentDateTime()
316
0
{
317
    /* create a date/time object with the current system date/time set */
318
0
    OFDateTime dateTime;
319
    /* this call might fail! */
320
0
    dateTime.setCurrentDateTime();
321
    /* return by-value */
322
0
    return dateTime;
323
0
}
324
325
326
// -- output operator --
327
328
STD_NAMESPACE ostream &operator<<(STD_NAMESPACE ostream &stream,
329
                                  const OFDateTime &dateTime)
330
0
{
331
0
    OFString string;
332
    /* print the given date and time in ISO format to the stream */
333
0
    if (dateTime.getISOFormattedDateTime(string, OFTrue /*showSeconds*/, OFTrue /*showFraction*/, OFTrue /*showTimeZone*/))
334
0
        stream << string;
335
0
    return stream;
336
0
}