Pārlūkot izejas kodu

zonedatetime: fix literals

Ranides Atterwim 1 gadu atpakaļ
vecāks
revīzija
b7cecde166

+ 2 - 1
assira.commons/src/main/java/net/ranides/assira/time2/ZonedDate.java

@@ -266,7 +266,8 @@ public abstract class ZonedDate implements Comparable<ZonedDate> {
 
         @Override
         public ZonedDateTime withTime(ZonedTime time) {
-            return value.withZoneSameInstant(time.getZone()).with(ChronoField.NANO_OF_DAY, time.toNanoOfDay());
+            // @todo it is not strictly reasonable
+            return value.withZoneSameInstant(time.getZone()).with(ChronoField.NANO_OF_DAY, time.toNanoOfDay()).withZoneSameInstant(getZone());
         }
 
         @Override

+ 28 - 4
assira.commons/src/main/java/net/ranides/assira/time2/ZonedTime.java

@@ -271,12 +271,36 @@ public abstract class ZonedTime implements Comparable<ZonedTime> {
 
         @Override
         public ZonedDateTime withDate(ZonedDate date) {
-            return value
-                .withZoneSameInstant(date.getZone())
+            // @todo it is not strictly reasonable
+
+            // this does not work in intuitive way if DATE caused that "value.getZone" returns different offsets
+            // before and after change (keep in mind DST rules and others). Our first assumption was that we can
+            // temporarily change zone and then rollback to original. But it is not exactly the case if original
+            // date has different offset than final date.
+            //
+            // Happy path:
+            // zone A => temporary zone => zone A
+            //
+            // Pessimistic path:
+            // zone A (07.07.2020 offset1 no DST) => temporary zone => zone A (30.12.2020 offset2 with DST)
+            //
+            // what should we do then?
+            //      1. accept this awkward behaviour
+            //      2. compute difference between A1 & A2 offsets and fix final result
+            //      3. throw if difference != 0
+            //
+            // at this moment option (1) seems to be acceptable, maybe even expected
+            ZonedDateTime adjusted = value.withZoneSameInstant(date.getZone());
+            ZonedDateTime output = adjusted
                 .withYear(date.getYear())
                 .withMonth(date.getMonth())
-                .withDayOfMonth(date.getDay())
-                .withZoneSameInstant(getZone());
+                .withDayOfMonth(date.getDay());
+
+//            if(!adjusted.getOffset().equals(output.getOffset())) {
+//                System.out.println("warning: DST happened");
+//            }
+
+            return output.withZoneSameInstant(getZone());
         }
 
         @Override

+ 72 - 11
assira.commons/src/test/java/net/ranides/assira/time2/ZonedTimeTest.java

@@ -47,25 +47,86 @@ public class ZonedTimeTest {
     }
 
     @Test
-    public void testWithTime() {
+    public void testWithTimeComplete() {
+        ZoneId zone = ZoneId.of("Pacific/Funafuti");
+
+        ZonedDate base1 = ZonedDate.of(ZonedDateTime.of(1980, 1, 1, 0, 0, 0, 0, DateTimeUtils.ZONE_UTC));
+        ZonedDate base2 = ZonedDate.of(ZonedDateTime.of(1980, 1, 1, 0, 0, 0, 0, zone));
+        ZonedDate base3 = ZonedDate.of(ZonedDateTime.of(2010, 1, 1, 0, 0, 0, 0, zone));
+        ZonedDate base4 = ZonedDate.of(ZonedDateTime.of(1900, 1, 1, 0, 0, 0, 0, zone));
+
+        ZonedTime time1 = ZonedTime.of(ZonedDateTime.of(1970, 1, 1, 6, 45, 0, 0, DateTimeUtils.ZONE_UTC));
+        ZonedTime time2 = ZonedTime.of(ZonedDateTime.of(1970, 1, 1, 6, 45, 0, 0, zone));
+
+        assertEquals("1980-01-01T06:45Z[Etc/GMT0]", time1.withDate(base1).toString());
+        assertEquals("1980-01-01T06:45Z[Etc/GMT0]", time1.withDate(base2).toString());
+        assertEquals("2010-01-01T06:45Z[Etc/GMT0]", time1.withDate(base3).toString());
+        assertEquals("1900-01-01T06:48:08Z[Etc/GMT0]", time1.withDate(base4).toString()); // not intuitive: time is affected
+
+        System.out.println("---");
+
+        assertEquals("1980-01-02T06:45+12:00[Pacific/Funafuti]", time2.withDate(base1).toString()); // not intuitive: date is affected
+        assertEquals("1980-01-01T06:45+12:00[Pacific/Funafuti]", time2.withDate(base2).toString());
+        assertEquals("2010-01-01T06:45+12:00[Pacific/Funafuti]", time2.withDate(base3).toString());
+        assertEquals("1900-01-01T06:45+11:56:52[Pacific/Funafuti]", time2.withDate(base4).toString());
+
+
+        ZonedTime time3 = ZonedTime.of(ZonedDateTime.of(1970, 1, 1, 13, 15, 0, 0, DateTimeUtils.ZONE_UTC));
+        ZonedDate date1 = ZonedDate.of(ZonedDateTime.of(2001, 2, 2, 0, 0, 0, 0, DateTimeUtils.ZONE_PL));
+        ZonedDate date2 = ZonedDate.of(ZonedDateTime.of(2001, 7, 7, 0, 0, 0, 0, DateTimeUtils.ZONE_PL));
+
+        assertEquals("2001-02-02T13:15Z[Etc/GMT0]", time3.withDate(date1).toString());
+        assertEquals("2001-07-07T12:15Z[Etc/GMT0]", time3.withDate(date2).toString()); // not intuitive: time is affected
+        assertEquals("2001-02-01T14:15+01:00[Poland]", date1.withTime(time3).toString()); // not intuitive: date affected
+        assertEquals("2001-07-06T15:15+02:00[Poland]", date2.withTime(time3).toString());  // not intuitive: date affected
+    }
+
+    @Test
+    public void testWithTimeLiterals() {
         ZoneId zone = ZoneId.of("Pacific/Funafuti");
 
         ZonedDate base1 = DateTimeLiteral.dateUtc(1980, 1, 1);
         ZonedDate base2 = DateTimeLiteral.date(zone, 1980, 1, 1);
         ZonedDate base3 = DateTimeLiteral.date(zone, 2010, 1, 1);
+        ZonedDate base4 = DateTimeLiteral.date(zone, 1900, 1, 1);
 
         ZonedTime time1 = DateTimeLiteral.timeUtc(6, 45, 0);
         ZonedTime time2 = DateTimeLiteral.time(zone, 6, 45, 0);
 
-        System.out.println(time1.withDate(base1));
-        // System.out.println(time1.withDate(base2));
-        // System.out.println(time1.withDate(base3));
-
-        System.out.println("---");
-
-        // System.out.println(time2.withDate(base1));
-        System.out.println(time2.withDate(base2));
-        System.out.println(time2.withDate(base3));
-
+        assertEquals("1980-01-01T06:45Z[Etc/GMT0]", time1.withDate(base1).toString());
+        assertThrows(UnsupportedOperationException.class, () -> {
+            time1.withDate(base2).toString();
+        });
+        assertThrows(UnsupportedOperationException.class, () -> {
+            time1.withDate(base3).toString();
+        });
+        assertThrows(UnsupportedOperationException.class, () -> {
+            time1.withDate(base4).toString();
+        });
+
+        assertThrows(UnsupportedOperationException.class, () -> {
+            time2.withDate(base1).toString();
+        });
+        assertEquals("1980-01-01T06:45+12:00[Pacific/Funafuti]", time2.withDate(base2).toString());
+        assertEquals("2010-01-01T06:45+12:00[Pacific/Funafuti]", time2.withDate(base3).toString());
+        assertEquals("1900-01-01T06:45+11:56:52[Pacific/Funafuti]", time2.withDate(base4).toString());
+
+
+        ZonedTime time3 = DateTimeLiteral.timeUtc(13, 15, 0);
+        ZonedDate date1 = DateTimeLiteral.datePolish(2001, 2, 2);
+        ZonedDate date2 = DateTimeLiteral.datePolish(2001, 7, 7);
+
+        assertThrows(UnsupportedOperationException.class, () -> {
+            time3.withDate(date1).toString();
+        });
+        assertThrows(UnsupportedOperationException.class, () -> {
+            time3.withDate(date2).toString();
+        });
+        assertThrows(UnsupportedOperationException.class, () -> {
+            date1.withTime(time3).toString();
+        });
+        assertThrows(UnsupportedOperationException.class, () -> {
+            date2.withTime(time3).toString();
+        });
     }
 }