Have any CDRs (EHRbase, EHRserver, Better, etc) implemented persistence of partial DV_DATE, DV_TIME or DV_DATE_TIME? For example a partial DV_DATE would be just a year, or a year and a month without the day.
If so, how did you handle the practical persistence in terms of types in database implementations, programming languages and query engines? Not to mention all the complications relating to the magnitude (what is it for a DV_DATE_TIME 2026? 2026-01-01?) and all the functions of Iso8601_date et al?
Explanations and/or code examples would be very welcome
Iâm sure someone in the community has some knowledge about this?
Also, if I and my CDR vendor DIPS (@bna) are wondering about this, maybe the Date Time Package of the specs should be more specific about how to do this? @SEC / @SEC-experts thoughts?
I am not sure I understand your question entirely, but for what I get is that you are looking for implementation nuances around comparing dates when persisted instances are partial.
programming languages also typically assume complete temporal values.
So the problem that you point out is that a partial temporal is not a concrete instant.
In our implementation we store it as text (json/xml), and depending on the use case use, it means a sort of range (when comparing values during a database query), or a plain narrative string (in forms, view), and in some situation the nearest date instance (e.g. 2026-01-01). But you might be right, this is not solid (enough), some assumptions are being takenâŚ
How do you think the spec should be more specific? What sort of information would be meaningful to add to that specification section, without diving in particular implementations aspects?
EhrBase and Better both support partial dateTimes like â1994â or â1988-03â - we used an example in the IHE Plugathon testing that checks this. Not sure about Cadasto @sebastian.iancu or Atomik ? @pablo
I donât know about the internal representations or how comparisons work.
Iâm also wondering if youâre looking for specific implementations of for a general set of rules at the spec level like âhow this should work in openEHRâ? @siljelb
Just a small comment: if we use Date or DateTime types at the database level, then the values should be valid full date and full date time. The data type implies the full data is provided, so partial dates wonât be accepted (in general). When storing strings you lose all the âdateâ functions and you might need to implement them yourself, which is basically like implementing your own data type at the database level. The next option is to have alternative fields: normal Date for full dates and strings or ranges for partial dates (as Sebastian mentioned a partial date is in fact a range). An alternative to string storage is using integers, but again you need to implement logic to interpret the int number, validate it, and have specific date functions over the int. There is no elegant solution, everything is a hack because openEHR specified this differently than how 99.99% of technologies actually work.
Oh, I forgot one option: having a normal date/datetime stored and an extra field for the precision, so you can store a full valid date, but when querying and comparing, youâll process that based on the precision, which will tell you something like âuse just the year and month from this dateâ, so 1991-05-07 should be interpreted as 1991-05, which can be interpreted as 1991-05-01..1991-05-31 (a range of dates).
In ehrbase Partial date/time values (e.g. "2023", "1985-06") are stored in the DB as two columns: the original ISO 8601 string preserving the actual precision, and a pre-computed long magnitude representing seconds since 0001-01-01T00:00:00Z â as defined by the openEHR spec, where DV_DATE and DV_DATE_TIME inherit from DV_QUANTIFIED via DV_TEMPORAL and DV_ABSOLUTE_QUANTITY, and ordering is defined as order by magnitude.
The magnitude is computed using a floor strategy: any missing fields are filled with their minimum values â month defaults to 1, day to 1, time components to 00:00:00, and timezone to UTC. AQL comparison operators (<, >, =, between) then map directly to integer comparisons on the magnitude column, with the implication that equality on mixed-precision values is semantically approximate â "2023" and "2023-01-01" produce identical magnitudes despite having different precision.
Thank you all for your responses, and particularly to @stefanspiska for the detailed explanations on your two columns as well as how you handle the magnitude. Using a floor strategy makes total sense.
Itâs really both. Regarding the specs, like when working with definitions in archetypes, itâs a good rule of thumb that if modelers/implementers are unsure about how to use an archetype or a part of the spec, it may be because itâs too vague
I have a few follow-up questions that I hope you all can answer as well:
Do you also use the accuracy (DV_DURATION) from DV_TEMPORAL to specify the level of accuracy in the persisted datetime? For example 0001 for "2023" when the specific year is meant, or 0001-01-01 for "2023-01-01" when specifically the first of january is meant? (is this what you meant in your second post, @pablo?)
DV_DATE_TIME inherits Iso8601_date_time, where functions year(), month(), day() etc are mandatory. These are specified to return 0 âif not presentâ (Foundation Types - Iso8601_date_time Class). Is this intended to be 0 (number zero) or ďż˝ (NULL)? If the former, how do you differentiate between hours/minutes/seconds ânot presentâ vs explicitly 0 (zero)?
When handling partial dates, times or datetimes in programming languages, do you use custom classes or some other tricks to avoid the issue that @sebastian.iancu points out here?
As I understand it, accuracy measures a different property: certainty
With partial dates you are dealing with certainty implicitly, so for me itâs a matter of precision more than certainty.
If you check the temporal types (Data Types Information Model), the accuracy is DV_DURATION, so it can be something like P30D, so if you want to represent 2015-05-XX I think you canât do it with the accuracy. From your example: 0001 isnât a valid duration expression, seems more like a mask, see below.
Just as an example, the concept of precision on a date expression, is like a data mask, so you can say precision=month, which means YYYY-MM-XX (XX is missing data), and you can see it as a 1111-11-00 mask, so you can store anything in the data that you donât know, to keep the datatype to be valid in the underlying technology (programming language, database, query language, exchange format) like 2026-04-01, but when consumed externally it should be interpreted as value && mask which is effectively 2026-04.
The problem is the spec expects partial dates to be supported by the underlying technology, it isnât the case and wonât be anytime soon, so at the implementation level you need to add the precision concept even if thatâs not in the spec explicitly, but it allows implements the concept of partial dates. The only types that have precision are DV_QUANTITY and DV_PROPORTION.
A small note about temporal types and magnitude: by the spec the magnitude is a method (calculated) not part of the state of the temporal types, so itâs not required to store it. Though we store it too to make comparisons and calculations on dates and times.