diff --git a/fhirpath/src/main/java/au/csiro/pathling/sql/dates/datetime/DateTimeUDFRegistrar.java b/fhirpath/src/main/java/au/csiro/pathling/sql/dates/datetime/DateTimeUDFRegistrar.java index 3f8444d750..b195325d9b 100644 --- a/fhirpath/src/main/java/au/csiro/pathling/sql/dates/datetime/DateTimeUDFRegistrar.java +++ b/fhirpath/src/main/java/au/csiro/pathling/sql/dates/datetime/DateTimeUDFRegistrar.java @@ -33,7 +33,6 @@ protected void registerUDFs(final UDFRegistrar udfRegistrar) { .register(new DateTimeGreaterThanFunction()) .register(new DateTimeGreaterThanOrEqualToFunction()) .register(new DateTimeLessThanFunction()) - .register(new DateTimeLessThanOrEqualToFunction()) - .register(new NormalizeDateTimeFunction()); + .register(new DateTimeLessThanOrEqualToFunction()); } } diff --git a/fhirpath/src/main/java/au/csiro/pathling/sql/dates/time/NormalizeTimeFunction.java b/fhirpath/src/main/java/au/csiro/pathling/sql/dates/time/NormalizeTimeFunction.java new file mode 100644 index 0000000000..cc9db27b0a --- /dev/null +++ b/fhirpath/src/main/java/au/csiro/pathling/sql/dates/time/NormalizeTimeFunction.java @@ -0,0 +1,39 @@ +package au.csiro.pathling.sql.dates.time; + +import au.csiro.pathling.sql.udf.SqlFunction1; +import java.time.LocalTime; +import java.time.temporal.ChronoUnit; +import java.util.Objects; +import org.apache.spark.sql.types.DataType; +import org.apache.spark.sql.types.DataTypes; + +/** + * A function for normalizing a time string to a long (nanoseconds) for comparison purposes. + *

+ * Truncates the precision of the time to milliseconds, as this is the highest precision supported + * by FHIR. + */ +public class NormalizeTimeFunction implements SqlFunction1 { + + private static final long serialVersionUID = 4117774962772392910L; + + public static final String FUNCTION_NAME = "normalize_time"; + + @Override + public String getName() { + return FUNCTION_NAME; + } + + @Override + public DataType getReturnType() { + return DataTypes.LongType; + } + + @Override + public Long call(final String timeString) throws Exception { + final LocalTime time = Objects.requireNonNull( + LocalTime.parse(timeString)); + return time.truncatedTo(ChronoUnit.MILLIS).toNanoOfDay(); + } + +} diff --git a/fhirpath/src/main/java/au/csiro/pathling/sql/misc/MiscUDFRegistrar.java b/fhirpath/src/main/java/au/csiro/pathling/sql/misc/MiscUDFRegistrar.java index 18c5c79909..f16528f6fd 100644 --- a/fhirpath/src/main/java/au/csiro/pathling/sql/misc/MiscUDFRegistrar.java +++ b/fhirpath/src/main/java/au/csiro/pathling/sql/misc/MiscUDFRegistrar.java @@ -16,6 +16,8 @@ */ package au.csiro.pathling.sql.misc; +import au.csiro.pathling.sql.dates.datetime.NormalizeDateTimeFunction; +import au.csiro.pathling.sql.dates.time.NormalizeTimeFunction; import au.csiro.pathling.sql.udf.AbstractUDFRegistrar; /** @@ -27,6 +29,8 @@ public class MiscUDFRegistrar extends AbstractUDFRegistrar { protected void registerUDFs(final UDFRegistrar udfRegistrar) { udfRegistrar .register(new CodingToLiteral()) - .register(new TemporalDifferenceFunction()); + .register(new TemporalDifferenceFunction()) + .register(new NormalizeDateTimeFunction()) + .register(new NormalizeTimeFunction()); } } diff --git a/fhirpath/src/test/java/au/csiro/pathling/views/FhirViewTest.java b/fhirpath/src/test/java/au/csiro/pathling/views/FhirViewTest.java index f504950215..b4612e10e8 100644 --- a/fhirpath/src/test/java/au/csiro/pathling/views/FhirViewTest.java +++ b/fhirpath/src/test/java/au/csiro/pathling/views/FhirViewTest.java @@ -18,6 +18,7 @@ import au.csiro.pathling.encoders.datatypes.DecimalCustomCoder; import au.csiro.pathling.io.source.DataSource; import au.csiro.pathling.sql.dates.datetime.NormalizeDateTimeFunction; +import au.csiro.pathling.sql.dates.time.NormalizeTimeFunction; import au.csiro.pathling.terminology.TerminologyServiceFactory; import au.csiro.pathling.test.SpringBootUnitTest; import ca.uhn.fhir.context.FhirContext; @@ -142,6 +143,8 @@ class Expect implements ResultExpectation { public static final String FHIR_DATE_TIME_PATTERN = "^([0-9]([0-9]([0-9][1-9]|[1-9]0)|[1-9]00)|" + "[1-9]000)(-(0[1-9]|1[0-2])(-(0[1-9]|[1-2][0-9]|3[0-1])(T([01][0-9]|2[0-3]):[0-5][0-9]:" + "([0-5][0-9]|60)(\\.[0-9]{1,9})?)?)?(Z|(\\+|-)((0[0-9]|1[0-3]):[0-5][0-9]|14:00)?)?)?$"; + public static final String FHIR_TIME_PATTERN = "^([01][0-9]|2[0-3]):[0-5][0-9]:([0-5][0-9]|60)" + + "(\\.[0-9]+)?$"; Path expectedJson; List expectedColumns; @@ -166,6 +169,9 @@ public void expectResult(@Nonnull final Dataset rowDataset) { return when( col(field.name()).rlike(FHIR_DATE_TIME_PATTERN), callUDF(NormalizeDateTimeFunction.FUNCTION_NAME, col(field.name())) + ).when( + col(field.name()).rlike(FHIR_TIME_PATTERN), + callUDF(NormalizeTimeFunction.FUNCTION_NAME, col(field.name())) ).otherwise(col(field.name())).alias(field.name()); } else { // Add the field to the selection without alteration.