Skip to content

Commit

Permalink
Me/dpc 4280 patient entity converter bug (#2278)
Browse files Browse the repository at this point in the history
## 🎫 Ticket

https://jira.cms.gov/browse/DPC-4280

## 🛠 Changes

Fixes bug in the `PatientEntity.toLocalDate()` method that caused it to
fail when given a date close to midnight.

## ℹ️ Context

If you passed a Date between 11pm and midnight to the
`PatientEntity.toLocalDate()` it would mistakenly return a `LocalDate`
for the next day. This was because in the conversion we were assuming
UTC time, and we are actually located in EST.

As for why the previous process failed, consider a `Date` of "1/1/2024
at 11:30pm EST". Converting that to UTC we get "1/2/2024 12:30am UTC".
Then converting it to a LocalDate, which has no concept of time zone, we
get "1/2/2024" when we were expecting "1/1/2024".

In the new version we use the system default time zone.

## 🧪 Validation

Created new test to verify results.
  • Loading branch information
MEspositoE14s authored Sep 25, 2024
1 parent b948299 commit 9214fe4
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import java.time.LocalDate;
import java.time.ZoneOffset;
import java.time.*;
import java.util.Date;
import java.util.List;
import java.util.Objects;
Expand Down Expand Up @@ -144,14 +143,15 @@ public int hashCode() {

@SuppressWarnings("JdkObsolete") // Date class is used by FHIR stu3 Patient model
public static LocalDate toLocalDate(Date date) {
return date.toInstant()
.atZone(ZoneOffset.UTC)
.toLocalDate();
// LocalDateTime has no concept of time zone, so the best we can do is guess based on the system default.
// We should really avoid using it where possible.
return ZonedDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault())
.toLocalDate();
}

@SuppressWarnings("JdkObsolete") // Date class is used by FHIR stu3 Patient model
public static Date fromLocalDate(LocalDate date) {
return Date.from(date.atStartOfDay().toInstant(ZoneOffset.UTC));
return Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant());
}


Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
package gov.cms.dpc.common.entities;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import org.junit.jupiter.api.Test;

import java.time.*;
import java.util.*;

import static org.junit.jupiter.api.Assertions.*;

public class PatientEntityTest {

Expand Down Expand Up @@ -83,4 +80,19 @@ public void testLocalDateFunctions() {
assertNotNull(utilityDate);
assertEquals(localDate, convertedDate);
}

@Test
public void testToLocalDateHandlesTimeZoneChange() {
// A previous version of toLocalDate failed when converting a date/time close to midnight because it converted
// to UTC before getting the LocalDate. Make sure that's no longer the case.

// 1/1/2024 11:55pm EST
Date testDate = new Calendar.Builder()
.setDate(2024, 0, 1)
.setTimeOfDay(23, 55, 0).build().getTime();

LocalDate resultLocalDate = PatientEntity.toLocalDate(testDate);

assertEquals(LocalDate.of(2024, 1, 1), resultLocalDate);
}
}

0 comments on commit 9214fe4

Please sign in to comment.