Skip to content

Commit

Permalink
feat: Create StartDate and EndDate types [DHIS2-16019] (#17454)
Browse files Browse the repository at this point in the history
  • Loading branch information
enricocolasante committed May 30, 2024
1 parent 55ea990 commit 24a0872
Show file tree
Hide file tree
Showing 14 changed files with 462 additions and 98 deletions.
60 changes: 58 additions & 2 deletions dhis-2/dhis-api/src/main/java/org/hisp/dhis/util/DateUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.temporal.ChronoUnit;
import java.util.Calendar;
Expand Down Expand Up @@ -109,6 +111,9 @@ public class DateUtils {
ObjectArrays.concat(
SUPPORTED_DATE_ONLY_PARSERS, SUPPORTED_DATE_TIME_FORMAT_PARSERS, DateTimeParser.class);

private static final DateTimeFormatter ONLY_DATE_FORMATTER =
new DateTimeFormatterBuilder().append(null, SUPPORTED_DATE_ONLY_PARSERS).toFormatter();

private static final DateTimeFormatter DATE_FORMATTER =
new DateTimeFormatterBuilder().append(null, SUPPORTED_DATE_FORMAT_PARSERS).toFormatter();

Expand Down Expand Up @@ -137,6 +142,9 @@ public class DateUtils {
private static final DateTimeFormatter LONG_DATE_FORMAT =
DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss");

private static final DateTimeFormatter LONG_DATE_FORMAT_WITH_MILLIS =
DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");

private static final DateTimeFormatter HTTP_DATE_FORMAT =
DateTimeFormat.forPattern("EEE, dd MMM yyyy HH:mm:ss 'GMT'").withLocale(Locale.ENGLISH);

Expand Down Expand Up @@ -182,6 +190,16 @@ public static String getLongGmtDateString(Date date) {
return date != null ? TIMESTAMP_UTC_TZ_FORMAT.print(new DateTime(date)) : null;
}

/**
* Formats a Date to the format yyyy-MM-dd HH:mm:ss.SSS.
*
* @param date the Date to parse.
* @return A formatted date string.
*/
public static String toLongDateWithMillis(Date date) {
return date != null ? LONG_DATE_FORMAT_WITH_MILLIS.print(new DateTime(date)) : null;
}

/**
* Formats a Date to the format yyyy-MM-dd HH:mm:ss.
*
Expand Down Expand Up @@ -652,8 +670,8 @@ public static String getPrettyInterval(Date start, Date end) {
}

/**
* Parses the given string into a Date using the supported date formats. Returns null if the
* string cannot be parsed.
* Parses the given string into a Date using the supported date formats. Add time at the beginning
* of the day if no time was provided. Returns null if the string cannot be parsed.
*
* @param dateString the date string.
* @return a date.
Expand All @@ -662,6 +680,44 @@ public static Date parseDate(final String dateString) {
return safeParseDateTime(dateString, DATE_FORMATTER);
}

/**
* Parses the given string into a Date using the supported date formats. Add time at the end of
* the day if no time was provided. Returns null if the string cannot be parsed.
*
* @param dateString the date string.
* @return a date.
*/
public static Date parseDateEndOfTheDay(String dateString) {
if (StringUtils.isEmpty(dateString)) {
return null;
}

try {
Date date = safeParseDateTime(dateString, ONLY_DATE_FORMATTER);
LocalDateTime localDateTime =
LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()).with(LocalTime.MAX);
return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
} catch (IllegalArgumentException e) {
// dateString has time defined
}
return safeParseDateTime(dateString, DATE_FORMATTER);
}

/**
* Parses the given string into a Date using the supported date formats. Returns null if the
* string cannot be parsed.
*
* @param dateString the date string.
* @return a date or null
*/
public static Date safeParseDate(String dateString) {
try {
return safeParseDateTime(dateString, DATE_FORMATTER);
} catch (Exception e) {
return null;
}
}

/**
* Create a TimeStamp with Time Zone from an input Date. This can be used as SQL value {@link
* java.sql.Types#TIMESTAMP_WITH_TIMEZONE}
Expand Down
47 changes: 47 additions & 0 deletions dhis-2/dhis-api/src/main/java/org/hisp/dhis/util/ObjectUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,13 @@

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;
import org.apache.commons.lang3.StringUtils;

/**
Expand Down Expand Up @@ -168,4 +171,48 @@ public static <T, U extends RuntimeException> T throwIfNull(T object, Supplier<U

return object;
}

/**
* If object is null return null, otherwise return function applied to object.
*
* @param object to check.
* @param <U> the function return type.
* @param <T> the object type.
* @param function the function to be applied to non-null object.
*/
public static <T, U> U applyIfNotNull(T object, Function<T, U> function) {
if (object == null) {
return null;
}

return function.apply(object);
}

/**
* Util method that always returns a new Set, either instantiated from a non-null Set passed as an
* argument, or if a null arg is passed then returning an empty Set. This helps reduce possible
* NullPointerExceptions when trying to instantiate a Set with a null value.
*
* @param set
* @return
* @param <T>
*/
@Nonnull
public static <T> Set<T> copyOf(Set<T> set) {
return set != null ? new HashSet<>(set) : new HashSet<>();
}

/**
* Util method that always returns a new List, either instantiated from a non-null Set passed as
* an argument, or if a null arg is passed then returning an empty Set. This helps reduce possible
* NullPointerExceptions when trying to instantiate a Set with a null value.
*
* @param list
* @return
* @param <T>
*/
@Nonnull
public static <T> List<T> copyOf(List<T> list) {
return list != null ? new ArrayList<>(list) : new ArrayList<>();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@
import org.hisp.dhis.webapi.controller.event.mapper.TrackedEntityCriteriaMapper;
import org.hisp.dhis.webapi.controller.event.webrequest.OrderCriteria;
import org.hisp.dhis.webapi.controller.event.webrequest.TrackedEntityInstanceCriteria;
import org.hisp.dhis.webapi.webdomain.EndDateTime;
import org.hisp.dhis.webapi.webdomain.StartDateTime;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;

Expand Down Expand Up @@ -146,17 +148,17 @@ void verifyCriteriaMapping() {
criteria.setProgram(programA.getUid());
criteria.setProgramStatus(ProgramStatus.ACTIVE);
criteria.setFollowUp(true);
criteria.setLastUpdatedStartDate(getDate(2019, 1, 1));
criteria.setLastUpdatedEndDate(getDate(2020, 1, 1));
criteria.setLastUpdatedStartDate(StartDateTime.of("2019-01-01"));
criteria.setLastUpdatedEndDate(EndDateTime.of("2020-01-01"));
criteria.setLastUpdatedDuration("20");
criteria.setProgramEnrollmentStartDate(getDate(2019, 8, 5));
criteria.setProgramEnrollmentEndDate(getDate(2020, 8, 5));
criteria.setProgramIncidentStartDate(getDate(2019, 5, 5));
criteria.setProgramIncidentEndDate(getDate(2020, 5, 5));
criteria.setProgramEnrollmentStartDate(StartDateTime.of("2019-08-05"));
criteria.setProgramEnrollmentEndDate(EndDateTime.of("2020-08-05"));
criteria.setProgramIncidentStartDate(StartDateTime.of("2019-05-05"));
criteria.setProgramIncidentEndDate(EndDateTime.of("2020-05-05"));
criteria.setTrackedEntityType(trackedEntityTypeA.getUid());
criteria.setEventStatus(EventStatus.COMPLETED);
criteria.setEventStartDate(getDate(2019, 7, 7));
criteria.setEventEndDate(getDate(2020, 7, 7));
criteria.setEventStartDate(StartDateTime.of("2019-07-07"));
criteria.setEventEndDate(EndDateTime.of("2020-07-07"));
criteria.setAssignedUserMode(AssignedUserSelectionMode.PROVIDED);
criteria.setAssignedUser(userIds);
criteria.setSkipMeta(true);
Expand Down Expand Up @@ -195,18 +197,23 @@ void verifyCriteriaMapping() {
assertThat(queryParams.isTotalPages(), is(false));
assertThat(queryParams.getProgramStatus(), is(ProgramStatus.ACTIVE));
assertThat(queryParams.getFollowUp(), is(true));
assertThat(queryParams.getLastUpdatedStartDate(), is(criteria.getLastUpdatedStartDate()));
assertThat(queryParams.getLastUpdatedEndDate(), is(criteria.getLastUpdatedEndDate()));
assertThat(
queryParams.getProgramEnrollmentStartDate(), is(criteria.getProgramEnrollmentStartDate()));
queryParams.getLastUpdatedStartDate(), is(criteria.getLastUpdatedStartDate().toDate()));
assertThat(queryParams.getLastUpdatedEndDate(), is(criteria.getLastUpdatedEndDate().toDate()));
assertThat(
queryParams.getProgramEnrollmentEndDate(), is(criteria.getProgramEnrollmentEndDate()));
queryParams.getProgramEnrollmentStartDate(),
is(criteria.getProgramEnrollmentStartDate().toDate()));
assertThat(
queryParams.getProgramIncidentStartDate(), is(criteria.getProgramIncidentStartDate()));
assertThat(queryParams.getProgramIncidentEndDate(), is(criteria.getProgramIncidentEndDate()));
queryParams.getProgramEnrollmentEndDate(),
is(criteria.getProgramEnrollmentEndDate().toDate()));
assertThat(
queryParams.getProgramIncidentStartDate(),
is(criteria.getProgramIncidentStartDate().toDate()));
assertThat(
queryParams.getProgramIncidentEndDate(), is(criteria.getProgramIncidentEndDate().toDate()));
assertThat(queryParams.getEventStatus(), is(EventStatus.COMPLETED));
assertThat(queryParams.getEventStartDate(), is(criteria.getEventStartDate()));
assertThat(queryParams.getEventEndDate(), is(criteria.getEventEndDate()));
assertThat(queryParams.getEventStartDate(), is(criteria.getEventStartDate().toDate()));
assertThat(queryParams.getEventEndDate(), is(criteria.getEventEndDate().toDate()));
assertThat(queryParams.getAssignedUserSelectionMode(), is(AssignedUserSelectionMode.PROVIDED));
assertTrue(queryParams.getAssignedUsers().stream().anyMatch(u -> u.equals(userId1)));
assertTrue(queryParams.getAssignedUsers().stream().anyMatch(u -> u.equals(userId2)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

import static org.apache.commons.lang3.BooleanUtils.toBooleanDefaultIfNull;
import static org.hisp.dhis.common.OrganisationUnitSelectionMode.ALL;
import static org.hisp.dhis.util.ObjectUtils.applyIfNotNull;
import static org.hisp.dhis.webapi.controller.event.mapper.OrderParamsHelper.toOrderParams;

import java.util.Date;
Expand All @@ -55,6 +56,8 @@
import org.hisp.dhis.user.User;
import org.hisp.dhis.webapi.controller.event.webrequest.OrderCriteria;
import org.hisp.dhis.webapi.controller.event.webrequest.tracker.TrackerEnrollmentCriteria;
import org.hisp.dhis.webapi.webdomain.EndDateTime;
import org.hisp.dhis.webapi.webdomain.StartDateTime;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

Expand Down Expand Up @@ -200,12 +203,12 @@ public ProgramInstanceQueryParams getFromUrl(
return getFromUrl(
TextUtils.splitToSet(trackerEnrollmentCriteria.getOrgUnit(), TextUtils.SEMICOLON),
trackerEnrollmentCriteria.getOuMode(),
trackerEnrollmentCriteria.getUpdatedAfter(),
applyIfNotNull(trackerEnrollmentCriteria.getUpdatedAfter(), StartDateTime::toDate),
trackerEnrollmentCriteria.getUpdatedWithin(),
trackerEnrollmentCriteria.getProgram(),
trackerEnrollmentCriteria.getProgramStatus(),
trackerEnrollmentCriteria.getEnrolledAfter(),
trackerEnrollmentCriteria.getEnrolledBefore(),
applyIfNotNull(trackerEnrollmentCriteria.getEnrolledAfter(), StartDateTime::toDate),
applyIfNotNull(trackerEnrollmentCriteria.getEnrolledBefore(), EndDateTime::toDate),
trackerEnrollmentCriteria.getTrackedEntityType(),
trackerEnrollmentCriteria.getTrackedEntity(),
trackerEnrollmentCriteria.getFollowUp(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
import static org.apache.commons.lang3.BooleanUtils.toBooleanDefaultIfNull;
import static org.apache.commons.lang3.StringUtils.isNotEmpty;
import static org.hisp.dhis.trackedentity.TrackedEntityInstanceQueryParams.OrderColumn.findColumn;
import static org.hisp.dhis.util.ObjectUtils.applyIfNotNull;
import static org.hisp.dhis.webapi.controller.event.mapper.OrderParamsHelper.toOrderParams;

import java.util.Date;
Expand Down Expand Up @@ -63,6 +64,8 @@
import org.hisp.dhis.webapi.controller.event.webrequest.TrackedEntityInstanceCriteria;
import org.hisp.dhis.webapi.controller.event.webrequest.tracker.TrackerTrackedEntityCriteria;
import org.hisp.dhis.webapi.controller.event.webrequest.tracker.mapper.TrackerTrackedEntityCriteriaMapper;
import org.hisp.dhis.webapi.webdomain.EndDateTime;
import org.hisp.dhis.webapi.webdomain.StartDateTime;
import org.mapstruct.factory.Mappers;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
Expand Down Expand Up @@ -113,12 +116,16 @@ public TrackedEntityInstanceQueryParams map(TrackedEntityInstanceCriteria criter
TrackedEntityInstanceQueryParams params = new TrackedEntityInstanceQueryParams();

final Date programEnrollmentStartDate =
ObjectUtils.firstNonNull(
criteria.getProgramEnrollmentStartDate(), criteria.getProgramStartDate());
applyIfNotNull(
ObjectUtils.firstNonNull(
criteria.getProgramEnrollmentStartDate(), criteria.getProgramStartDate()),
StartDateTime::toDate);

final Date programEnrollmentEndDate =
ObjectUtils.firstNonNull(
criteria.getProgramEnrollmentEndDate(), criteria.getProgramEndDate());
applyIfNotNull(
ObjectUtils.firstNonNull(
criteria.getProgramEnrollmentEndDate(), criteria.getProgramEndDate()),
EndDateTime::toDate);

User user = currentUserService.getCurrentUser();

Expand Down Expand Up @@ -180,18 +187,22 @@ public TrackedEntityInstanceQueryParams map(TrackedEntityInstanceCriteria criter
.setProgramStage(validateProgramStage(criteria, program))
.setProgramStatus(criteria.getProgramStatus())
.setFollowUp(criteria.getFollowUp())
.setLastUpdatedStartDate(criteria.getLastUpdatedStartDate())
.setLastUpdatedEndDate(criteria.getLastUpdatedEndDate())
.setLastUpdatedStartDate(
applyIfNotNull(criteria.getLastUpdatedStartDate(), StartDateTime::toDate))
.setLastUpdatedEndDate(
applyIfNotNull(criteria.getLastUpdatedEndDate(), EndDateTime::toDate))
.setLastUpdatedDuration(criteria.getLastUpdatedDuration())
.setProgramEnrollmentStartDate(programEnrollmentStartDate)
.setProgramEnrollmentEndDate(programEnrollmentEndDate)
.setProgramIncidentStartDate(criteria.getProgramIncidentStartDate())
.setProgramIncidentEndDate(criteria.getProgramIncidentEndDate())
.setProgramIncidentStartDate(
applyIfNotNull(criteria.getProgramIncidentStartDate(), StartDateTime::toDate))
.setProgramIncidentEndDate(
applyIfNotNull(criteria.getProgramIncidentEndDate(), EndDateTime::toDate))
.setTrackedEntityType(validateTrackedEntityType(criteria))
.setOrganisationUnitMode(criteria.getOuMode())
.setEventStatus(criteria.getEventStatus())
.setEventStartDate(criteria.getEventStartDate())
.setEventEndDate(criteria.getEventEndDate())
.setEventStartDate(applyIfNotNull(criteria.getEventStartDate(), StartDateTime::toDate))
.setEventEndDate(applyIfNotNull(criteria.getEventEndDate(), EndDateTime::toDate))
.setAssignedUserSelectionMode(criteria.getAssignedUserMode())
.setAssignedUsers(criteria.getAssignedUsers())
.setTrackedEntityInstanceUids(criteria.getTrackedEntityInstances())
Expand Down
Loading

0 comments on commit 24a0872

Please sign in to comment.