Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 68 additions & 29 deletions core/src/value/partial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -281,15 +281,15 @@ where
impl DicomDate {
/**
* Constructs a new `DicomDate` with year precision
* (YYYY)
* (`YYYY`)
*/
pub fn from_y(year: u16) -> Result<DicomDate> {
check_component(DateComponent::Year, &year)?;
Ok(DicomDate(DicomDateImpl::Year(year)))
}
/**
* Constructs a new `DicomDate` with year and month precision
* (YYYYMM)
* (`YYYYMM`)
*/
pub fn from_ym(year: u16, month: u8) -> Result<DicomDate> {
check_component(DateComponent::Year, &year)?;
Expand All @@ -298,7 +298,7 @@ impl DicomDate {
}
/**
* Constructs a new `DicomDate` with a year, month and day precision
* (YYYYMMDD)
* (`YYYYMMDD`)
*/
pub fn from_ymd(year: u16, month: u8, day: u8) -> Result<DicomDate> {
check_component(DateComponent::Year, &year)?;
Expand All @@ -307,23 +307,23 @@ impl DicomDate {
Ok(DicomDate(DicomDateImpl::Day(year, month, day)))
}

// Retrievies the year from a date as a reference
/// Retrieves the year from a date as a reference
pub fn year(&self) -> &u16 {
match self {
DicomDate(DicomDateImpl::Year(y)) => y,
DicomDate(DicomDateImpl::Month(y, _)) => y,
DicomDate(DicomDateImpl::Day(y, _, _)) => y,
}
}
// Retrievies the month from a date as a reference
/// Retrieves the month from a date as a reference
pub fn month(&self) -> Option<&u8> {
match self {
DicomDate(DicomDateImpl::Year(_)) => None,
DicomDate(DicomDateImpl::Month(_, m)) => Some(m),
DicomDate(DicomDateImpl::Day(_, m, _)) => Some(m),
}
}
// Retrievies the day from a date as a reference
/// Retrieves the day from a date as a reference
pub fn day(&self) -> Option<&u8> {
match self {
DicomDate(DicomDateImpl::Year(_)) => None,
Expand Down Expand Up @@ -384,7 +384,7 @@ impl fmt::Debug for DicomDate {
impl DicomTime {
/**
* Constructs a new `DicomTime` with hour precision
* (HH).
* (`HH`).
*/
pub fn from_h(hour: u8) -> Result<DicomTime> {
check_component(DateComponent::Hour, &hour)?;
Expand All @@ -393,7 +393,7 @@ impl DicomTime {

/**
* Constructs a new `DicomTime` with hour and minute precision
* (HHMM).
* (`HHMM`).
*/
pub fn from_hm(hour: u8, minute: u8) -> Result<DicomTime> {
check_component(DateComponent::Hour, &hour)?;
Expand All @@ -403,7 +403,7 @@ impl DicomTime {

/**
* Constructs a new `DicomTime` with hour, minute and second precision
* (HHMMSS).
* (`HHMMSS`).
*/
pub fn from_hms(hour: u8, minute: u8, second: u8) -> Result<DicomTime> {
check_component(DateComponent::Hour, &hour)?;
Expand All @@ -413,7 +413,7 @@ impl DicomTime {
}
/**
* Constructs a new `DicomTime` from an hour, minute, second and millisecond value,
* which leads to a (HHMMSS.FFF) precision. Millisecond cannot exceed `999`.
* which leads to the precision `HHMMSS.FFF`. Millisecond cannot exceed `999`.
*/
pub fn from_hms_milli(hour: u8, minute: u8, second: u8, millisecond: u32) -> Result<DicomTime> {
check_component(DateComponent::Millisecond, &millisecond)?;
Expand All @@ -427,7 +427,7 @@ impl DicomTime {
}

/// Constructs a new `DicomTime` from an hour, minute, second and microsecond value,
/// which leads to full (`HHMMSS.FFFFFF`) precision.
/// which leads to the full precision `HHMMSS.FFFFFF`.
///
/// Microsecond cannot exceed `999_999`.
/// Instead, leap seconds can be represented by setting `second` to 60.
Expand All @@ -441,7 +441,7 @@ impl DicomTime {
6,
)))
}
/** Retrievies the hour from a time as a reference */
/** Retrieves the hour from a time as a reference */
pub fn hour(&self) -> &u8 {
match self {
DicomTime(DicomTimeImpl::Hour(h)) => h,
Expand All @@ -450,7 +450,7 @@ impl DicomTime {
DicomTime(DicomTimeImpl::Fraction(h, _, _, _, _)) => h,
}
}
/** Retrievies the minute from a time as a reference */
/** Retrieves the minute from a time as a reference */
pub fn minute(&self) -> Option<&u8> {
match self {
DicomTime(DicomTimeImpl::Hour(_)) => None,
Expand All @@ -459,7 +459,7 @@ impl DicomTime {
DicomTime(DicomTimeImpl::Fraction(_, m, _, _, _)) => Some(m),
}
}
/** Retrievies the minute from a time as a reference */
/** Retrieves the minute from a time as a reference */
pub fn second(&self) -> Option<&u8> {
match self {
DicomTime(DicomTimeImpl::Hour(_)) => None,
Expand All @@ -468,7 +468,7 @@ impl DicomTime {
DicomTime(DicomTimeImpl::Fraction(_, _, s, _, _)) => Some(s),
}
}
/** Retrievies the fraction of a second as a reference, if it has full (microsecond) precision. */
/** Retrieves the fraction of a second as a reference, if it has full (microsecond) precision. */
pub fn fraction(&self) -> Option<&u32> {
match self {
DicomTime(DicomTimeImpl::Hour(_)) => None,
Expand All @@ -480,7 +480,7 @@ impl DicomTime {
},
}
}
/** Retrievies the fraction of a second and it's precision from a time as a reference */
/** Retrieves the fraction of a second and it's precision from a time as a reference */
pub(crate) fn fraction_and_precision(&self) -> Option<(&u32, &u8)> {
match self {
DicomTime(DicomTimeImpl::Hour(_)) => None,
Expand Down Expand Up @@ -844,16 +844,7 @@ impl DicomTime {
DicomTime(DicomTimeImpl::Second(h, m, s)) => format!("{:02}{:02}{:02}", h, m, s),
DicomTime(DicomTimeImpl::Fraction(h, m, s, f, fp)) => {
let sfrac = (u32::pow(10, *fp as u32) + f).to_string();
format!(
"{:02}{:02}{:02}.{}",
h,
m,
s,
match f {
0 => "0",
_ => sfrac.get(1..).unwrap(),
}
)
format!("{:02}{:02}{:02}.{}", h, m, s, sfrac.get(1..).unwrap())
}
}
}
Expand Down Expand Up @@ -1159,10 +1150,26 @@ mod tests {
DicomTime::from_hmsf(7, 55, 1, 1, 5).unwrap().to_encoded(),
"075501.00001"
);
// any precision for zero is just one zero
// the number of trailing zeros always complies with precision
assert_eq!(
DicomTime::from_hmsf(9, 1, 1, 0, 2).unwrap().to_encoded(),
"090101.00"
);
assert_eq!(
DicomTime::from_hmsf(9, 1, 1, 0, 3).unwrap().to_encoded(),
"090101.000"
);
assert_eq!(
DicomTime::from_hmsf(9, 1, 1, 0, 4).unwrap().to_encoded(),
"090101.0000"
);
assert_eq!(
DicomTime::from_hmsf(9, 1, 1, 0, 5).unwrap().to_encoded(),
"090101.00000"
);
assert_eq!(
DicomTime::from_hmsf(9, 1, 1, 0, 6).unwrap().to_encoded(),
"090101.0"
"090101.000000"
);

// leap second allowed here
Expand All @@ -1178,7 +1185,7 @@ mod tests {
DicomTime::try_from(&NaiveTime::from_hms_micro_opt(16, 31, 59, 1_000_000).unwrap())
.unwrap()
.to_encoded(),
"163160.0",
"163160.000000",
);

// sub-second precision after leap second from NaiveTime is admitted
Expand All @@ -1189,6 +1196,38 @@ mod tests {
"163160.012345",
);


// time specifically with 0 microseconds
assert_eq!(
DicomTime::try_from(&NaiveTime::from_hms_micro_opt(16, 31, 59, 0).unwrap())
.unwrap()
.to_encoded(),
"163159.000000",
);

// specific date-time from chrono
let date_time: DateTime<_> = DateTime::<chrono::Utc>::from_naive_utc_and_offset(
NaiveDateTime::new(
NaiveDate::from_ymd_opt(2024, 8, 9).unwrap(),
NaiveTime::from_hms_opt(9, 9, 39).unwrap(),
),
chrono::Utc,
).with_timezone(&FixedOffset::east_opt(0).unwrap());
let dicom_date_time = DicomDateTime::try_from(&date_time).unwrap();
assert!(dicom_date_time.has_time_zone());
assert!(dicom_date_time.is_precise());
let dicom_time = dicom_date_time.time().unwrap();
assert_eq!(
dicom_time.fraction_and_precision(),
Some((&0, &6)),
);
assert_eq!(
dicom_date_time.to_encoded(),
"20240809090939.000000+0000"
);

// bad inputs

assert!(matches!(
DicomTime::from_hmsf(9, 1, 1, 1, 7),
Err(Error::FractionPrecisionRange { value: 7, .. })
Expand Down
9 changes: 9 additions & 0 deletions core/src/value/primitive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5079,6 +5079,15 @@ mod tests {
.unwrap(),
);
assert_eq!(val.calculate_byte_len(), 14);

// very precise date time, 0 microseconds
let dicom_date_time = DicomDateTime::from_date_and_time_with_time_zone(
DicomDate::from_ymd(2024, 8, 26).unwrap(),
DicomTime::from_hms_micro(19, 41, 38, 0).unwrap(),
FixedOffset::west_opt(0).unwrap(),
).unwrap();
let val = PrimitiveValue::from(dicom_date_time);
assert_eq!(val.calculate_byte_len(), 26);
}

#[test]
Expand Down