From 7aa9fe76c8863247c5395f2ba8b78cef86195315 Mon Sep 17 00:00:00 2001 From: Sean Flanigan Date: Tue, 6 Oct 2015 14:56:30 +1000 Subject: [PATCH] refactor: replace Joda-Time/PrettyTime with java.time and ICU4J --- functional-test/pom.xml | 5 - .../feature/testharness/ZanataTestCase.java | 30 ++-- pom.xml | 7 +- zanata-model/pom.xml | 5 - .../org/zanata/model/ModelEntityBase.java | 17 ++ .../zanata/model/tm/TMXMetadataHelper.java | 15 +- zanata-war/pom.xml | 10 -- .../java/org/zanata/action/ReindexAction.java | 32 +--- .../zanata/dao/TextFlowTargetHistoryDAO.java | 39 ++--- .../dto/suggestion/JsonDateSerializer.java | 13 +- .../org/zanata/rest/service/DateRange.java | 44 ++--- .../rest/service/StatisticsServiceImpl.java | 35 ++-- .../search/FilterConstraintToQuery.java | 11 +- .../org/zanata/search/FilterConstraints.java | 15 +- .../main/java/org/zanata/util/DateUtil.java | 151 ++++++++++-------- .../server/rpc/GetTransUnitListHandler.java | 11 +- .../rpc/GetTransUnitsNavigationService.java | 2 - .../dao/TextFlowTargetHistoryDAOTest.java | 50 +++--- .../org/zanata/model/HTextFlowBuilder.java | 6 +- .../zanata/rest/service/DateRangeTest.java | 47 +++--- .../FilterConstraintToQueryJpaTest.java | 8 +- .../java/org/zanata/util/DateUtilTest.java | 61 +++++++ 22 files changed, 335 insertions(+), 279 deletions(-) create mode 100644 zanata-war/src/test/java/org/zanata/util/DateUtilTest.java diff --git a/functional-test/pom.xml b/functional-test/pom.xml index 4e2b0f7616..8ede44b806 100644 --- a/functional-test/pom.xml +++ b/functional-test/pom.xml @@ -322,11 +322,6 @@ annotations - - joda-time - joda-time - - com.jayway.awaitility awaitility diff --git a/functional-test/src/test/java/org/zanata/feature/testharness/ZanataTestCase.java b/functional-test/src/test/java/org/zanata/feature/testharness/ZanataTestCase.java index eae1fa158f..93f2a65ba8 100644 --- a/functional-test/src/test/java/org/zanata/feature/testharness/ZanataTestCase.java +++ b/functional-test/src/test/java/org/zanata/feature/testharness/ZanataTestCase.java @@ -22,10 +22,6 @@ package org.zanata.feature.testharness; import lombok.extern.slf4j.Slf4j; -import org.joda.time.DateTime; -import org.joda.time.Duration; -import org.joda.time.format.PeriodFormatter; -import org.joda.time.format.PeriodFormatterBuilder; import org.junit.After; import org.junit.Before; import org.junit.Rule; @@ -35,6 +31,9 @@ import org.zanata.util.EnsureLogoutRule; import org.zanata.util.SampleProjectRule; +import java.time.Duration; +import java.time.Instant; + /** * Global application of rules to Zanata functional tests * @@ -62,7 +61,7 @@ public class ZanataTestCase { * public Timeout timeout = new Timeout(MAX_TEST_DURATION); */ - public DateTime testFunctionStart; + public Instant testFunctionStart; private String getTestDescription() { return this.getClass().getCanonicalName() @@ -73,24 +72,17 @@ private String getTestDescription() { @Before public void testEntry() { log.info("Starting ".concat(getTestDescription())); - testFunctionStart = new DateTime(); + testFunctionStart = Instant.now(); } @After public void testExit() { - Duration duration = new Duration(testFunctionStart, new DateTime()); - PeriodFormatter periodFormatter = new PeriodFormatterBuilder() - .appendLiteral("Finished " - .concat(getTestDescription()).concat(" in ")) - .printZeroAlways() - .appendMinutes() - .appendSuffix(" minutes, ") - .appendSeconds() - .appendSuffix(" seconds, ") - .appendMillis() - .appendSuffix("ms") - .toFormatter(); - log.info(periodFormatter.print(duration.toPeriod())); + Duration d = Duration.between(testFunctionStart, Instant.now()); + String msg = + String.format("Finished %s in %d minutes, %d seconds, %dms", + getTestDescription(), d.toMinutes(), d.getSeconds(), + d.getNano() / 1000_000); + log.info(msg); WebDriverFactory.INSTANCE.logLogs(); } diff --git a/pom.xml b/pom.xml index 06f94ee40a..c789f9a9fa 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,7 @@ ${weld.version} 18.0 2.6.1 - 50.1.1 + 55.1 ${project.build.sourceDirectory}/org/zanata 3.6.2 3.9.17 @@ -1228,11 +1228,6 @@ 1.1.0 test - - joda-time - joda-time - 2.8.1 - org.fedorahosted.tennera jgettext diff --git a/zanata-model/pom.xml b/zanata-model/pom.xml index e97047e817..9bd14b0b75 100644 --- a/zanata-model/pom.xml +++ b/zanata-model/pom.xml @@ -293,11 +293,6 @@ validation-api - - joda-time - joda-time - - com.google.code.findbugs annotations diff --git a/zanata-model/src/main/java/org/zanata/model/ModelEntityBase.java b/zanata-model/src/main/java/org/zanata/model/ModelEntityBase.java index 2b2076062b..2c84f74c91 100644 --- a/zanata-model/src/main/java/org/zanata/model/ModelEntityBase.java +++ b/zanata-model/src/main/java/org/zanata/model/ModelEntityBase.java @@ -23,6 +23,8 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.Serializable; +import java.time.Instant; +import java.time.ZonedDateTime; import java.util.Date; import javax.persistence.Column; @@ -36,6 +38,7 @@ import javax.persistence.PreUpdate; import javax.persistence.Temporal; import javax.persistence.TemporalType; +import javax.persistence.Transient; import javax.persistence.Version; import lombok.extern.slf4j.Slf4j; @@ -94,6 +97,10 @@ public void setCreationDate(Date creationDate) { this.creationDate = creationDate; } + @Transient + public Instant getCreationInstant() { + return creationDate.toInstant(); + } // TODO extract lastChanged from ModelEntityBase and use with @Embedded // NB: also used in HSimpleComment @@ -109,6 +116,16 @@ public void setLastChanged(Date lastChanged) { this.lastChanged = lastChanged; } + @Transient + public Instant getLastChangedInstant() { + return lastChanged.toInstant(); + } + + @Transient + public void setLastChangedInstant(Instant lastChanged) { + this.lastChanged = Date.from(lastChanged); + } + @Override public int hashCode() { final int prime = 31; diff --git a/zanata-model/src/main/java/org/zanata/model/tm/TMXMetadataHelper.java b/zanata-model/src/main/java/org/zanata/model/tm/TMXMetadataHelper.java index a44ba4dd33..6c50734e39 100644 --- a/zanata-model/src/main/java/org/zanata/model/tm/TMXMetadataHelper.java +++ b/zanata-model/src/main/java/org/zanata/model/tm/TMXMetadataHelper.java @@ -21,6 +21,10 @@ package org.zanata.model.tm; +import java.time.Instant; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.time.temporal.TemporalAccessor; import java.util.Collections; import java.util.Date; import java.util.List; @@ -36,8 +40,6 @@ import nu.xom.Elements; import org.codehaus.jackson.map.ObjectMapper; -import org.joda.time.format.DateTimeFormat; -import org.joda.time.format.DateTimeFormatter; import org.zanata.util.TMXConstants; import org.zanata.util.TMXParseException; @@ -61,8 +63,8 @@ public class TMXMetadataHelper { private static final String TMX_ELEMENT_CHILDREN = "__TMX_ELEMENT_CHILDREN__"; - private static final DateTimeFormatter ISO8601Z = DateTimeFormat - .forPattern("yyyyMMdd'T'HHmmss'Z").withZoneUTC(); + private static final DateTimeFormatter ISO_FORMATTER = DateTimeFormatter + .ofPattern("yyyyMMdd'T'HHmmss'Z'").withZone(ZoneOffset.UTC); private static final ObjectMapper jsonMapper = new ObjectMapper(); // TMX attributes which we store as fields (*not* in the generic metadata @@ -295,13 +297,14 @@ private static void setGenericMetadata(HasTMMetadata toEntity, @SuppressWarnings("null") public static @Nonnull Date toDate(String dateString) { - return ISO8601Z.parseDateTime(dateString).toDate(); + TemporalAccessor temporalAccessor = ISO_FORMATTER.parse(dateString); + return Date.from(Instant.from(temporalAccessor)); } @SuppressWarnings("null") public static @Nonnull String toString(Date date) { - return ISO8601Z.print(date.getTime()); + return ISO_FORMATTER.format(date.toInstant()); } private static Map buildMetadata(Element fromElem) { diff --git a/zanata-war/pom.xml b/zanata-war/pom.xml index 47b65b80fa..e711d8b4f6 100644 --- a/zanata-war/pom.xml +++ b/zanata-war/pom.xml @@ -2316,12 +2316,6 @@ deltaspike-jpa-module-impl - - org.ocpsoft.prettytime - prettytime - 3.0.2.Final - - org.apache.httpcomponents httpcore @@ -2411,10 +2405,6 @@ org.fedorahosted.tennera jgettext - - joda-time - joda-time - com.beust jcommander diff --git a/zanata-war/src/main/java/org/zanata/action/ReindexAction.java b/zanata-war/src/main/java/org/zanata/action/ReindexAction.java index 77057469ea..8bbcbd1f68 100644 --- a/zanata-war/src/main/java/org/zanata/action/ReindexAction.java +++ b/zanata-war/src/main/java/org/zanata/action/ReindexAction.java @@ -2,6 +2,7 @@ import java.io.Serializable; import java.text.DecimalFormat; +import java.util.Date; import java.util.List; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; @@ -13,17 +14,13 @@ import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; -import org.zanata.security.annotations.CheckLoggedIn; -import org.zanata.security.annotations.CheckPermission; import org.zanata.security.annotations.CheckRole; -import org.joda.time.Period; -import org.joda.time.format.PeriodFormatter; -import org.joda.time.format.PeriodFormatterBuilder; import org.zanata.async.AsyncTaskHandle; import org.zanata.security.annotations.ZanataSecured; import org.zanata.service.SearchIndexManager; import com.google.common.base.Optional; +import org.zanata.util.DateUtil; @AutoCreate @Name("reindexAction") @@ -188,40 +185,21 @@ public boolean isCanceled() { && searchIndexManager.getProcessHandle().isCancelled(); } - // TODO move to common location with ViewAllStatusAction - private static final PeriodFormatter PERIOD_FORMATTER = - new PeriodFormatterBuilder().appendDays() - .appendSuffix(" day", " days").appendSeparator(", ") - .appendHours().appendSuffix(" hour", " hours") - .appendSeparator(", ").appendMinutes() - .appendSuffix(" min", " mins") - .toFormatter(); - - private String formatTimePeriod(long durationInMillis) { - Period period = new Period(durationInMillis); - - if (period.toStandardMinutes().getMinutes() <= 0) { - return "less than a minute"; // TODO Localize - } else { - return PERIOD_FORMATTER.print(period.normalizedStandard()); - } - } - public String getElapsedTime() { AsyncTaskHandle processHandle = searchIndexManager.getProcessHandle(); if (processHandle == null) { log.error("processHandle is null when looking up elapsed time"); return ""; } else { - long elapsedTime = processHandle.getExecutingTime(); - return formatTimePeriod(elapsedTime); + Date start = new Date(processHandle.getStartTime()); + return DateUtil.getHowLongAgoDescription(start); } } public String getEstimatedTimeRemaining() { Optional estimate = searchIndexManager.getProcessHandle().getEstimatedTimeRemaining(); if (estimate.isPresent()) { - return formatTimePeriod(estimate.get()); + return DateUtil.getTimeRemainingDescription(estimate.get()); } // TODO localize (not expecting to display estimate when it is unavailable anyway). return "unknown"; diff --git a/zanata-war/src/main/java/org/zanata/dao/TextFlowTargetHistoryDAO.java b/zanata-war/src/main/java/org/zanata/dao/TextFlowTargetHistoryDAO.java index a2214fc80f..53e648ee75 100644 --- a/zanata-war/src/main/java/org/zanata/dao/TextFlowTargetHistoryDAO.java +++ b/zanata-war/src/main/java/org/zanata/dao/TextFlowTargetHistoryDAO.java @@ -21,6 +21,8 @@ package org.zanata.dao; import java.math.BigInteger; +import java.time.Instant; +import java.time.ZoneId; import java.util.Date; import java.util.List; import java.util.concurrent.TimeUnit; @@ -32,8 +34,6 @@ import org.jboss.seam.annotations.AutoCreate; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; -import org.joda.time.DateTime; -import org.joda.time.DateTimeZone; import org.zanata.common.ContentState; import org.zanata.model.HPerson; import org.zanata.model.HTextFlowTarget; @@ -71,8 +71,8 @@ public TextFlowTargetHistoryDAO(Session session) { * * @param versionId HProjectIteration identifier * @param personId HPerson identifier - * @param from start of date range - * @param to end of date range + * @param fromDate start of date range + * @param toDate end of date range * * @return list of Object[wordCount][contentState][localeId] */ @@ -205,8 +205,8 @@ public boolean findConflictInHistory(HTextFlowTarget target, */ @NativeQuery(value = "need to use union", specificTo = "mysql due to usage of date() and convert_tz() functions.") public List getUserTranslationMatrix( - HPerson user, DateTime fromDate, DateTime toDate, - Optional userZoneOpt, DateTimeZone systemZone, + HPerson user, Instant fromDate, Instant toDate, + Optional userZoneOpt, ZoneId systemZone, ResultTransformer resultTransformer) { // @formatter:off String queryHistory = "select history.id, iter.id as iteration, tft.locale as locale, tf.wordCount as wordCount, history.state as state, history.lastChanged as lastChanged " + @@ -228,8 +228,9 @@ public List getUserTranslationMatrix( " and tft.last_modified_by_id = :user and (tft.translated_by_id is not null or tft.reviewed_by_id is not null)" + " and tft.state <> :untranslated and tft.state <> :rejected and tft.automatedEntry =:automatedEntry"; + // NB: we use the same timezones for the entire period String convertedLastChanged = convertTimeZoneFunction("lastChanged", - userZoneOpt, systemZone); + userZoneOpt, systemZone, toDate); // @formatter:on String dateOfLastChanged = stripTimeFromDateTimeFunction(convertedLastChanged); String queryString = @@ -244,18 +245,19 @@ public List getUserTranslationMatrix( .setInteger("untranslated", ContentState.New.ordinal()) .setInteger("rejected", ContentState.Rejected.ordinal()) .setBoolean("automatedEntry", false) - .setTimestamp("fromDate", fromDate.toDate()) - .setTimestamp("toDate", toDate.toDate()) + .setTimestamp("fromDate", Date.from(fromDate)) + .setTimestamp("toDate", Date.from(toDate)) .setResultTransformer(resultTransformer); return query.list(); } @VisibleForTesting protected String convertTimeZoneFunction(String columnName, - Optional userZoneOpt, DateTimeZone systemZone) { + Optional userZoneOpt, + ZoneId systemZone, Instant asAtTime) { if (userZoneOpt.isPresent()) { - String userOffset = getOffsetAsString(userZoneOpt.get()); - String systemOffset = getOffsetAsString(systemZone); + String userOffset = getOffsetAsString(userZoneOpt.get(), asAtTime); + String systemOffset = getOffsetAsString(systemZone, asAtTime); return String.format("CONVERT_TZ(%s, '%s', '%s')", columnName, systemOffset, userOffset); } // no need to convert timezone @@ -274,15 +276,16 @@ private T loadById(Object object, Class entityClass) { ((BigInteger) object).longValue()); } - private static String getOffsetAsString(DateTimeZone zone) { - int standardOffset = zone.getStandardOffset(0); + private static String getOffsetAsString(ZoneId zone, Instant asAtTime) { + int offsetSec = zone.getRules().getOffset(asAtTime).getTotalSeconds(); String prefix = ""; - if (standardOffset < 0) { + if (offsetSec < 0) { prefix = "-"; - standardOffset = -standardOffset; + offsetSec = -offsetSec; } - return String.format("%s%02d:00", prefix, - TimeUnit.MILLISECONDS.toHours(standardOffset)); + int hours = (int) TimeUnit.SECONDS.toHours(offsetSec); + int min = (int) TimeUnit.SECONDS.toMinutes(offsetSec) % 60; + return String.format("%s%02d:%02d", prefix, hours, min); } } diff --git a/zanata-war/src/main/java/org/zanata/rest/editor/dto/suggestion/JsonDateSerializer.java b/zanata-war/src/main/java/org/zanata/rest/editor/dto/suggestion/JsonDateSerializer.java index ed014397ce..2e30980145 100644 --- a/zanata-war/src/main/java/org/zanata/rest/editor/dto/suggestion/JsonDateSerializer.java +++ b/zanata-war/src/main/java/org/zanata/rest/editor/dto/suggestion/JsonDateSerializer.java @@ -23,11 +23,12 @@ import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.map.JsonSerializer; import org.codehaus.jackson.map.SerializerProvider; -import org.joda.time.DateTime; -import org.joda.time.format.DateTimeFormatter; -import org.joda.time.format.ISODateTimeFormat; import java.io.IOException; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.util.Date; /** @@ -38,11 +39,13 @@ */ public class JsonDateSerializer extends JsonSerializer { - private static final DateTimeFormatter ISO8601Format = ISODateTimeFormat.dateTime(); + private static final DateTimeFormatter ISO8601Format = DateTimeFormatter.ISO_OFFSET_DATE_TIME; + private static final ZoneId ZONE = ZoneId.systemDefault(); @Override public void serialize(Date date, JsonGenerator jsonGenerator, SerializerProvider provider) throws IOException { - String dateString = ISO8601Format.print(new DateTime(date)); + LocalDateTime ldt = LocalDateTime.ofInstant(date.toInstant(), ZONE); + String dateString = ISO8601Format.format(ldt); jsonGenerator.writeString(dateString); } diff --git a/zanata-war/src/main/java/org/zanata/rest/service/DateRange.java b/zanata-war/src/main/java/org/zanata/rest/service/DateRange.java index 93bd5dc8cb..79d9270dbd 100644 --- a/zanata-war/src/main/java/org/zanata/rest/service/DateRange.java +++ b/zanata-war/src/main/java/org/zanata/rest/service/DateRange.java @@ -1,20 +1,22 @@ package org.zanata.rest.service; +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.util.Date; import java.util.TimeZone; import org.jboss.resteasy.spi.BadRequestException; -import org.joda.time.DateTime; -import org.joda.time.DateTimeZone; -import org.joda.time.Days; -import org.joda.time.format.DateTimeFormat; -import org.joda.time.format.DateTimeFormatter; import org.zanata.exception.InvalidDateParamException; import org.zanata.util.DateUtil; import lombok.AccessLevel; import lombok.Getter; import lombok.RequiredArgsConstructor; +import static java.time.temporal.ChronoUnit.DAYS; + /** * @author Patrick Huang * pahuang@redhat.com @@ -22,12 +24,14 @@ @RequiredArgsConstructor(access = AccessLevel.PRIVATE) class DateRange { private static final int MAX_STATS_DAYS = 365; + private static final Duration MAX_STATS_DURATION = Duration.ofDays(MAX_STATS_DAYS); + @Getter - private final DateTime fromDate; + private final ZonedDateTime fromDate; @Getter - private final DateTime toDate; + private final ZonedDateTime toDate; @Getter - private final DateTimeZone timeZone; + private final ZoneId timeZone; static DateRange from(String dateRangeParam) { return from(dateRangeParam, null); @@ -38,32 +42,32 @@ static DateRange from(String dateRangeParam, String fromTimezoneId) { if (dateRange.length != 2) { throw new InvalidDateParamException(dateRangeParam); } - DateTimeZone zone; + ZoneId zone; if (fromTimezoneId == null) { - zone = DateTimeZone.getDefault(); + zone = ZoneId.systemDefault(); } else { try { - zone = DateTimeZone.forID(fromTimezoneId); + zone = ZoneId.of(fromTimezoneId); } catch (IllegalArgumentException e) { throw new BadRequestException("Invalid timezone ID:" + fromTimezoneId); } } - DateTime fromDate; - DateTime toDate; + ZonedDateTime fromDate; + ZonedDateTime toDate; try { DateTimeFormatter formatter = - DateTimeFormat.forPattern(StatisticsResource.DATE_FORMAT) + DateTimeFormatter.ofPattern(StatisticsResource.DATE_FORMAT) .withZone(zone); - fromDate = formatter.parseDateTime(dateRange[0]); - toDate = formatter.parseDateTime(dateRange[1]); + fromDate = ZonedDateTime.parse(dateRange[0], formatter); + toDate = ZonedDateTime.parse(dateRange[1], formatter); - fromDate = fromDate.withTimeAtStartOfDay(); // start of day - toDate = toDate.plusDays(1).minusMillis(1); // end of day + fromDate = fromDate.truncatedTo(DAYS); // start of day + toDate = toDate.truncatedTo(DAYS).plusDays(1).minusNanos(1000_000L); // end of day - if (fromDate.isAfter(toDate) || Days.daysBetween(fromDate, - toDate).getDays() > MAX_STATS_DAYS) { + Duration duration = Duration.between(fromDate, toDate); + if (duration.isNegative() || duration.compareTo(MAX_STATS_DURATION) > 0) { throw new InvalidDateParamException(dateRangeParam); } } catch (IllegalArgumentException e) { diff --git a/zanata-war/src/main/java/org/zanata/rest/service/StatisticsServiceImpl.java b/zanata-war/src/main/java/org/zanata/rest/service/StatisticsServiceImpl.java index ceacfcb2b7..02532f3bf8 100644 --- a/zanata-war/src/main/java/org/zanata/rest/service/StatisticsServiceImpl.java +++ b/zanata-war/src/main/java/org/zanata/rest/service/StatisticsServiceImpl.java @@ -23,6 +23,10 @@ import java.math.BigDecimal; import java.math.BigInteger; import java.net.URI; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; import java.util.Date; import java.util.List; import java.util.Map; @@ -44,10 +48,6 @@ import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; -import org.joda.time.DateTime; -import org.joda.time.DateTimeZone; -import org.joda.time.format.DateTimeFormat; -import org.joda.time.format.DateTimeFormatter; import org.zanata.common.ContentState; import org.zanata.common.EntityStatus; import org.zanata.common.LocaleId; @@ -343,8 +343,8 @@ public ContributionStatistics getContributionStatistics(String projectSlug, List data = textFlowTargetHistoryDAO.getUserContributionStatisticInVersion( version.getId(), person.getId(), - dateRange.getFromDate().toDate(), - dateRange.getToDate().toDate()); + Date.from(dateRange.getFromDate().toInstant()), + Date.from(dateRange.getToDate().toInstant())); for (Object[] entry : data) { int count = ((BigDecimal) entry[0]).intValue(); @@ -456,19 +456,20 @@ public List getUserWorkMatrix( HPerson person = findPersonOrExceptionOnNotFound(username); DateRange dateRange = DateRange.from(dateRangeParam, userTimeZoneID); - DateTime fromDate = dateRange.getFromDate(); - DateTime toDate = dateRange.getToDate(); + ZonedDateTime fromDate = dateRange.getFromDate(); + ZonedDateTime toDate = dateRange.getToDate(); - DateTimeZone userZone = dateRange.getTimeZone(); + ZoneId userZone = dateRange.getTimeZone(); DateTimeFormatter dateFormatter = - DateTimeFormat.forPattern(DATE_FORMAT) + DateTimeFormatter.ofPattern(DATE_FORMAT) .withZone(userZone); // TODO system time zone should be persisted in database - DateTimeZone systemZone = DateTimeZone.getDefault(); + ZoneId systemZone = ZoneId.systemDefault(); - Optional userZoneOpt; - if (userZone.getStandardOffset(0) != systemZone.getStandardOffset(0)) { + Optional userZoneOpt; + Instant asAt = toDate.toInstant(); + if (userZone.getRules().getOffset(asAt) != systemZone.getRules().getOffset(asAt)) { userZoneOpt = Optional.of(userZone); } else { userZoneOpt = Optional.absent(); @@ -476,7 +477,7 @@ public List getUserWorkMatrix( List translationMatrixList = textFlowTargetHistoryDAO.getUserTranslationMatrix(person, - fromDate, toDate, userZoneOpt, systemZone, + fromDate.toInstant(), toDate.toInstant(), userZoneOpt, systemZone, new UserMatrixResultTransformer(entityManager, dateFormatter)); return translationMatrixList; @@ -487,12 +488,12 @@ public static class UserMatrixResultTransformer implements ResultTransformer { private static final long serialVersionUID = 1L; private final EntityManager entityManager; - private final DateTimeFormatter dateFormater; + private final DateTimeFormatter dateFormatter; @Override public Object transformTuple(Object[] tuple, String[] aliases) { - String savedDate = dateFormater.print( - new DateTime(tuple[0]).toDate().getTime()); + String savedDate = dateFormatter.format( + ((Date) tuple[0]).toInstant()); HProjectIteration iteration = entityManager.find(HProjectIteration.class, ((BigInteger) tuple[1]).longValue()); diff --git a/zanata-war/src/main/java/org/zanata/search/FilterConstraintToQuery.java b/zanata-war/src/main/java/org/zanata/search/FilterConstraintToQuery.java index 0ab37a8028..eb9c658d2e 100644 --- a/zanata-war/src/main/java/org/zanata/search/FilterConstraintToQuery.java +++ b/zanata-war/src/main/java/org/zanata/search/FilterConstraintToQuery.java @@ -1,5 +1,7 @@ package org.zanata.search; +import java.sql.Date; +import java.time.Instant; import java.util.Collection; import java.util.List; @@ -8,7 +10,6 @@ import org.apache.commons.lang.StringUtils; import org.hibernate.Query; import org.hibernate.criterion.MatchMode; -import org.joda.time.DateTime; import org.zanata.model.HLocale; import org.zanata.util.HqlCriterion; import org.zanata.util.QueryBuilder; @@ -252,8 +253,8 @@ private String buildTargetCommentCondition(String transComment) { } private String buildLastModifiedDateCondition() { - DateTime changedBeforeTime = constraints.getChangedBefore(); - DateTime changedAfterTime = constraints.getChangedAfter(); + Instant changedBeforeTime = constraints.getChangedBefore(); + Instant changedAfterTime = constraints.getChangedAfter(); if (changedBeforeTime == null && changedAfterTime == null) { return null; } @@ -366,11 +367,11 @@ public Query setQueryParameters(Query textFlowQuery, HLocale hLocale) { LastModifiedBy); if (constraints.getChangedAfter() != null) { textFlowQuery.setParameter(LastChangedAfter.namedParam(), - constraints.getChangedAfter().toDate()); + Date.from(constraints.getChangedAfter())); } if (constraints.getChangedBefore() != null) { textFlowQuery.setParameter(LastChangedBefore.namedParam(), - constraints.getChangedBefore().toDate()); + Date.from(constraints.getChangedBefore())); } return textFlowQuery; } diff --git a/zanata-war/src/main/java/org/zanata/search/FilterConstraints.java b/zanata-war/src/main/java/org/zanata/search/FilterConstraints.java index 0eaa1a4903..cafa909103 100644 --- a/zanata-war/src/main/java/org/zanata/search/FilterConstraints.java +++ b/zanata-war/src/main/java/org/zanata/search/FilterConstraints.java @@ -23,7 +23,6 @@ //TODO May want to add document(someDocument) to these constraints //so that only one search method is needed on the interface. -import org.joda.time.DateTime; import org.zanata.webtrans.shared.model.ContentStateGroup; import lombok.Getter; @@ -31,6 +30,8 @@ import com.google.common.base.Objects; import com.google.common.base.Preconditions; +import java.time.Instant; + /** * Specifies a set of constraints to be applied by a filter. * @@ -44,8 +45,8 @@ public class FilterConstraints { private boolean searchInTarget; private ContentStateGroup includedStates; private String resId; - private DateTime changedBefore; - private DateTime changedAfter; + private Instant changedBefore; + private Instant changedAfter; private String lastModifiedByUser; private String sourceComment; private String transComment; @@ -104,8 +105,8 @@ public static class Builder { private boolean searchInTarget; private ContentStateGroup.Builder states; private String resId; - private DateTime changedBefore; - private DateTime changedAfter; + private Instant changedBefore; + private Instant changedAfter; private String lastModifiedByUser; private String sourceComment; private String transComment; @@ -241,12 +242,12 @@ public Builder lastModifiedBy(String username) { return this; } - public Builder targetChangedBefore(DateTime date) { + public Builder targetChangedBefore(Instant date) { this.changedBefore = date; return this; } - public Builder targetChangedAfter(DateTime date) { + public Builder targetChangedAfter(Instant date) { this.changedAfter = date; return this; } diff --git a/zanata-war/src/main/java/org/zanata/util/DateUtil.java b/zanata-war/src/main/java/org/zanata/util/DateUtil.java index d47186c60c..55b4bef876 100644 --- a/zanata-war/src/main/java/org/zanata/util/DateUtil.java +++ b/zanata-war/src/main/java/org/zanata/util/DateUtil.java @@ -3,23 +3,26 @@ */ package org.zanata.util; +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; import java.util.Date; -import java.util.Locale; -import java.util.concurrent.TimeUnit; - -import org.joda.time.DateTime; -import org.joda.time.Days; -import org.joda.time.Period; -import org.joda.time.format.DateTimeFormat; -import org.joda.time.format.DateTimeFormatter; -import org.joda.time.format.PeriodFormatter; -import org.joda.time.format.PeriodFormatterBuilder; -import org.ocpsoft.prettytime.PrettyTime; +import java.util.function.LongFunction; + +import com.ibm.icu.impl.duration.BasicPeriodFormatterService; +import com.ibm.icu.impl.duration.DurationFormatter; +import lombok.ToString; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; +import static java.time.DayOfWeek.MONDAY; +import static java.time.temporal.ChronoUnit.DAYS; +import static java.time.temporal.TemporalAdjusters.previousOrSame; + /** * * @author Alex Eng aeng@redhat.com @@ -28,15 +31,11 @@ public class DateUtil { private final static String DATE_TIME_SHORT_PATTERN = "dd/MM/yy HH:mm"; private final static String TIME_SHORT_PATTERN = "hh:mm:ss"; - - // Period Formatters are thread safe and immutableaccording to joda time - // docs - private static final PeriodFormatter TIME_REMAINING_FORMATTER = - new PeriodFormatterBuilder().appendDays() - .appendSuffix(" day", " days").appendSeparator(", ") - .appendHours().appendSuffix(" hour", " hours") - .appendSeparator(", ").appendMinutes() - .appendSuffix(" min", " mins").toFormatter(); + private static final ZoneId ZONE = ZoneId.systemDefault(); + private static final DurationFormatter TIME_REMAINING_FORMATTER = + BasicPeriodFormatterService.getInstance().newDurationFormatterFactory().getFormatter(); + // one millisecond in nanos + private static final long ONE_MILLI = 1000_000L; /** * Format date to dd/MM/yy hh:mm a @@ -46,9 +45,9 @@ public class DateUtil { */ public static String formatShortDate(Date date) { if (date != null) { - DateTimeFormatter fmt = - DateTimeFormat.forPattern(DATE_TIME_SHORT_PATTERN); - return fmt.print(new DateTime(date)); + DateTimeFormatter fmt = DateTimeFormatter.ofPattern( + DATE_TIME_SHORT_PATTERN).withZone(ZoneId.systemDefault()); + return fmt.format(date.toInstant()); } return null; } @@ -61,9 +60,9 @@ public static String formatShortDate(Date date) { */ public static String formatTime(Date date) { if (date != null) { - DateTimeFormatter fmt = - DateTimeFormat.forPattern(TIME_SHORT_PATTERN); - return fmt.print(new DateTime(date)); + DateTimeFormatter fmt = DateTimeFormatter.ofPattern( + TIME_SHORT_PATTERN).withZone(ZoneId.systemDefault()); + return fmt.format(date.toInstant()); } return null; } @@ -76,17 +75,35 @@ public static String formatTime(Date date) { * @return */ public static String getHowLongAgoDescription(Date then) { - Locale locale = Locale.getDefault(); - PrettyTime p = new PrettyTime(locale); - return p.format(then); + long now = new Date().getTime(); + long durationInMillis = now - then.getTime(); + return getDurationDescription(durationInMillis, d -> + TIME_REMAINING_FORMATTER.formatDurationFrom(-durationInMillis, now)); } public static String getTimeRemainingDescription(long durationInMillis) { - Period period = new Period(durationInMillis); - if (period.toStandardMinutes().getMinutes() <= 0) { + return getDurationDescription(durationInMillis, d -> + TIME_REMAINING_FORMATTER.formatDurationFromNow( + durationInMillis) + ); + } + + private static String getDurationDescription(long durationInMillis, + LongFunction format) { + if (durationInMillis < 60_000) { return "less than a minute"; } else { - return TIME_REMAINING_FORMATTER.print(period.normalizedStandard()); + StringBuilder sb = new StringBuilder(); + sb.append(format.apply(durationInMillis)); + Duration d = Duration.ofMillis(durationInMillis); + sb.append(" ("); + if (d.toDays() != 0) { + sb.append(d.toDays()).append("d "); + } + sb.append(LocalTime.MIDNIGHT.plus(d).format( + DateTimeFormatter.ofPattern("H'h':mm'm'"))); + sb.append(")"); + return sb.toString(); } } @@ -95,15 +112,13 @@ public static long getDurationInMillisecond(Date from, Date then) { } public static DateUnitAndFigure getUnitAndFigure(long durationInMillis) { - Period period = new Period(durationInMillis); - if (period.toStandardMinutes().getMinutes() <= 0) { - return new DateUnitAndFigure("seconds", period.toStandardSeconds() - .getSeconds()); - } else if (period.toStandardDays().getDays() <= 0) { - return new DateUnitAndFigure("minutes", period.toStandardMinutes() - .getMinutes()); + Duration period = Duration.ofMillis(durationInMillis); + if (period.toMinutes() <= 0) { + return new DateUnitAndFigure("seconds", period.getSeconds()); + } else if (period.toDays() <= 0) { + return new DateUnitAndFigure("minutes", period.toMinutes()); } - return new DateUnitAndFigure("days", period.toStandardDays().getDays()); + return new DateUnitAndFigure("days", period.toDays()); } public static int compareDate(Date date1, Date date2) { @@ -121,9 +136,10 @@ public static int compareDate(Date date1, Date date2) { @Getter @AllArgsConstructor @NoArgsConstructor + @ToString public static class DateUnitAndFigure { private String unit; // s(second) m(minute) or d(day) - private int figure; + private long figure; } /** @@ -134,8 +150,9 @@ public static class DateUnitAndFigure { * @return */ public static Date getStartOfDay(Date actionTime) { - DateTime dateTime = new DateTime(actionTime); - return dateTime.withTimeAtStartOfDay().toDate(); + LocalDateTime ldt = LocalDateTime.ofInstant(actionTime.toInstant(), ZONE); + LocalDateTime start = ldt.toLocalDate().atStartOfDay(); + return Date.from(start.atZone(ZONE).toInstant()); } /** @@ -146,9 +163,9 @@ public static Date getStartOfDay(Date actionTime) { * @return */ public static Date getEndOfTheDay(Date actionTime) { - DateTime endOfTheDay = new DateTime(actionTime).plusDays(1) - .withTimeAtStartOfDay().minusMillis(1); - return endOfTheDay.toDate(); + LocalDateTime ldt = LocalDateTime.ofInstant(actionTime.toInstant(), ZONE); + LocalDateTime end = ldt.toLocalDate().atStartOfDay().plusDays(1).minusNanos(ONE_MILLI); + return Date.from(end.atZone(ZONE).toInstant()); } /** @@ -158,9 +175,9 @@ public static Date getEndOfTheDay(Date actionTime) { * @return */ public static Date getStartOfWeek(Date actionTime) { - DateTime truncateMonth = - new DateTime(actionTime).weekOfWeekyear().roundFloorCopy(); - return truncateMonth.toDate(); + LocalDateTime ldt = LocalDateTime.ofInstant(actionTime.toInstant(), ZONE); + LocalDateTime start = ldt.truncatedTo(DAYS).with(previousOrSame(MONDAY)); + return Date.from(start.atZone(ZONE).toInstant()); } /** @@ -170,10 +187,9 @@ public static Date getStartOfWeek(Date actionTime) { * @return */ public static Date getEndOfTheWeek(Date actionTime) { - DateTime truncateMonth = - new DateTime(actionTime).weekOfWeekyear().roundCeilingCopy() - .minusMillis(1); - return truncateMonth.toDate(); + LocalDateTime ldt = LocalDateTime.ofInstant(actionTime.toInstant(), ZONE); + LocalDateTime end = ldt.truncatedTo(DAYS).with(previousOrSame(MONDAY)).plusWeeks(1).minusNanos(ONE_MILLI); + return Date.from(end.atZone(ZONE).toInstant()); } /** @@ -184,9 +200,9 @@ public static Date getEndOfTheWeek(Date actionTime) { * @return */ public static Date getStartOfMonth(Date actionTime) { - DateTime truncateMonth = - new DateTime(actionTime).monthOfYear().roundFloorCopy(); - return truncateMonth.toDate(); + LocalDateTime ldt = LocalDateTime.ofInstant(actionTime.toInstant(), ZONE); + LocalDateTime start = ldt.truncatedTo(DAYS).withDayOfMonth(1); + return Date.from(start.atZone(ZONE).toInstant()); } /** @@ -197,10 +213,9 @@ public static Date getStartOfMonth(Date actionTime) { * @return */ public static Date getEndOfTheMonth(Date actionTime) { - DateTime truncateMonth = - new DateTime(actionTime).monthOfYear().roundCeilingCopy() - .minusMillis(1); - return truncateMonth.toDate(); + LocalDateTime ldt = LocalDateTime.ofInstant(actionTime.toInstant(), ZONE); + LocalDateTime start = ldt.truncatedTo(DAYS).withDayOfMonth(1).plusMonths(1).minusNanos(ONE_MILLI); + return Date.from(start.atZone(ZONE).toInstant()); } /** @@ -213,22 +228,22 @@ public static Date getEndOfTheMonth(Date actionTime) { public static Date getDate(String date, String pattern) throws IllegalArgumentException { DateTimeFormatter formatter = - DateTimeFormat.forPattern(pattern); - return formatter.parseDateTime(date).toDate(); + DateTimeFormatter.ofPattern(pattern); + LocalDateTime ldt = LocalDateTime.parse(date, formatter); + return Date.from(ldt.atZone(ZONE).toInstant()); } /** - * Check if date difference is within given days. + * Check that date difference is no more than 'days' days. * * @param from * @param to * @param days */ public static boolean isDatesInRange(Date from, Date to, int days) { - DateTime fromDate = new DateTime(from); - DateTime toDate = new DateTime(to); - - Days d = Days.daysBetween(fromDate, toDate); - return d.getDays() <= days; + long durationMillis = to.getTime() - from.getTime(); + Duration actual = Duration.ofMillis(durationMillis); + Duration limit = Duration.ofDays(days); + return actual.compareTo(limit) <= 0; } } diff --git a/zanata-war/src/main/java/org/zanata/webtrans/server/rpc/GetTransUnitListHandler.java b/zanata-war/src/main/java/org/zanata/webtrans/server/rpc/GetTransUnitListHandler.java index be8e32d79e..f61d577f93 100755 --- a/zanata-war/src/main/java/org/zanata/webtrans/server/rpc/GetTransUnitListHandler.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/server/rpc/GetTransUnitListHandler.java @@ -20,6 +20,8 @@ */ package org.zanata.webtrans.server.rpc; +import java.time.Instant; +import java.time.format.DateTimeFormatter; import java.util.List; import lombok.extern.slf4j.Slf4j; @@ -30,9 +32,6 @@ import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; -import org.joda.time.DateTime; -import org.joda.time.format.DateTimeFormat; -import org.joda.time.format.DateTimeFormatter; import org.zanata.dao.TextFlowDAO; import org.zanata.exception.ZanataServiceException; import org.zanata.model.HLocale; @@ -80,7 +79,7 @@ public class GetTransUnitListHandler extends private GetTransUnitsNavigationService getTransUnitsNavigationService; private DateTimeFormatter dateFormatter = - DateTimeFormat.forPattern("yyyy-MM-dd"); + DateTimeFormatter.ofPattern("yyyy-MM-dd"); @Override public GetTransUnitListResult execute(GetTransUnitList action, @@ -150,9 +149,9 @@ public GetTransUnitListResult execute(GetTransUnitList action, return result; } - private DateTime parseDateIfPresent(String dateInString) { + private Instant parseDateIfPresent(String dateInString) { return Strings.isNullOrEmpty(dateInString) ? null : - dateFormatter.parseDateTime(dateInString); + dateFormatter.parse(dateInString, Instant::from); } private int getTotalPageIndex(int indexListSize, int countPerPage) { diff --git a/zanata-war/src/main/java/org/zanata/webtrans/server/rpc/GetTransUnitsNavigationService.java b/zanata-war/src/main/java/org/zanata/webtrans/server/rpc/GetTransUnitsNavigationService.java index 7b50bbc3db..6d2dc0b007 100644 --- a/zanata-war/src/main/java/org/zanata/webtrans/server/rpc/GetTransUnitsNavigationService.java +++ b/zanata-war/src/main/java/org/zanata/webtrans/server/rpc/GetTransUnitsNavigationService.java @@ -30,8 +30,6 @@ import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Scope; -import org.joda.time.format.DateTimeFormat; -import org.joda.time.format.DateTimeFormatter; import org.zanata.common.ContentState; import org.zanata.dao.TextFlowDAO; import org.zanata.model.HLocale; diff --git a/zanata-war/src/test/java/org/zanata/dao/TextFlowTargetHistoryDAOTest.java b/zanata-war/src/test/java/org/zanata/dao/TextFlowTargetHistoryDAOTest.java index a300922a17..b55c95ecf5 100644 --- a/zanata-war/src/test/java/org/zanata/dao/TextFlowTargetHistoryDAOTest.java +++ b/zanata-war/src/test/java/org/zanata/dao/TextFlowTargetHistoryDAOTest.java @@ -1,12 +1,14 @@ package org.zanata.dao; +import java.time.Instant; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.format.FormatStyle; +import java.time.temporal.ChronoUnit; import java.util.List; import org.hibernate.transform.ResultTransformer; -import org.joda.time.DateTime; -import org.joda.time.DateTimeZone; -import org.joda.time.format.DateTimeFormat; -import org.joda.time.format.DateTimeFormatter; import org.junit.Before; import org.junit.Test; import org.zanata.ZanataJpaTest; @@ -33,18 +35,20 @@ import lombok.RequiredArgsConstructor; +import static java.time.temporal.ChronoUnit.DAYS; import static org.assertj.core.api.Assertions.assertThat; public class TextFlowTargetHistoryDAOTest extends ZanataJpaTest { private TextFlowTargetHistoryDAO historyDAO; private HPerson user; private HLocale hLocale; - private DateTime today = new DateTime(); - private DateTime yesterday = new DateTime().minusDays(1); - private DateTime twoDaysAgo = new DateTime().minusDays(2); + private Instant today = Instant.now(); + private Instant yesterday = today.minus(1, DAYS); + private Instant twoDaysAgo = today.minus(2, DAYS); private HDocument hDocument; private ResultTransformer resultTransformer; - private static final DateTimeFormatter dateFormatter = DateTimeFormat.mediumDate(); + private static final DateTimeFormatter dateFormatter = + DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM); @Before public void setUp() throws Exception { @@ -134,10 +138,10 @@ public void canGetUserTranslationMatrix() { List result = historyDAO .getUserTranslationMatrix(user, - twoDaysAgo.withTimeAtStartOfDay(), - today.withTimeAtStartOfDay(), - Optional. absent(), - DateTimeZone.getDefault(), resultTransformer); + twoDaysAgo.truncatedTo(ChronoUnit.DAYS), + today.truncatedTo(ChronoUnit.DAYS), + Optional. absent(), + ZoneId.systemDefault(), resultTransformer); assertThat(result).hasSize(4); final SavedDatePredicate yesterdayPredicate = @@ -200,11 +204,11 @@ public void whenSettingParameterIt() { new HTextFlowBuilder().withDocument(hDocument) .withTargetLocale(hLocale); - DateTimeZone zone = DateTimeZone - .forID("Australia/Brisbane"); + ZoneId zone = ZoneId + .of("Australia/Brisbane"); baseBuilder .withLastModifiedDate( - new DateTime(2015, 2, 1, 1, 0, zone)) + ZonedDateTime.of(2015, 2, 1, 1, 0, 0, 0, zone).toInstant()) .withLastModifiedBy(user) .withResId("res1").withSourceContent("source 1") .withTargetContent("target 1") @@ -213,17 +217,17 @@ public void whenSettingParameterIt() { List result = historyDAO .getUserTranslationMatrix(user, - new DateTime(2015, 2, 1, 1, 1, zone), - new DateTime(zone), Optional. absent(), - DateTimeZone.getDefault(), resultTransformer); + ZonedDateTime.of(2015, 2, 1, 1, 1, 0, 0, zone).toInstant(), + ZonedDateTime.now(zone).toInstant(), Optional. absent(), + ZoneId.systemDefault(), resultTransformer); assertThat(result).isEmpty(); } @Test - public void canConvertTimeZoneIfUSerSuppliedDifferentZone() { + public void canConvertTimeZoneIfUserSuppliedDifferentZone() { String result = historyDAO.convertTimeZoneFunction("lastChanged", - Optional.of(DateTimeZone.forID("Australia/Brisbane")), - DateTimeZone.forID("America/Chicago")); + Optional.of(ZoneId.of("Australia/Brisbane")), + ZoneId.of("America/Chicago"), Instant.now()); assertThat(result).isEqualToIgnoringCase( "convert_tz(lastChanged, '-06:00', '10:00')"); @@ -244,8 +248,8 @@ private static class SavedDatePredicate implements Predicate { private final String theDate; - private SavedDatePredicate(DateTime theDate) { - this.theDate = dateFormatter.print(theDate.withTimeAtStartOfDay()); + private SavedDatePredicate(Instant theDate) { + this.theDate = dateFormatter.format(theDate.truncatedTo(ChronoUnit.DAYS)); } @Override diff --git a/zanata-war/src/test/java/org/zanata/model/HTextFlowBuilder.java b/zanata-war/src/test/java/org/zanata/model/HTextFlowBuilder.java index 599e8a4a0b..eaa9b3b4e7 100644 --- a/zanata-war/src/test/java/org/zanata/model/HTextFlowBuilder.java +++ b/zanata-war/src/test/java/org/zanata/model/HTextFlowBuilder.java @@ -1,8 +1,8 @@ package org.zanata.model; +import java.time.Instant; import java.util.Date; -import org.joda.time.DateTime; import org.zanata.common.ContentState; import org.zanata.model.po.HPotEntryData; @@ -39,7 +39,7 @@ public class HTextFlowBuilder { private String targetContent; private ContentState targetState; private HPerson lastModifiedBy; - private DateTime lastModifiedDate; + private Instant lastModifiedDate; private String targetComment; public HTextFlow build() { @@ -69,7 +69,7 @@ public HTextFlow build() { target.setTranslator(lastModifiedBy); } if (lastModifiedDate != null) { - target.setLastChanged(lastModifiedDate.toDate()); + target.setLastChangedInstant(lastModifiedDate); } else { target.setLastChanged(new Date()); } diff --git a/zanata-war/src/test/java/org/zanata/rest/service/DateRangeTest.java b/zanata-war/src/test/java/org/zanata/rest/service/DateRangeTest.java index b742720f5b..f0921cc5a5 100644 --- a/zanata-war/src/test/java/org/zanata/rest/service/DateRangeTest.java +++ b/zanata-war/src/test/java/org/zanata/rest/service/DateRangeTest.java @@ -1,46 +1,45 @@ package org.zanata.rest.service; import org.assertj.core.api.Assertions; -import org.joda.time.DateTime; -import org.joda.time.DateTimeZone; -import org.joda.time.Hours; -import org.joda.time.format.DateTimeFormat; -import org.joda.time.format.DateTimeFormatter; import org.junit.Test; +import java.time.Duration; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.temporal.ChronoUnit; + public class DateRangeTest { @Test public void testConcept() { + ZoneId bneZone = ZoneId.of("Australia/Brisbane"); + ZoneId shanghaiZone = ZoneId.of("Asia/Shanghai"); // 2 hours late - DateTimeZone bneZone = DateTimeZone.forID("Australia/Brisbane"); - DateTimeZone shanghaiZone = DateTimeZone.forID("Asia/Shanghai"); // 2 hours late - - DateTime bneTime = new DateTime(2015, 2, 1, 0, 0, bneZone); - DateTime shanghaiTime = new DateTime(2015, 2, 1, 0, 0, shanghaiZone); - int hours = Hours.hoursBetween(bneTime, shanghaiTime).getHours(); - Assertions.assertThat(hours).isEqualTo(2); + ZonedDateTime bneTime = ZonedDateTime.of(2015, 2, 1, 0, 0, 0, 0, bneZone); + ZonedDateTime shanghaiTime = ZonedDateTime.of(2015, 2, 1, 0, 0, 0, 0, shanghaiZone); + Assertions.assertThat(Duration.between(bneTime, shanghaiTime)).isEqualTo(Duration.of(2, ChronoUnit.HOURS)); - DateTime bneToShanghai = bneTime.toDateTime(shanghaiZone); - Assertions.assertThat(bneToShanghai.getMonthOfYear()).isEqualTo(1); + ZonedDateTime bneToShanghai = bneTime.withZoneSameInstant(shanghaiZone); + Assertions.assertThat(bneToShanghai.getMonthValue()).isEqualTo(1); Assertions.assertThat(bneToShanghai.getDayOfMonth()).isEqualTo(31); - Assertions.assertThat(bneToShanghai.getHourOfDay()).isEqualTo(22); + Assertions.assertThat(bneToShanghai.getHour()).isEqualTo(22); // now test our parser DateTimeFormatter bneFormat = - DateTimeFormat.forPattern("yyyy-MM-dd").withZone(bneZone); + DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(bneZone); DateTimeFormatter shanghaiFormat = bneFormat.withZone(shanghaiZone); - DateTime timeAsShanghai = shanghaiFormat.parseDateTime("2015-02-01"); - DateTime timeInBne = timeAsShanghai.toDateTime(bneZone); - Assertions.assertThat(timeInBne.getMonthOfYear()).isEqualTo(2); - Assertions.assertThat(timeInBne.getHourOfDay()).isEqualTo(2); + ZonedDateTime timeAsShanghai = ZonedDateTime.parse("2015-02-01 00:00:00", shanghaiFormat); + ZonedDateTime timeInBne = timeAsShanghai.withZoneSameInstant(bneZone); + Assertions.assertThat(timeInBne.getMonthValue()).isEqualTo(2); + Assertions.assertThat(timeInBne.getHour()).isEqualTo(2); - timeAsShanghai = shanghaiFormat.parseDateTime("2015-02-01"); - DateTime endOfDayShanghai = timeAsShanghai.plusDays(1).minusMillis(1); + timeAsShanghai = ZonedDateTime.parse("2015-02-01 00:00:00", shanghaiFormat); + ZonedDateTime endOfDayShanghai = timeAsShanghai.plusDays(1).minus(1, ChronoUnit.MILLIS); - timeInBne = endOfDayShanghai.toDateTime(bneZone); - Assertions.assertThat(timeInBne.getMonthOfYear()).isEqualTo(2); + timeInBne = endOfDayShanghai.withZoneSameInstant(bneZone); + Assertions.assertThat(timeInBne.getMonthValue()).isEqualTo(2); Assertions.assertThat(timeInBne.getDayOfMonth()).isEqualTo(2); } diff --git a/zanata-war/src/test/java/org/zanata/search/FilterConstraintToQueryJpaTest.java b/zanata-war/src/test/java/org/zanata/search/FilterConstraintToQueryJpaTest.java index b5d48f5aea..d8a43da54d 100644 --- a/zanata-war/src/test/java/org/zanata/search/FilterConstraintToQueryJpaTest.java +++ b/zanata-war/src/test/java/org/zanata/search/FilterConstraintToQueryJpaTest.java @@ -1,14 +1,16 @@ package org.zanata.search; +import static java.time.temporal.ChronoUnit.DAYS; import static org.hamcrest.MatcherAssert.assertThat; +import java.time.Instant; +import java.time.temporal.ChronoUnit; import java.util.List; import lombok.extern.slf4j.Slf4j; import org.hamcrest.Matchers; import org.hibernate.transform.ResultTransformer; -import org.joda.time.DateTime; import org.junit.Before; import org.junit.Test; import org.zanata.ZanataJpaTest; @@ -44,8 +46,8 @@ public class FilterConstraintToQueryJpaTest extends ZanataJpaTest { .addAll().build(); private HLocale hLocale; private DocumentId documentId; - private DateTime today = new DateTime(); - private DateTime yesterday = new DateTime().minusDays(1); + private Instant today = Instant.now(); + private Instant yesterday = today.minus(1, DAYS); private ResultTransformer transformer; private HPerson admin; private HPerson translator; diff --git a/zanata-war/src/test/java/org/zanata/util/DateUtilTest.java b/zanata-war/src/test/java/org/zanata/util/DateUtilTest.java new file mode 100644 index 0000000000..a24adc3ea7 --- /dev/null +++ b/zanata-war/src/test/java/org/zanata/util/DateUtilTest.java @@ -0,0 +1,61 @@ +package org.zanata.util; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.Date; + +import static java.time.temporal.ChronoUnit.DAYS; + +public class DateUtilTest { +// @Test +// public void testFormat() { +// Date now = new Date(); +// System.out.println(DateUtil.formatShortDate(now)); +// System.out.println(DateUtil.formatTime(now)); +// System.out.println(DateUtil.getHowLongAgoDescription(new Date(0))); +// System.out.println(DateUtil.getHowLongAgoDescription(Date.from(now.toInstant().minusMillis(10_000L)))); +// System.out.println(DateUtil.getHowLongAgoDescription(Date.from(now.toInstant().minusMillis(302_000L)))); +// System.out.println(DateUtil.getHowLongAgoDescription(Date.from(now.toInstant().minusMillis(3610_000L)))); +// System.out.println(DateUtil.getHowLongAgoDescription(Date.from(now.toInstant().minusMillis(72_600_000L)))); +// System.out.println(DateUtil.getHowLongAgoDescription(Date.from(now.toInstant().minusMillis(97_200_000L)))); +// +// System.out.println(DateUtil.getTimeRemainingDescription(10_000L)); +// System.out.println(DateUtil.getTimeRemainingDescription(302_000L)); +// System.out.println(DateUtil.getTimeRemainingDescription(3610_000L)); +// System.out.println(DateUtil.getTimeRemainingDescription(72_600_000L)); +// System.out.println(DateUtil.getTimeRemainingDescription(97_200_000L)); +// +// System.out.println(DateUtil.getUnitAndFigure(10_000L)); +// System.out.println(DateUtil.getUnitAndFigure(302_000L)); +// System.out.println(DateUtil.getUnitAndFigure(3610_000L)); +// System.out.println(DateUtil.getUnitAndFigure(72_600_000L)); +// System.out.println(DateUtil.getUnitAndFigure(97_200_000L)); +// +// System.out.println(DateUtil.getStartOfDay(now)); +// System.out.println(DateUtil.getEndOfTheDay(now)); +// System.out.println(DateUtil.getStartOfWeek(now)); +// System.out.println(DateUtil.getEndOfTheWeek(now)); +// System.out.println(DateUtil.getStartOfMonth(now)); +// System.out.println(DateUtil.getEndOfTheMonth(now)); +// +// System.out.println(DateUtil.getDate("31/12/1999 23:59", "dd/MM/yyyy HH:mm")); +// } + + @Test + public void testRanges() { + Date now = new Date(); + + // within range (true): + Date soon = Date.from(now.toInstant().plusSeconds(60)); + Assert.assertTrue(DateUtil.isDatesInRange(now, soon, 1)); + Date tomorrow = Date.from(now.toInstant().plus(1, DAYS)); + Assert.assertTrue(DateUtil.isDatesInRange(now, tomorrow, 1)); + + // outside range (false): + Date tomorrowPlus = Date.from(now.toInstant().plus(1, DAYS).plusMillis(1)); + Assert.assertFalse(DateUtil.isDatesInRange(now, tomorrowPlus, 1)); + Date dayAfterTomorrow = Date.from(now.toInstant().plus(2, DAYS)); + Assert.assertFalse(DateUtil.isDatesInRange(now, dayAfterTomorrow, 1)); + } +}