Patch #895 » github_pr17.patch
| ofstd/include/dcmtk/ofstd/ofdatime.h | ||
|---|---|---|
|
/** set the date/time value to the given ISO formatted date/time string.
|
||
|
* The two ISO date/time formats supported by this function are
|
||
|
* - "YYYY-MM-DD HH:MM[:SS [&ZZ:ZZ]]" (with arbitrary delimiters) and
|
||
|
* - "YYYYMMDDHHMM[SS[&ZZZZ]]" (without delimiters, useful for DICOM datetime type)
|
||
|
* where the brackets enclose optional parts. Please note that the optional fractional
|
||
|
* part of a second ".FFFFFF" (see getISOFormattedDateTime()) is not yet supported.
|
||
|
* - "YYYY-MM-DD HH:MM[:SS[.FFFFFF] [&ZZ:ZZ]]" (with arbitrary delimiters) and
|
||
|
* - "YYYYMMDDHHMM[SS[.FFFFFF][&ZZZZ]]" (without delimiters, useful for DICOM datetime type)
|
||
|
* where the brackets enclose optional parts. Optional fractional
|
||
|
* part of a second ".FFFFFF" (see getISOFormattedDateTime()) is supported.
|
||
|
* @param formattedDateTime ISO formatted date/time value to be set
|
||
|
* @return OFTrue if input is valid and result variable has been set, OFFalse otherwise
|
||
|
*/
|
||
| ofstd/include/dcmtk/ofstd/oftime.h | ||
|---|---|---|
|
/** set the time value to the given ISO formatted time string.
|
||
|
* The two ISO time formats supported by this function are
|
||
|
* - "HH:MM[:SS [&ZZ:ZZ]]" (with arbitrary delimiters) and
|
||
|
* - "HHMM[SS[&ZZZZ]]" (without delimiters)
|
||
|
* where the brackets enclose optional parts. Please note that the optional fractional
|
||
|
* part of a second ".FFFFFF" (see getISOFormattedTime()) is not yet supported.
|
||
|
* - "HH:MM[:SS[.FFFFFF] [&ZZ:ZZ]]" (with arbitrary delimiters) and
|
||
|
* - "HHMM[SS[.FFFFFF][&ZZZZ]]" (without delimiters)
|
||
|
* where the brackets enclose optional parts. Optional fractional
|
||
|
* part of a second ".FFFFFF" (see getISOFormattedTime()) is supported.
|
||
|
* @param formattedTime ISO formatted time value to be set
|
||
|
* @return OFTrue if input is valid and result variable has been set, OFFalse otherwise
|
||
|
*/
|
||
| ofstd/libsrc/ofdatime.cc | ||
|---|---|---|
|
OFBool OFDateTime::setISOFormattedDateTime(const OFString &formattedDateTime)
|
||
|
{
|
||
|
OFBool result = OFFalse;
|
||
|
const size_t length = formattedDateTime.length();
|
||
|
const size_t firstSep = formattedDateTime.find_first_not_of("0123456789");
|
||
|
const OFBool separators = (firstSep != OFString_npos);
|
||
|
/* check for supported formats: "YYYYMMDDHHMM[SS]" or "YYYYMMDDHHMMSS&ZZZZ" */
|
||
|
if (((((length == 12) || (length == 14)) && !separators) ||
|
||
|
((length == 19) && (firstSep == 14) && ((formattedDateTime[14] == '+') || (formattedDateTime[14] == '-')))))
|
||
|
{
|
||
|
if (Date.setISOFormattedDate(formattedDateTime.substr(0, 8)) && Time.setISOFormattedTime(formattedDateTime.substr(8)))
|
||
|
result = OFTrue;
|
||
|
size_t tm_pos = 0;
|
||
|
size_t date_digits = 0;
|
||
|
size_t date_size = 0;
|
||
|
/* find end of YYYYMMDD or YYYY-MM-DD */
|
||
|
while (tm_pos < length && date_digits < 8) {
|
||
|
if (isdigit(formattedDateTime.at(tm_pos)))
|
||
|
date_digits++;
|
||
|
tm_pos++;
|
||
|
}
|
||
|
/* "YYYY-MM-DD HH:MM[:SS]" or "YYYY-MM-DD HH:MM:SS &ZZ:ZZ" */
|
||
|
else if ((length >= 16) && separators)
|
||
|
{
|
||
|
if (Date.setISOFormattedDate(formattedDateTime.substr(0, 10)))
|
||
|
{
|
||
|
size_t pos = 10;
|
||
|
/* search for first digit of the time value (skip arbitrary separators) */
|
||
|
while ((pos < length) && !isdigit(OFstatic_cast(unsigned char, formattedDateTime.at(pos))))
|
||
|
++pos;
|
||
|
if ((pos < length) && Time.setISOFormattedTime(formattedDateTime.substr(pos)))
|
||
|
result = OFTrue;
|
||
|
}
|
||
|
/* check if we found enough number of digits for date and symbols for time to continue parsing */
|
||
|
if (date_digits < 8 || tm_pos == length)
|
||
|
return OFFalse;
|
||
|
date_size = tm_pos;
|
||
|
if (formattedDateTime.at(tm_pos) == 'T') {
|
||
|
/* dateTtime, skip T */
|
||
|
tm_pos++;
|
||
|
} else {
|
||
|
/* skip heading spaces from time */
|
||
|
while (tm_pos < length && formattedDateTime.at(tm_pos) == ' ')
|
||
|
tm_pos++;
|
||
|
}
|
||
|
return result;
|
||
|
/* check if we have enough symbols for time to continue parsing */
|
||
|
if (tm_pos == length)
|
||
|
return OFFalse;
|
||
|
/* parse ISO formatted date */
|
||
|
if (!Date.setISOFormattedDate(formattedDateTime.substr(0, date_size)))
|
||
|
return OFFalse;
|
||
|
/* parse ISO formatted time */
|
||
|
if (!Time.setISOFormattedTime(formattedDateTime.substr(tm_pos)))
|
||
|
return OFFalse;
|
||
|
return OFTrue;
|
||
|
}
|
||
| ofstd/libsrc/oftime.cc | ||
|---|---|---|
|
*
|
||
|
*/
|
||
|
#include "dcmtk/config/osconfig.h"
|
||
|
#define INCLUDE_CSTDIO
|
||
| ... | ... | |
|
OFBool OFTime::setISOFormattedTime(const OFString &formattedTime)
|
||
|
{
|
||
|
OFBool status = OFFalse;
|
||
|
unsigned int hours, minutes;
|
||
|
double seconds, timezone;
|
||
|
size_t pos = 0;
|
||
|
const size_t length = formattedTime.length();
|
||
|
const size_t firstSep = formattedTime.find_first_not_of("0123456789");
|
||
|
const OFBool separators = (firstSep != OFString_npos);
|
||
|
unsigned int hours, minutes, seconds;
|
||
|
/* check for supported formats: HHMM */
|
||
|
if ((length == 4) && !separators)
|
||
|
{
|
||
|
/* extract "HH" and "MM" components from time string */
|
||
|
if (sscanf(formattedTime.c_str(), "%02u%02u", &hours, &minutes) == 2)
|
||
|
status = setTime(hours, minutes, 0 /*seconds*/);
|
||
|
OFBool delim_must_present = OFFalse;
|
||
|
char delimiter = ':';
|
||
|
#define FTOA_TODIGIT(c) ((c) - '0')
|
||
|
if ((length - pos) < 2 || !isdigit(formattedTime[pos]) || !isdigit(formattedTime[pos + 1])) {
|
||
|
/* no digits available to get hours */
|
||
|
return OFFalse;
|
||
|
}
|
||
|
/* HH:MM */
|
||
|
else if ((length == 5) && separators)
|
||
|
{
|
||
|
/* extract "HH" and "MM" components from time string */
|
||
|
if (sscanf(formattedTime.c_str(), "%02u%*c%02u", &hours, &minutes) == 2)
|
||
|
status = setTime(hours, minutes, 0 /*seconds*/);
|
||
|
hours = FTOA_TODIGIT(formattedTime[pos]) * 10 + FTOA_TODIGIT(formattedTime[pos + 1]);
|
||
|
/* step to minutes or delimiter */
|
||
|
pos += 2;
|
||
|
if ((length - pos) < 1) {
|
||
|
/* length is not enough for ':' (possible) delimiter */
|
||
|
return OFFalse;
|
||
|
}
|
||
|
/* HHMMSS */
|
||
|
else if ((length == 6) && !separators)
|
||
|
{
|
||
|
/* extract "HH", "MM" and "SS" components from time string */
|
||
|
if (sscanf(formattedTime.c_str(), "%02u%02u%02u", &hours, &minutes, &seconds) == 3)
|
||
|
status = setTime(hours, minutes, seconds);
|
||
|
/* skip delimiter ':' if it found here */
|
||
|
if (formattedTime[pos] == ':' || formattedTime[pos] == '-') {
|
||
|
/* after first ':' between HH and MM we require it everywhere */
|
||
|
delim_must_present = OFTrue;
|
||
|
delimiter = formattedTime[pos];
|
||
|
pos++;
|
||
|
}
|
||
|
/* HH:MM:SS */
|
||
|
else if ((length == 8) && separators)
|
||
|
{
|
||
|
/* extract "HH", "MM" and "SS" components from time string */
|
||
|
if (sscanf(formattedTime.c_str(), "%02u%*c%02u%*c%02u", &hours, &minutes, &seconds) == 3)
|
||
|
status = setTime(hours, minutes, seconds);
|
||
|
if ((length - pos) < 2 || !isdigit(formattedTime[pos]) || !isdigit(formattedTime[pos + 1])) {
|
||
|
/* no digits available to get minutes */
|
||
|
return OFFalse;
|
||
|
}
|
||
|
/* HHMMSS&ZZZZ */
|
||
|
else if ((length == 11) && (firstSep == 6) && ((formattedTime[6] == '+') || (formattedTime[6] == '-')))
|
||
|
{
|
||
|
int tzHours;
|
||
|
unsigned int tzMinutes;
|
||
|
/* extract "HH", "MM", "SS" and "&ZZZZ" components from time string */
|
||
|
if (sscanf(formattedTime.c_str(), "%02u%02u%02u%03d%02u", &hours, &minutes, &seconds, &tzHours, &tzMinutes) == 5)
|
||
|
{
|
||
|
const double timeZone = (tzHours < 0) ? tzHours - OFstatic_cast(double, tzMinutes) / 60
|
||
|
: tzHours + OFstatic_cast(double, tzMinutes) / 60;
|
||
|
status = setTime(hours, minutes, seconds, timeZone);
|
||
|
minutes = FTOA_TODIGIT(formattedTime[pos]) * 10 + FTOA_TODIGIT(formattedTime[pos + 1]);
|
||
|
/* step to seconds or delimiter */
|
||
|
pos += 2;
|
||
|
if ((length - pos) < 1) {
|
||
|
/* HHMM or HH:MM is okay */
|
||
|
return setTime(hours, minutes, seconds);
|
||
|
}
|
||
|
/* skip one allowed ':' if it found here */
|
||
|
if (formattedTime[pos] == delimiter) {
|
||
|
pos++;
|
||
|
} else if (delim_must_present) {
|
||
|
return OFFalse;
|
||
|
}
|
||
|
if ((length - pos) < 2 || !isdigit(formattedTime[pos]) || !isdigit(formattedTime[pos + 1])) {
|
||
|
/* no digits available to get seconds */
|
||
|
return OFFalse;
|
||
|
}
|
||
|
seconds = FTOA_TODIGIT(formattedTime[pos]) * 10.0 + FTOA_TODIGIT(formattedTime[pos + 1]);
|
||
|
/* step to fractional part of seconds or time zone */
|
||
|
pos += 2;
|
||
|
if ((length - pos) >= 1 && formattedTime[pos] == '.') {
|
||
|
pos++;
|
||
|
size_t fp_start = pos, fp_size = 0;
|
||
|
/* we are on beginning of the fractional part of seconds */
|
||
|
while ( pos < length && isdigit(formattedTime[pos]) ) {
|
||
|
fp_size++;
|
||
|
pos++;
|
||
|
}
|
||
|
/* Part 05, sect 6.2. The FFFFFF component, if present, shall contain 1 to 6 digits. */
|
||
|
if (fp_size == 0 || fp_size > 6) {
|
||
|
return OFFalse;
|
||
|
}
|
||
|
double fp_divider = 0.1;
|
||
|
for (size_t fpi = fp_start; fpi < pos; fpi++, fp_divider /= 10.0) {
|
||
|
seconds += fp_divider * FTOA_TODIGIT(formattedTime[fpi]);
|
||
|
}
|
||
|
}
|
||
|
/* HH:MM:SS &ZZ:ZZ */
|
||
|
else if ((length >= 14) && separators)
|
||
|
{
|
||
|
/* first, extract "HH", "MM" and "SS" components from time string */
|
||
|
if (sscanf(formattedTime.c_str(), "%02u%*c%02u%*c%02u", &hours, &minutes, &seconds) == 3)
|
||
|
{
|
||
|
size_t pos = 8;
|
||
|
/* then search for the first digit of the time zone value (skip arbitrary separators) */
|
||
|
while ((pos < length) && !isdigit(OFstatic_cast(unsigned char, formattedTime.at(pos))))
|
||
|
++pos;
|
||
|
if (pos < length)
|
||
|
{
|
||
|
/* and finally, extract the time zone component from the time string */
|
||
|
int tzHours;
|
||
|
unsigned int tzMinutes;
|
||
|
if (sscanf(formattedTime.c_str() + pos - 1, "%03d%*c%02u", &tzHours, &tzMinutes) == 2)
|
||
|
{
|
||
|
const double timeZone = (tzHours < 0) ? tzHours - OFstatic_cast(double, tzMinutes) / 60
|
||
|
: tzHours + OFstatic_cast(double, tzMinutes) / 60;
|
||
|
status = setTime(hours, minutes, seconds, timeZone);
|
||
|
}
|
||
|
}
|
||
|
if ((length - pos) >= 1) {
|
||
|
/* extract "&ZZZZ" or "&ZZ:ZZ" components from time string */
|
||
|
if (delim_must_present) {
|
||
|
while (pos < length && formattedTime[pos] == ' ')
|
||
|
pos++;
|
||
|
}
|
||
|
if ((length - pos) < 1) {
|
||
|
/* length is not enough for '&' delimiter */
|
||
|
return OFFalse;
|
||
|
}
|
||
|
if (((formattedTime[pos] != '+') && (formattedTime[pos] != '-')))
|
||
|
return OFFalse;
|
||
|
int tzHours;
|
||
|
unsigned int tzMinutes;
|
||
|
if (delim_must_present) {
|
||
|
if (sscanf(formattedTime.c_str() + pos, "%03d%*c%02u", &tzHours, &tzMinutes) != 2)
|
||
|
return OFFalse;
|
||
|
} else {
|
||
|
if (sscanf(formattedTime.c_str() + pos, "%03d%02u", &tzHours, &tzMinutes) != 2)
|
||
|
return OFFalse;
|
||
|
}
|
||
|
const double timeZone = (tzHours < 0) ? tzHours - OFstatic_cast(double, tzMinutes) / 60
|
||
|
: tzHours + OFstatic_cast(double, tzMinutes) / 60;
|
||
|
return setTime(hours, minutes, seconds, timeZone);
|
||
|
}
|
||
|
return status;
|
||
|
return setTime(hours, minutes, seconds);
|
||
|
}
|
||
| ofstd/tests/tofdatim.cc | ||
|---|---|---|
|
OFCHECK_EQUAL(time1.getTimeInSeconds(OFTrue /*useTimeZone*/, OFFalse /*normalize*/), 13599);
|
||
|
OFCHECK(time1.setTimeInHours(99, 0, OFTrue /*normalized*/));
|
||
|
OFCHECK_EQUAL(time1.getTimeInHours(OFTrue /*useTimeZone*/, OFFalse /*normalize*/), 3);
|
||
|
/* the "seconds" part is mandatory if fractional part is present */
|
||
|
OFCHECK(!time1.setISOFormattedTime("10:15.9"));
|
||
|
OFCHECK(time1.setISOFormattedTime("10:15:30.9"));
|
||
|
OFCHECK_EQUAL(time1.getSecond(), 30.9);
|
||
|
OFCHECK(time1.setISOFormattedTime("101530.987654"));
|
||
|
OFCHECK_EQUAL(time1.getHour(), 10);
|
||
|
OFCHECK_EQUAL(time1.getMinute(), 15);
|
||
|
OFCHECK_EQUAL(time1.getSecond(), 30.987654);
|
||
|
OFCHECK(time1.setISOFormattedTime("10:15:30.102030 +01:30"));
|
||
|
OFCHECK_EQUAL(time1.getTimeZone(), +1.50);
|
||
|
OFCHECK_EQUAL(time1.getSecond(), 30.10203);
|
||
|
}
|
||
| ... | ... | |
|
/* the "seconds" part is mandatory if time zone is present */
|
||
|
OFCHECK(!dateTime2.setISOFormattedDateTime("2000-12-31 10:15 -02:30"));
|
||
|
OFCHECK(!dateTime2.setISOFormattedDateTime("200012311015+0100"));
|
||
|
/* the "seconds" part is mandatory if fractional part is present */
|
||
|
OFCHECK(!dateTime1.setISOFormattedDateTime("200012311015.9"));
|
||
|
/* fractional part must contain digits only */
|
||
|
OFCHECK(!dateTime1.setISOFormattedDateTime("20001231101530.9B2"));
|
||
|
OFCHECK(dateTime1.setISOFormattedDateTime("20001231101530.9"));
|
||
|
OFCHECK(dateTime1.getISOFormattedDateTime(tmpString, OFTrue /*showSeconds*/, OFTrue /*showFraction*/,
|
||
|
OFTrue /*showTimeZone*/, OFFalse /*showDelimiter*/, "" /*dateTimeSeparator*/, "" /*timeZoneSeparator*/));
|
||
|
OFCHECK_EQUAL(tmpString, "20001231101530.900000+0000");
|
||
|
/* maximal length is 6 digits */
|
||
|
OFCHECK(!dateTime1.setISOFormattedDateTime("20001231101530.0000001"));
|
||
|
OFCHECK(dateTime1.setISOFormattedDateTime("20001231101530.123456-0130"));
|
||
|
OFCHECK(dateTime1.getISOFormattedDateTime(tmpString, OFTrue /*showSeconds*/, OFTrue /*showFraction*/,
|
||
|
OFTrue /*showTimeZone*/, OFTrue /*showDelimiter*/, " " /*dateTimeSeparator*/, " " /*timeZoneSeparator*/));
|
||
|
OFCHECK_EQUAL(tmpString, "2000-12-31 10:15:30.123456 -01:30");
|
||
|
}
|
||