Patch #895 » 2ec7d368c.diff
| ofstd/include/dcmtk/ofstd/ofdatime.h | ||
|---|---|---|
|
*
|
||
|
* Module: ofstd
|
||
|
*
|
||
|
* Author: Joerg Riesmeier
|
||
|
* Author: Joerg Riesmeier, Harald Roesen
|
||
|
*
|
||
|
* Purpose: Combined class for date and time functions
|
||
|
*
|
||
| ... | ... | |
|
/** 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)
|
||
|
* - "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 and the "&" is a placeholder for the sign
|
||
|
* symbol ("+" or "-").
|
||
|
* @note Please note that the optional fractional part of a second ".FFFFFF" (see
|
||
|
* getISOFormattedDateTime()) is not yet supported.
|
||
|
* symbol ("+" or "-"). The pattern "FFFFFF" contains a fractional part of a second.
|
||
|
* If specified, it shall contain one to six digits representing a range from 0 to 999999.
|
||
|
* @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 | ||
|---|---|---|
|
*
|
||
|
* Module: ofstd
|
||
|
*
|
||
|
* Author: Joerg Riesmeier
|
||
|
* Author: Joerg Riesmeier, Harald Roesen
|
||
|
*
|
||
|
* Purpose: Class for time functions
|
||
|
*
|
||
| ... | ... | |
|
/** 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)
|
||
|
* - "HH:MM[:SS[.FFFFFF] [&ZZ:ZZ]]" (with arbitrary delimiters) and
|
||
|
* - "HHMM[SS[.FFFFFF][&ZZZZ]]" (without delimiters)
|
||
|
*
|
||
|
* where the brackets enclose optional parts and the "&" is a placeholder for the
|
||
|
* sign symbol ("+" or "-").
|
||
|
* @note Please note that the optional fractional part of a second ".FFFFFF" (see
|
||
|
* getISOFormattedTime()) is not yet supported.
|
||
|
* sign symbol ("+" or "-"). The pattern "FFFFFF" contains a fractional part of a second.
|
||
|
* If specified, it shall contain one to six digits representing a range from 0 to 999999.
|
||
|
* @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 | ||
|---|---|---|
|
*
|
||
|
* Module: ofstd
|
||
|
*
|
||
|
* Author: Joerg Riesmeier
|
||
|
* Author: Joerg Riesmeier, Harald Roesen
|
||
|
*
|
||
|
* Purpose: Class for date and time functions (Source)
|
||
|
*
|
||
| ... | ... | |
|
}
|
||
|
OFBool OFDateTime::setISOFormattedDateTime(const OFString &formattedDateTime)
|
||
|
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;
|
||
|
// try to split 'formattedDateTime' into a 'formattedDate' and a 'formattedTime'
|
||
|
size_t const length = formattedDateTime.length();
|
||
|
// a 'formattedDate' is at least eight characters long: YYYMMDD
|
||
|
if (length < 8) {
|
||
|
return OFFalse;
|
||
|
}
|
||
|
/* "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;
|
||
|
// (weak) check if a delimiter is used
|
||
|
char const delim = formattedDateTime.at(4);
|
||
|
OFBool const delimsUsed = !std::isdigit(delim);
|
||
|
// where will 'formattedTime' start within 'formattedDateTime'?
|
||
|
size_t pos = 0;
|
||
|
if (delimsUsed && (length >= 10)) {
|
||
|
// a 'formattedDate' with delimiters is at least ten characters long: YYYY-MM-DD
|
||
|
pos = 10;
|
||
|
}
|
||
|
else if (!delimsUsed && (length >= 8)) {
|
||
|
// a 'formattedDate' without delimiters is at least eight characters long: YYYYMMDD
|
||
|
pos = 8;
|
||
|
}
|
||
|
else {
|
||
|
return OFFalse;
|
||
|
}
|
||
|
// remember the current date in case setting the formatted time will fail
|
||
|
OFDate const preDate = getDate();
|
||
|
// try to set the formatted date
|
||
|
OFString const formattedDate = formattedDateTime.substr(0, pos);
|
||
|
OFBool const setDateStatus = Date.setISOFormattedDate(formattedDate);
|
||
|
// setting the formatted date failed, time to return
|
||
|
if (!setDateStatus) {
|
||
|
return OFFalse;
|
||
|
}
|
||
|
// skip non digits in case delimiter character has been used
|
||
|
if(delimsUsed) {
|
||
|
while ((pos < length) && !std::isdigit(formattedDateTime.at(pos))) {
|
||
|
++pos;
|
||
|
}
|
||
|
}
|
||
|
return result;
|
||
|
OFString const formattedTime = formattedDateTime.substr(pos);
|
||
|
OFBool const setTimeStatus = Time.setISOFormattedTime(formattedTime);
|
||
|
if (!setTimeStatus) {
|
||
|
// setting the time failed, restore the former date
|
||
|
if (preDate.isValid()) {
|
||
|
setDate(preDate);
|
||
|
}
|
||
|
else {
|
||
|
Date.clear();
|
||
|
}
|
||
|
}
|
||
|
return setTimeStatus;
|
||
|
}
|
||
| ofstd/libsrc/oftime.cc | ||
|---|---|---|
|
*
|
||
|
* Module: ofstd
|
||
|
*
|
||
|
* Author: Joerg Riesmeier
|
||
|
* Author: Joerg Riesmeier, Harald Roesen
|
||
|
*
|
||
|
* Purpose: Class for time functions (Source)
|
||
|
*
|
||
| ... | ... | |
|
return status;
|
||
|
}
|
||
|
OFBool OFTime::setISOFormattedTime(const OFString &formattedTime)
|
||
|
OFBool OFTime::setISOFormattedTime(OFString const & formattedTime)
|
||
|
{
|
||
|
OFBool status = OFFalse;
|
||
|
const size_t length = formattedTime.length();
|
||
|
const size_t firstDelimiter = formattedTime.find_first_not_of("0123456789");
|
||
|
const OFBool hasDelimiters = (firstDelimiter != OFString_npos);
|
||
|
unsigned int hours, minutes, seconds;
|
||
|
/* check for supported formats: HHMM */
|
||
|
if ((length == 4) && !hasDelimiters)
|
||
|
{
|
||
|
/* extract "HH" and "MM" components from time string */
|
||
|
if (sscanf(formattedTime.c_str(), "%02u%02u", &hours, &minutes) == 2)
|
||
|
status = setTime(hours, minutes, 0 /*seconds*/);
|
||
|
}
|
||
|
/* HH:MM */
|
||
|
else if ((length == 5) && hasDelimiters)
|
||
|
{
|
||
|
/* extract "HH" and "MM" components from time string (ignore delimiter) */
|
||
|
if (sscanf(formattedTime.c_str(), "%02u%*c%02u", &hours, &minutes) == 2)
|
||
|
status = setTime(hours, minutes, 0 /*seconds*/);
|
||
|
size_t const length = formattedTime.length();
|
||
|
if (length < 3) {
|
||
|
// not enough input to scan
|
||
|
return OFFalse;
|
||
|
}
|
||
|
/* HHMMSS */
|
||
|
else if ((length == 6) && !hasDelimiters)
|
||
|
size_t pos = 0;
|
||
|
char const delim = formattedTime.at(pos + 2);
|
||
|
OFBool const delimsUsed = !std::isdigit(delim);
|
||
|
unsigned int hours = 0;
|
||
|
unsigned int minutes = 0;
|
||
|
unsigned int seconds = 0;
|
||
|
double fractionalSeconds = 0.0;
|
||
|
double timeZone = OFTime::unspecifiedTimeZone;
|
||
|
{
|
||
|
/* 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);
|
||
|
// scan for HHMM or HH:MM - hours and minutes
|
||
|
OFString hhmmFormat("%2u");
|
||
|
if (delimsUsed) {
|
||
|
hhmmFormat += delim;
|
||
|
}
|
||
|
hhmmFormat += "%2u%n";
|
||
|
int const nCharactersExpected = (delimsUsed ? 5 : 4);
|
||
|
int nCharactersRead = 0;
|
||
|
int const nReceivedArgs =
|
||
|
std::sscanf(formattedTime.c_str() + pos, hhmmFormat.data(), &hours, &minutes, &nCharactersRead);
|
||
|
if ((nReceivedArgs == 2) && (nCharactersRead == nCharactersExpected)) {
|
||
|
pos += nCharactersRead;
|
||
|
}
|
||
|
else {
|
||
|
// found no valid HH[:]MM 'pattern'
|
||
|
return OFFalse;
|
||
|
}
|
||
|
}
|
||
|
/* HH:MM:SS */
|
||
|
else if ((length == 8) && hasDelimiters)
|
||
|
{
|
||
|
/* extract "HH", "MM" and "SS" components from time string (ignore delimiters) */
|
||
|
if (sscanf(formattedTime.c_str(), "%02u%*c%02u%*c%02u", &hours, &minutes, &seconds) == 3)
|
||
|
status = setTime(hours, minutes, seconds);
|
||
|
// Is still input available?
|
||
|
if (pos < length) {
|
||
|
// scan for SS or :SS - seconds
|
||
|
OFString ssFormat;
|
||
|
if (delimsUsed) {
|
||
|
ssFormat += delim;
|
||
|
}
|
||
|
ssFormat += "%2u%n";
|
||
|
int const nCharactersExpected = (delimsUsed ? 3 : 2);
|
||
|
int nCharactersRead = 0;
|
||
|
int const nReceivedArgs =
|
||
|
std::sscanf(formattedTime.c_str() + pos, ssFormat.data(), &seconds, &nCharactersRead);
|
||
|
if (nReceivedArgs == 1 && (nCharactersRead == nCharactersExpected)) {
|
||
|
pos += nCharactersRead;
|
||
|
}
|
||
|
else {
|
||
|
// found no valid [:]SS 'pattern'
|
||
|
return OFFalse;
|
||
|
}
|
||
|
}
|
||
|
/* HHMMSS&ZZZZ */
|
||
|
else if ((length == 11) && (firstDelimiter == 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);
|
||
|
// Is still input available that also starts with a dot ('.') character?
|
||
|
if ((pos < length) && (formattedTime.at(pos) == '.')) {
|
||
|
// scan for .FFFFFF - fractional seconds
|
||
|
char buffer[7] = {'\0'};
|
||
|
buffer[0] = '.';
|
||
|
++pos; // overread the dot ('.') character at front
|
||
|
int nCharactersRead = 0;
|
||
|
int const nReceivedArgs =
|
||
|
std::sscanf(formattedTime.c_str() + pos, "%6[0123456789]%n", (buffer + 1), &nCharactersRead);
|
||
|
if (nReceivedArgs == 1) {
|
||
|
pos += nCharactersRead;
|
||
|
fractionalSeconds = std::atof(buffer);
|
||
|
}
|
||
|
else {
|
||
|
// found no valid .FFFFFF 'pattern'
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
/* HH:MM:SS &ZZ:ZZ */
|
||
|
else if ((length >= 14) && hasDelimiters)
|
||
|
{
|
||
|
/* first, extract "HH", "MM" and "SS" components from time string (ignore delimiters) */
|
||
|
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 delimiters) */
|
||
|
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;
|
||
|
/* ignore the delimiter "%c" */
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
// skip whitespaces in case delimiter character has been used
|
||
|
if (delimsUsed) {
|
||
|
while ((pos < length) && std::isspace(formattedTime.at(pos))) {
|
||
|
++pos;
|
||
|
}
|
||
|
}
|
||
|
return status;
|
||
|
// Is still input available that also starts with a plus ('+') or minus ('-')
|
||
|
// character?
|
||
|
if ((pos < length) && ((formattedTime.at(pos) == '+') || (formattedTime.at(pos) == '-'))) {
|
||
|
// scan for &ZZZZ or &ZZ:ZZ - time zone
|
||
|
OFString tzFormat("%3d");
|
||
|
if (delimsUsed) {
|
||
|
tzFormat += delim;
|
||
|
}
|
||
|
tzFormat += "%2u%n";
|
||
|
int tzHours;
|
||
|
unsigned int tzMinutes;
|
||
|
int nCharactersRead = 0;
|
||
|
int const nReceivedArgs =
|
||
|
sscanf(formattedTime.c_str() + pos, tzFormat.data(), &tzHours, &tzMinutes, &nCharactersRead);
|
||
|
if (nReceivedArgs == 2) {
|
||
|
timeZone = (tzHours < 0) ? tzHours - static_cast<double>(tzMinutes) / 60
|
||
|
: tzHours + static_cast<double>(tzMinutes) / 60;
|
||
|
pos += nCharactersRead;
|
||
|
}
|
||
|
else {
|
||
|
// found no valid &ZZ[:]ZZ 'pattern'
|
||
|
return OFFalse;
|
||
|
}
|
||
|
}
|
||
|
// Is still input available?
|
||
|
if (pos < length) {
|
||
|
// too much
|
||
|
return OFFalse;
|
||
|
}
|
||
|
// all 'eaten up'
|
||
|
return setTime(hours, minutes, seconds + fractionalSeconds, timeZone);
|
||
|
}
|
||
| ofstd/tests/tofdatim.cc | ||
|---|---|---|
|
*
|
||
|
* Module: ofstd
|
||
|
*
|
||
|
* Author: Joerg Riesmeier
|
||
|
* Author: Joerg Riesmeier, Harald Roesen
|
||
|
*
|
||
|
* Purpose: test program for classes OFDate, OFTime and OFDateTime
|
||
|
*
|
||
| ... | ... | |
|
OFCHECK_EQUAL(time2.getSecond(), 30.1234);
|
||
|
OFCHECK_EQUAL(time2.getIntSecond(), 30);
|
||
|
/* check setting ISO formatted time */
|
||
|
OFCHECK(time1.setISOFormattedTime("1215"));
|
||
|
OFCHECK(time1.setISOFormattedTime("12:15"));
|
||
|
OFCHECK(time1.setISOFormattedTime("121530"));
|
||
|
OFCHECK(time1.setISOFormattedTime("12:15:30"));
|
||
|
OFCHECK( time1.setISOFormattedTime("1215"));
|
||
|
OFCHECK(!time1.setISOFormattedTime("1215."));
|
||
|
OFCHECK(!time1.setISOFormattedTime("1215.1"));
|
||
|
OFCHECK(!time1.setISOFormattedTime("1215.123456"));
|
||
|
OFCHECK(!time1.setISOFormattedTime("1215.1234567"));
|
||
|
OFCHECK( time1.setISOFormattedTime("12:15"));
|
||
|
OFCHECK(!time1.setISOFormattedTime("12:15."));
|
||
|
OFCHECK(!time1.setISOFormattedTime("12:15.1"));
|
||
|
OFCHECK(!time1.setISOFormattedTime("12:15.123456"));
|
||
|
OFCHECK(!time1.setISOFormattedTime("12:15.1234567"));
|
||
|
OFCHECK( time1.setISOFormattedTime("121530"));
|
||
|
OFCHECK(!time1.setISOFormattedTime("121530."));
|
||
|
OFCHECK( time1.setISOFormattedTime("121530.1"));
|
||
|
OFCHECK( time1.setISOFormattedTime("121530.123456"));
|
||
|
OFCHECK(!time1.setISOFormattedTime("121530.1234567"));
|
||
|
OFCHECK( time1.setISOFormattedTime("12:15:30"));
|
||
|
OFCHECK(!time1.setISOFormattedTime("12:15:30."));
|
||
|
OFCHECK( time1.setISOFormattedTime("12:15:30.1"));
|
||
|
OFCHECK( time1.setISOFormattedTime("12:15:30.123456"));
|
||
|
OFCHECK(!time1.setISOFormattedTime("12:15:30.1234567"));
|
||
|
OFCHECK( time1.setISOFormattedTime("121530+0100"));
|
||
|
OFCHECK(!time1.setISOFormattedTime("121530.+0100"));
|
||
|
OFCHECK( time1.setISOFormattedTime("121530.1+0100"));
|
||
|
OFCHECK( time1.setISOFormattedTime("121530.123456+0100"));
|
||
|
OFCHECK(!time1.setISOFormattedTime("121530.1234567+0100"));
|
||
|
OFCHECK(time1.setISOFormattedTime("121530+0100"));
|
||
|
OFCHECK_EQUAL(time1.getTimeZone(), 1.0);
|
||
|
OFCHECK(time1.setISOFormattedTime("12:15:30 -02:30"));
|
||
| ... | ... | |
|
/* 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"));
|
||
|
OFCHECK( dateTime2.setISOFormattedDateTime("20001231101530-0230"));
|
||
|
OFCHECK(!dateTime2.setISOFormattedDateTime("20001231101530.-0230"));
|
||
|
OFCHECK( dateTime2.setISOFormattedDateTime("20001231101530.1-0230"));
|
||
|
OFCHECK( dateTime2.setISOFormattedDateTime("20001231101530.123456-0230"));
|
||
|
OFCHECK(!dateTime2.setISOFormattedDateTime("20001231101530.1234567-0230"));
|
||
|
OFCHECK( dateTime2.setISOFormattedDateTime("2000-12-31 10:15:30 -02:30"));
|
||
|
OFCHECK(!dateTime2.setISOFormattedDateTime("2000-12-31 10:15:30. -02:30"));
|
||
|
OFCHECK( dateTime2.setISOFormattedDateTime("2000-12-31 10:15:30.1 -02:30"));
|
||
|
OFCHECK( dateTime2.setISOFormattedDateTime("2000-12-31 10:15:30.123456 -02:30"));
|
||
|
OFCHECK(!dateTime2.setISOFormattedDateTime("2000-12-31 10:15:30.1234567 -02:30"));
|
||
|
// check if date is restored in case setting time failed
|
||
|
OFCHECK( dateTime2.setISOFormattedDateTime("2345-12-31 10:15:30 -02:30"));
|
||
|
OFDate const preDate = dateTime2.getDate();
|
||
|
OFCHECK(!dateTime2.setISOFormattedDateTime("2000-12-31 10:15:30 -0230"));
|
||
|
OFDate const postDate = dateTime2.getDate();
|
||
|
OFCHECK_EQUAL(preDate, postDate);
|
||
|
}
|
||