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");
|
||
}
|
||