Pārlūkot izejas kodu

draft: datetime

Ranides Atterwim 11 mēneši atpakaļ
vecāks
revīzija
7421bc2755

+ 6 - 6
assira.commons/src/main/java/net/ranides/assira/time/DateTimeFormat.java

@@ -204,14 +204,14 @@ public class DateTimeFormat {
         return printFormatter().format(input);
     }
 
-    public String formatDate(ZonedDate input) {
-        // @todo validate zone conversion
-        return printFormatter().format(input.withZero());
+    public String formatDate(Temporal input) {
+        // @todo validate zone conversion, test
+        return printFormatter().format(input.with(LocalTime.MIN));
     }
 
-    public String formatTime(ZonedTime input) {
-        // @todo validate zone conversion
-        return printFormatter().format(input.withZero());
+    public String formatTime(Temporal input) {
+        // @todo validate zone conversion, test
+        return printFormatter().format(input.with(LocalDate.ofEpochDay(0)));
     }
 
     public ZonedDateTime parse(String input) {

+ 13 - 16
assira.core/src/main/java/net/ranides/assira/time/FormatTime.java

@@ -15,11 +15,7 @@ import java.util.regex.Pattern;
  * Utility class built on top of {@link SimpleDateFormat}.
  */
 @UtilityClass
-public class FormatTime {
-
-    private static final String DATE = "yyyy-MM-dd";
-
-    private static final String TIME = "HH:mm:ss";
+public class DateTimeFormatUtils {
 
     private static final String DATE_TIME = "yyyy-MM-dd HH:mm:ss";
 
@@ -32,8 +28,9 @@ public class FormatTime {
      * @param time time
      * @return String
      */
-    public static String asDate(Date time) {
-        return asText(DATE, time);
+    public static String formatDate(Date time) {
+        // @todo test
+        return DateTimeFormat.DATE.formatDate(time.toInstant());
     }
 
     /**
@@ -42,8 +39,8 @@ public class FormatTime {
      * @param time time
      * @return String
      */
-    public static String asTime(Date time) {
-        return asText(TIME, time);
+    public static String formatTime(Date time) {
+        return DateTimeFormat.TIME.formatTime(time.toInstant());
     }
 
     /**
@@ -52,8 +49,8 @@ public class FormatTime {
      * @param time time
      * @return String
      */
-    public static String asDateTime(Date time) {
-        return asText(DATE_TIME, time);
+    public static String formatDateTime(Date time) {
+        return DateTimeFormat.DATETIME.format(time.toInstant());
     }
 
     /**
@@ -63,7 +60,7 @@ public class FormatTime {
      * @param time time
      * @return String
      */
-    private static String asText(String pattern, Date time) {
+    private static String format(String pattern, Date time) {
         return new SimpleDateFormat(pattern).format(time);
     }
 
@@ -75,7 +72,7 @@ public class FormatTime {
      * @param text text
      * @return Duration
      */
-    public static Duration asDuration(String text) {
+    public static Duration parseDuration(String text) {
         Matcher hit = TIME_TO_MS.matcher(text.replace(',', '.'));
         if (hit.matches()) {
             double h = asNumber(hit.group(1));
@@ -100,8 +97,8 @@ public class FormatTime {
      * @param duration duration
      * @return String
      */
-    public static String asText(Duration duration) {
-        return asText(duration, ChronoUnit.MILLIS);
+    public static String formatDuration(Duration duration) {
+        return formatDuration(duration, ChronoUnit.MILLIS);
     }
 
     /**
@@ -118,7 +115,7 @@ public class FormatTime {
      *
      * @return String
      */
-    public static String asText(Duration duration, TemporalUnit precision) {
+    public static String formatDuration(Duration duration, TemporalUnit precision) {
         long ts = duration.getSeconds();
         long tn = duration.getNano();
 

+ 29 - 1
assira.commons/src/main/java/net/ranides/assira/time/DateTimeUtils.java

@@ -6,9 +6,17 @@ import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.sql.Timestamp;
-import java.time.*;
+import java.time.DayOfWeek;
+import java.time.Duration;
+import java.time.LocalTime;
+import java.time.OffsetDateTime;
+import java.time.Period;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
 import java.time.temporal.ChronoUnit;
+import java.time.temporal.Temporal;
 import java.time.temporal.TemporalAdjusters;
+import java.time.temporal.TemporalQueries;
 import java.util.Locale;
 import java.util.Objects;
 
@@ -253,4 +261,24 @@ public class DateTimeUtils {
         return Objects.nonNull(datetime) && datetime.getDayOfWeek() == DayOfWeek.SATURDAY;
     }
 
+    @Contract("null -> null")
+    public static ZoneId getZone(@Nullable Temporal input) {
+        if(Objects.isNull(input)) {
+            return null;
+        } else {
+            return input.query(TemporalQueries.zone());
+        }
+    }
+
+    @Contract("null,_ -> null")
+    public static <T extends Temporal> T requireZone(@NotNull ZoneId expected, @Nullable T input) {
+        if(input != null) {
+            ZoneId zone = getZone(input);
+            if(zone !=null && !zone.equals(expected)) {
+                throw new IllegalArgumentException("TimeZone mismatch: " + expected + " != " + input);
+            }
+        }
+        return input;
+    }
+
 }

+ 26 - 10
assira.commons/src/main/java/net/ranides/assira/time/ZonedDate.java

@@ -9,18 +9,25 @@ import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
 import java.sql.Timestamp;
-import java.time.*;
+import java.time.Instant;
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.time.Period;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
 import java.time.temporal.ChronoField;
 import java.time.temporal.ChronoUnit;
 import java.time.temporal.Temporal;
 import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalQuery;
 import java.time.temporal.TemporalUnit;
 import java.util.Objects;
 
 
 @JsonDeserialize(using = ZonedDateDeserializer.class)
 @JsonSerialize(using = ZonedDateSerializer.class)
-public class ZonedDate implements Comparable<ZonedDate>, Temporal {
+public class ZonedDate implements Comparable<ZonedDate>, Temporal, ZonedRange {
 
     private final ZoneId zone;
 
@@ -162,16 +169,14 @@ public class ZonedDate implements Comparable<ZonedDate>, Temporal {
         return withMin();
     }
 
-    public ZonedDateTime withMidnight() {
-        return withMin();
-    }
-
-    public ZonedDateTime atStartOfDay() {
-        return withMin();
+    @Override
+    public ZonedDateTime begin() {
+        return withZero();
     }
 
-    public ZonedDateTime atEndOfDay() {
-        return withMax();
+    @Override
+    public ZonedDateTime end() {
+        return withZero().plusDays(1);
     }
 
     @Override
@@ -269,4 +274,15 @@ public class ZonedDate implements Comparable<ZonedDate>, Temporal {
         return date.getLong(field);
     }
 
+    @Override
+    public  <R> R query(TemporalQuery<R> query) {
+        if (query == TemporalQueries.zone() || query == TemporalQueries.zoneId()) {
+            return (R) getZone();
+        }
+        else if (query == TemporalQueries.precision()) {
+            return (R)ChronoUnit.DAYS;
+        }
+        return query.queryFrom(date);
+    }
+
 }

+ 7 - 7
assira.commons/src/main/java/net/ranides/assira/time/ZonedDateSet.java

@@ -13,17 +13,17 @@ import static java.time.LocalDateTime.MIN;
 // @todo ZonedDateSet
 public abstract class ZonedDateSet {
 
-    public boolean contains(ZonedDate date) {
-        return !contains(ZonedRange.of(date)).isZero();
+    public boolean containsFully(ZonedRange range) {
+        return intersection(range).equals(Duration.ofDays(1));
     }
 
-    public boolean containsFully(ZonedDate date) {
-        return contains(ZonedRange.of(date)).equals(Duration.ofDays(1));
+    public boolean contains(ZonedDate date) {
+        return !intersection(ZonedRange.of(date)).isZero();
     }
 
     public abstract boolean contains(ZonedDateTime datetime);
 
-    public abstract Duration contains(ZonedRange range);
+    public abstract Duration intersection(ZonedRange range);
 
     public static class Empty extends ZonedDateSet {
 
@@ -33,7 +33,7 @@ public abstract class ZonedDateSet {
         }
 
         @Override
-        public Duration contains(ZonedRange range) {
+        public Duration intersection(ZonedRange range) {
             return null;
         }
     }
@@ -51,7 +51,7 @@ public abstract class ZonedDateSet {
 
         @ZoneHazard
         @Override
-        public Duration contains(ZonedRange range) {
+        public Duration intersection(ZonedRange range) {
             ZonedDateTime lower = range.begin();
             ZonedDateTime upper = range.end();
 

+ 37 - 27
assira.commons/src/main/java/net/ranides/assira/time/ZonedRange.java

@@ -7,43 +7,53 @@ import static net.ranides.assira.time.DateTimeUtils.max;
 import static net.ranides.assira.time.DateTimeUtils.min;
 
 // @todo ZonedRange
-public class ZonedRange {
+public interface ZonedRange {
 
-    private final ZonedDateTime begin;
-
-    private final ZonedDateTime end;
-
-    private ZonedRange(ZonedDateTime begin, ZonedDateTime end) {
-        if(begin.isAfter(end)) {
-            this.begin = end;
-            this.end = begin;
-        } else {
-            this.begin = begin;
-            this.end = end;
-        }
+    static ZonedRange of(ZonedDateTime begin, ZonedDateTime end) {
+        return new Simple(begin, end);
     }
 
-    public static ZonedRange of(ZonedDateTime begin, ZonedDateTime end) {
-        return new ZonedRange(begin, end);
+    static ZonedRange of(ZonedDate date) {
+        return new Simple(date.withMin(), date.plusDays(1).withMin());
     }
 
-    public static ZonedRange of(ZonedDate date) {
-        return new ZonedRange(date.withMin(), date.plusDays(1).withMin());
-    }
+    ZonedDateTime begin();
 
-    public ZonedDateTime begin() {
-        return begin;
-    }
+    ZonedDateTime end();
 
-    public ZonedDateTime end() {
-        return end;
+    default Duration duration() {
+        return Duration.between(begin(), end());
     }
 
-    public Duration duration() {
-        return Duration.between(begin, end);
+    default ZonedRange intersection(ZonedRange range) {
+        return of(max(range.begin(), begin()), min(range.end(), end()));
     }
 
-    public ZonedRange intersection(ZonedRange range) {
-        return of(max(range.begin(), begin), min(range.end(), end));
+    class Simple implements ZonedRange {
+
+        private final ZonedDateTime begin;
+
+        private final ZonedDateTime end;
+
+        private Simple(ZonedDateTime begin, ZonedDateTime end) {
+            if (begin.isAfter(end)) {
+                this.begin = end;
+                this.end = begin;
+            } else {
+                this.begin = begin;
+                this.end = end;
+            }
+        }
+
+        @Override
+        public ZonedDateTime begin() {
+            return begin;
+        }
+
+        @Override
+        public ZonedDateTime end() {
+            return end;
+        }
+
     }
 }

+ 13 - 0
assira.commons/src/main/java/net/ranides/assira/time/ZonedTime.java

@@ -19,6 +19,8 @@ import java.time.temporal.ChronoField;
 import java.time.temporal.ChronoUnit;
 import java.time.temporal.Temporal;
 import java.time.temporal.TemporalField;
+import java.time.temporal.TemporalQueries;
+import java.time.temporal.TemporalQuery;
 import java.time.temporal.TemporalUnit;
 import java.util.Objects;
 
@@ -290,4 +292,15 @@ public class ZonedTime implements Comparable<ZonedTime>, Temporal {
         return time + " [" + zone + "]";
     }
 
+    @Override
+    public  <R> R query(TemporalQuery<R> query) {
+        if (query == TemporalQueries.zone() || query == TemporalQueries.zoneId()) {
+            return (R) getZone();
+        }
+        else if (query == TemporalQueries.precision()) {
+            return (R)ChronoUnit.NANOS;
+        }
+        return query.queryFrom(time);
+    }
+
 }

+ 1 - 1
assira.commons/src/main/java/net/ranides/assira/time/json/JsonFormatUtils.java

@@ -9,7 +9,7 @@ import java.time.format.DateTimeFormatter;
 import java.util.Arrays;
 
 @UtilityClass
-public class JsonFormatUtils {
+class JsonFormatUtils {
 
     public static DateTimeFormat adjustFormatter(DateTimeFormat formatter, JsonFormat.Value options) {
         if(options.hasPattern()) {

+ 39 - 0
assira.commons/src/test/java/net/ranides/assira/time/DateTimeFormatUtilsTest.java

@@ -0,0 +1,39 @@
+package net.ranides.assira.time;
+
+import org.junit.Test;
+
+import java.time.Duration;
+import java.time.temporal.ChronoUnit;
+
+import static org.junit.Assert.*;
+
+public class DateTimeFormatUtilsTest {
+
+    @Test
+    public void asText() {
+        Duration a = Duration.ofSeconds(3600 + 45 * 60).plusSeconds(45).plusMillis(750).plusNanos(17800);
+        Duration b = Duration.ofSeconds(3600 + 25 * 60).plusSeconds(45).plusMillis(750);
+        Duration c = Duration.ofSeconds(7200 + 45 * 60);
+
+        assertEquals("2h", DateTimeFormatUtils.formatDuration(a, ChronoUnit.HOURS));
+        assertEquals("1h 46m", DateTimeFormatUtils.formatDuration(a, ChronoUnit.MINUTES));
+        assertEquals("1h 45m 46s", DateTimeFormatUtils.formatDuration(a, ChronoUnit.SECONDS));
+        assertEquals("1h 45m 45s 750ms", DateTimeFormatUtils.formatDuration(a));
+        assertEquals("1h 45m 45s 750ms 18µs", DateTimeFormatUtils.formatDuration(a, ChronoUnit.MICROS));
+        assertEquals("1h 45m 45s 750ms 17µs 800ns", DateTimeFormatUtils.formatDuration(a, ChronoUnit.NANOS));
+
+        assertEquals("1h", DateTimeFormatUtils.formatDuration(b, ChronoUnit.HOURS));
+        assertEquals("1h 26m", DateTimeFormatUtils.formatDuration(b, ChronoUnit.MINUTES));
+        assertEquals("1h 25m 46s", DateTimeFormatUtils.formatDuration(b, ChronoUnit.SECONDS));
+        assertEquals("1h 25m 45s 750ms", DateTimeFormatUtils.formatDuration(b));
+        assertEquals("1h 25m 45s 750ms", DateTimeFormatUtils.formatDuration(b, ChronoUnit.MICROS));
+        assertEquals("1h 25m 45s 750ms", DateTimeFormatUtils.formatDuration(b, ChronoUnit.NANOS));
+
+        assertEquals("3h", DateTimeFormatUtils.formatDuration(c, ChronoUnit.HOURS));
+        assertEquals("2h 45m", DateTimeFormatUtils.formatDuration(c, ChronoUnit.MINUTES));
+        assertEquals("2h 45m", DateTimeFormatUtils.formatDuration(c, ChronoUnit.SECONDS));
+        assertEquals("2h 45m", DateTimeFormatUtils.formatDuration(c));
+        assertEquals("2h 45m", DateTimeFormatUtils.formatDuration(c, ChronoUnit.MICROS));
+        assertEquals("2h 45m", DateTimeFormatUtils.formatDuration(c, ChronoUnit.NANOS));
+    }
+}

+ 0 - 39
assira.core/src/test/java/net/ranides/assira/time/TimeFormatTest.java

@@ -1,39 +0,0 @@
-package net.ranides.assira.time;
-
-import org.junit.Test;
-
-import java.time.Duration;
-import java.time.temporal.ChronoUnit;
-
-import static org.junit.Assert.*;
-
-public class TimeFormatTest {
-
-    @Test
-    public void asText() {
-        Duration a = Duration.ofSeconds(3600 + 45 * 60).plusSeconds(45).plusMillis(750).plusNanos(17800);
-        Duration b = Duration.ofSeconds(3600 + 25 * 60).plusSeconds(45).plusMillis(750);
-        Duration c = Duration.ofSeconds(7200 + 45 * 60);
-
-        assertEquals("2h", FormatTime.asText(a, ChronoUnit.HOURS));
-        assertEquals("1h 46m", FormatTime.asText(a, ChronoUnit.MINUTES));
-        assertEquals("1h 45m 46s", FormatTime.asText(a, ChronoUnit.SECONDS));
-        assertEquals("1h 45m 45s 750ms", FormatTime.asText(a));
-        assertEquals("1h 45m 45s 750ms 18µs", FormatTime.asText(a, ChronoUnit.MICROS));
-        assertEquals("1h 45m 45s 750ms 17µs 800ns", FormatTime.asText(a, ChronoUnit.NANOS));
-
-        assertEquals("1h", FormatTime.asText(b, ChronoUnit.HOURS));
-        assertEquals("1h 26m", FormatTime.asText(b, ChronoUnit.MINUTES));
-        assertEquals("1h 25m 46s", FormatTime.asText(b, ChronoUnit.SECONDS));
-        assertEquals("1h 25m 45s 750ms", FormatTime.asText(b));
-        assertEquals("1h 25m 45s 750ms", FormatTime.asText(b, ChronoUnit.MICROS));
-        assertEquals("1h 25m 45s 750ms", FormatTime.asText(b, ChronoUnit.NANOS));
-
-        assertEquals("3h", FormatTime.asText(c, ChronoUnit.HOURS));
-        assertEquals("2h 45m", FormatTime.asText(c, ChronoUnit.MINUTES));
-        assertEquals("2h 45m", FormatTime.asText(c, ChronoUnit.SECONDS));
-        assertEquals("2h 45m", FormatTime.asText(c));
-        assertEquals("2h 45m", FormatTime.asText(c, ChronoUnit.MICROS));
-        assertEquals("2h 45m", FormatTime.asText(c, ChronoUnit.NANOS));
-    }
-}