Project

General

Profile

Patch #895 » github_pr17.patch

GitHub pull request #17 - Jörg Riesmeier, 2019-08-07 14:52

View differences:

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