Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/date time helper methods #189

Draft
wants to merge 15 commits into
base: main
Choose a base branch
from

Conversation

bpeake-illuscio
Copy link
Contributor

@bpeake-illuscio bpeake-illuscio commented Mar 17, 2021

Opening this as a draft, but if you like the API, I think it's ready to be a full PR.

This PR adds several helper methods to the Date, Time, and Datetime types. The work I do involves manipulating DICOM dates and times pretty frequently, so I thought it might be nice to add some quality-of-life features to follow up on the groundwork of #171

Since not all values on a given [Type].Time field are valid due to low precision of the source values, I've added methods for the relevant time values that also report their presence.

Each type has also received a general method to easily check whether a value has at least some precision value.

An example using Datetime:

// This is a DT value like we would expect
dtString := "2020121012"

dt, err := ParseDatetime(dtString)
if err != nil {
	panic(err)
}

// Our Datetime value has some methods similar to time.Time's methods, but also
// returns presence information since not all DICOM datetimes contain all datetime
// components.
//
// Try to get the Day value. Our value included a day, so 'ok' will be true
if day, ok := dt.Day(); ok {
	fmt.Println("DAY VALUE   :", day)
}

// Try to get the Minute value. Because minutes are not included, 'ok' will be false
// and this will not print.
if minute, ok := dt.Minute(); ok {
	fmt.Println("MINUTE VALUE :", minute)
}

// We can also easily check if the value contains a certain precision:
hasMinutes := dt.HasPrecision(PrecisionMinutes)
fmt.Println("HAS MINUTES :", hasMinutes)

// Output:
// TIME VALUE  : 2020-12-10 12:00:00 +0000 +0000
// PRECISION   : HOURS
// NO OFFSET   : true
// DAY VALUE   : 10
// HAS MINUTES : false

A method has also been added to both the Date and Time types to combine a Date value and a Time value into a single Datetime value:

daString := "20200316"
tmString := "105434.123456"

daParsed, err := ParseDate(daString)
if err != nil {
	panic(err)
}

tmParsed, err := ParseTime(tmString)
if err != nil {
	panic(err)
}

datetime, err := daParsed.Combine(tmParsed, time.UTC)
if err != nil {
	panic(err)
}

fmt.Println("DCM    :", datetime.DCM())
fmt.Println("STRING :", datetime.String())

// Output:
// DCM    : 20200316105434.123456+0000
// STRING : 2020-03-16 10:54:34.123456 +00:00

Both #186 and #188 have been merged into this branch already.

@bpeake-illuscio
Copy link
Contributor Author

bpeake-illuscio commented Mar 26, 2021

I've just pushed an update to this followup that tweaks and adds a couple methods so that you can form a few common interfaces between the dcmtime types. For instance, you can now write a helper function like this:

// DCMTime is a common interface for dcmtime.Date, dcmtime.Time, and dcmtime.Datetime.
type DCMTime interface {
	GetTime() time.Time
	GetPrecision() dcmtime.PrecisionLevel
	DCM() string
}

func InspectDICOMTimeVal(value DCMTime) error {
	// Do something with this value
	return nil
}

The main addition here is adding a GetTime() and GetPrecision() method to each of the dcmtime types. I've been writing some code where a single code path could be used with an interface like this, so I decided it was worth adding in. Callers could do this though wrappers on their own, but having it right out of the box is kind of nice, IMO.

I realize that I am kind of bloating this PR, so let me know if you would like me to try and break this up into smaller PRs.
Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants