All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.projecthusky.common.utils.time.Hl7Dtm Maven / Gradle / Ivy

package org.projecthusky.common.utils.time;

import ca.uhn.hl7v2.model.DataTypeException;
import ca.uhn.hl7v2.model.primitive.CommonTS;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;

import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.EnumMap;
import java.util.Map;
import java.util.Objects;

/**
 * HL7 timestamps (data type DTM) with particular precision, normalized to UTC.
 *
 * 

Original code from IPF (https://github.com/oehf/ipf) under Apache 2.0 licence. * * @author Dmytro Rud */ public class Hl7Dtm { /** * The enumeration of possible precisions. */ public enum Precision { YEAR, MONTH, DAY, HOUR, MINUTE, SECOND, FRAC_SECOND } /** * Formatters for the different patterns. It is only used when converting to HL7 DTM format, not for parsing. */ private static final Map<@NonNull Precision, @NonNull DateTimeFormatter> FORMATTERS = new EnumMap<>(Precision.class); static { FORMATTERS.put(Precision.YEAR, DateTimeFormatter.ofPattern("yyyy")); FORMATTERS.put(Precision.MONTH, DateTimeFormatter.ofPattern("yyyyMM")); FORMATTERS.put(Precision.DAY, DateTimeFormatter.ofPattern("yyyyMMdd")); FORMATTERS.put(Precision.HOUR, DateTimeFormatter.ofPattern("yyyyMMddHHxxxx")); FORMATTERS.put(Precision.MINUTE, DateTimeFormatter.ofPattern("yyyyMMddHHmmxxxx")); FORMATTERS.put(Precision.SECOND, DateTimeFormatter.ofPattern("yyyyMMddHHmmssxxxx")); FORMATTERS.put(Precision.FRAC_SECOND, DateTimeFormatter.ofPattern("yyyyMMddHHmmss.SSSSxxxx")); } /** * Timestamp. */ private OffsetDateTime dateTime; /** * Precision of the timestamp (smallest present element, e.g. YEAR for "1980"). */ private Precision precision; /** * Initializes a {@link Hl7Dtm} object with the given datetime and precision. */ public Hl7Dtm(@NonNull final OffsetDateTime dateTime, @NonNull final Precision precision) { this.dateTime = Objects.requireNonNull(dateTime); this.precision = Objects.requireNonNull(precision); } /** * Creates a {@link Hl7Dtm} object from the given string. * @param s String of the pattern YYYY[MM[DD[HH[MM[SS[.S[S[S[S]]]]]]]]][+/-ZZZZ]. Milliseconds will * be ignored. * @return a {@link Hl7Dtm} object. * @throws IllegalArgumentException if the DTM string is invalid. */ public static Hl7Dtm fromHl7(@NonNull final String s) { var pos = Math.max(Objects.requireNonNull(s).indexOf('-'), s.indexOf('+')); var len = (pos >= 0) ? pos : s.length(); // determine precision Precision precision; if (len >= 16 && len <= 19) { precision = Precision.FRAC_SECOND; } else if (len == 14) { precision = Precision.SECOND; } else if (len == 12) { precision = Precision.MINUTE; } else if (len == 10) { precision = Precision.HOUR; } else if (len == 8) { precision = Precision.DAY; } else if (len == 6) { precision = Precision.MONTH; } else if (len == 4) { precision = Precision.YEAR; } else { throw new IllegalArgumentException("The passed HL7 DTM is invalid"); } // parse timestamp return new Hl7Dtm(Objects.requireNonNull(toOffsetDateTime(s)), precision); } /** * * @return a {@link Hl7Dtm} with the current date-time in second precision. */ public static Hl7Dtm now() { return new Hl7Dtm(OffsetDateTime.now(), Precision.SECOND); } /** * Creates a {@link OffsetDateTime} object from the given string. * @param s * String of the pattern YYYY[MM[DD[HH[MM[SS[.S[S[S[S]]]]]]]]][+/-ZZZZ]. * Milliseconds will be ignored. * @return * a {@link OffsetDateTime} object, or null if the parameter is {@code null} or empty. * @throws IllegalArgumentException if the DTM string is invalid. */ public static OffsetDateTime toOffsetDateTime(@NonNull String s) { if (s.isBlank()) { throw new IllegalArgumentException("The passed HL7 DTM is empty"); } var pos = Math.max(s.indexOf('-'), s.indexOf('+')); // default time zone is UTC if (pos < 0) { s += "+0000"; } // parse timestamp final CommonTS ts; try { ts = new CommonTS(s); } catch (final DataTypeException e) { throw new IllegalArgumentException("Unparsable HL7 DTM format", e); } return OffsetDateTime.of( ts.getYear(), (ts.getMonth() == 0) ? 1 : ts.getMonth(), (ts.getDay() == 0) ? 1 : ts.getDay(), ts.getHour(), ts.getMinute(), ts.getSecond(), (int) Math.floor(ts.getFractSecond() * 1_000_000_000), ZoneOffset.ofHoursMinutes( ts.getGMTOffset() / 100, ts.getGMTOffset() % 100 ) ); } public void setDateTime(@NonNull final OffsetDateTime dateTime) { this.dateTime = Objects.requireNonNull(dateTime); } @NonNull public OffsetDateTime getDateTime() { return this.dateTime; } public void setPrecision(@NonNull final Precision precision) { this.precision = Objects.requireNonNull(precision); } @NonNull public Precision getPrecision() { return this.precision; } @NonNull public Instant toInstant() { return this.dateTime.toInstant(); } @NonNull public String toHl7() { return FORMATTERS.get(getPrecision()).format(getDateTime()); } /** * Two HL7 timestamps are equal when they have the same values in the relevant fields * (i.e. in the ones covered by the precision). */ @Override public boolean equals(@Nullable final Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } var timestamp = (Hl7Dtm) o; return Objects.equals(this.toHl7(), timestamp.toHl7()); } @Override public int hashCode() { return Objects.hash(dateTime, precision); } @Override public String toString() { return "Timestamp(" + "dateTime=" + dateTime + ", precision=" + precision + ')'; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy