Home | History | Annotate | Download | only in time
      1 /*
      2  * Copyright (C) 2017 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package libcore.java.time;
     17 
     18 import org.junit.Test;
     19 import java.time.LocalDate;
     20 import java.time.LocalDateTime;
     21 import java.time.LocalTime;
     22 import java.time.Month;
     23 import java.time.ZoneId;
     24 import java.time.ZoneOffset;
     25 import java.time.ZonedDateTime;
     26 
     27 import static org.junit.Assert.assertEquals;
     28 
     29 
     30 /**
     31  * Additional tets for {@link ZonedDateTime}.
     32  *
     33  * @see tck.java.time.TCKZonedDateTime
     34  * @see test.java.time.TestZonedDateTime
     35  */
     36 public class ZonedDateTimeTest {
     37 
     38     // Europe/Vienna is UTC+2 during summer, UTC+1 during winter.
     39     private static final ZoneId ZONE_VIENNA = ZoneId.of("Europe/Vienna");
     40 
     41     // UTC+1, the offset during winter time.
     42     private static final ZoneOffset OFFSET_P1 = ZoneOffset.ofHours(1);
     43 
     44     // UTC+2, the offset during summer time.
     45     private static final ZoneOffset OFFSET_P2 = ZoneOffset.ofHours(2);
     46 
     47     // LocalDateTime during winter time (OFFSET_P1 in ZONE_VIENNA).
     48     private static final LocalDateTime LDT_P1 = LocalDateTime.of(2000, Month.JANUARY, 1, 0, 0);
     49 
     50     // LocalDateTime during summer time (OFFSET_P2 in ZONE_VIENNA).
     51     private static final LocalDateTime LDT_P2 = LocalDateTime.of(2000, Month.JUNE, 1, 0, 0);
     52 
     53     // LocalDateTime that is in a gap that occurs at the switch from winter time to summer time.
     54     // This is not a valid local time in ZONE_VIENNA.
     55     private static final LocalDateTime LDT_IN_GAP = LocalDateTime.of(2000, Month.MARCH, 26, 2, 30);
     56 
     57     // LocalDateTime that is in an overlap that occurs at the switch from summer time to winter
     58     // time. This LDT actually occurs twice in ZONE_VIENNA.
     59     private static final LocalDateTime LDT_IN_OVERLAP =
     60             LocalDateTime.of(2000, Month.OCTOBER, 29, 2, 30);
     61 
     62     @Test
     63     public void test_ofInstant() {
     64         // ofInstant behaves as if it calculated an Instant from the LocalDateTime/ZoneOffset
     65         // and then calling ofInstant(Instant, ZoneId). That's why "invalid" zone offsets are
     66         // tolerated and basically just change how the LocalDateTime is interpreted.
     67 
     68         // checkOfInstant(localDateTime, offset, zone, expectedDateTime, expectedOffset)
     69 
     70         // Correct offset in summer.
     71         checkOfInstant(LDT_P1, OFFSET_P1, ZONE_VIENNA, LDT_P1, OFFSET_P1);
     72         // Correct offset in winter.
     73         checkOfInstant(LDT_P2, OFFSET_P2, ZONE_VIENNA, LDT_P2, OFFSET_P2);
     74         // "Wrong" offset in winter.
     75         checkOfInstant(LDT_P1, OFFSET_P2, ZONE_VIENNA, LDT_P1.minusDays(1).withHour(23), OFFSET_P1);
     76         // "Wrong" offset in summer.
     77         checkOfInstant(LDT_P2, OFFSET_P1, ZONE_VIENNA, LDT_P2.withHour(1), OFFSET_P2);
     78 
     79         // Very wrong offset in winter.
     80         checkOfInstant(LDT_P1, ZoneOffset.ofHours(-10), ZONE_VIENNA, LDT_P1.withHour(11),
     81                 OFFSET_P1);
     82 
     83         // Neither of those combinations exist, so they are interpreted as either before or after
     84         // the gap, depending on the offset.
     85         checkOfInstant(LDT_IN_GAP, OFFSET_P1, ZONE_VIENNA, LDT_IN_GAP.plusHours(1), OFFSET_P2);
     86         checkOfInstant(LDT_IN_GAP, OFFSET_P2, ZONE_VIENNA, LDT_IN_GAP.minusHours(1), OFFSET_P1);
     87 
     88         // Both combinations exist and are valid, so they produce exactly the input.
     89         checkOfInstant(LDT_IN_OVERLAP, OFFSET_P1, ZONE_VIENNA, LDT_IN_OVERLAP, OFFSET_P1);
     90         checkOfInstant(LDT_IN_OVERLAP, OFFSET_P2, ZONE_VIENNA, LDT_IN_OVERLAP, OFFSET_P2);
     91     }
     92 
     93     /**
     94      * Assert that calling {@link ZonedDateTime#ofInstant(LocalDateTime, ZoneOffset, ZoneId)} with
     95      * the first three parameters produces a sane result with the localDateTime and offset equal to
     96      * the last two.
     97      */
     98     private static void checkOfInstant(LocalDateTime localDateTime, ZoneOffset offset,
     99             ZoneId zone, LocalDateTime expectedDateTime, ZoneOffset expectedOffset) {
    100         ZonedDateTime zonedDateTime = ZonedDateTime.ofInstant(localDateTime, offset, zone);
    101         String message = String.format(" for ofInstant(%s, %s, %s) = %s, ",
    102                 localDateTime, offset, zone, zonedDateTime);
    103         // Note that localDateTime doesn't necessarily equal zoneDateTime.toLocalDateTime(),
    104         // specifically when offset is not a valid offset for zone at localDateTime (or ever).
    105         assertEquals("zone" + message, zone, zonedDateTime.getZone());
    106 
    107         assertEquals("offset" + message, expectedOffset, zonedDateTime.getOffset());
    108         assertEquals("localDateTime" + message, expectedDateTime, zonedDateTime.toLocalDateTime());
    109         if (offset.equals(expectedOffset)) {
    110             // When we get same offset, the localDateTime must be the same as the input. This
    111             // assert basically just verifies that the test is written correctly.
    112             assertEquals("expected localDateTime" + message,
    113                     expectedDateTime, zonedDateTime.toLocalDateTime());
    114         }
    115     }
    116 
    117     @Test(expected = NullPointerException.class)
    118     public void test_ofInstant_localDateTime_null() {
    119         ZonedDateTime.ofInstant(null, OFFSET_P1, ZONE_VIENNA);
    120     }
    121 
    122     @Test(expected = NullPointerException.class)
    123     public void test_ofInstant_offset_null() {
    124         ZonedDateTime.ofInstant(LDT_P1, null, ZONE_VIENNA);
    125     }
    126 
    127     @Test(expected = NullPointerException.class)
    128     public void test_ofInstant_zone_null() {
    129         ZonedDateTime.ofInstant(LDT_P1, OFFSET_P1, null);
    130     }
    131 
    132     @Test
    133     public void test_ofLocal() {
    134         // checkOfLocal(localDateTime, zone, preferredOffset, expectedDateTime, expectedOffset)
    135 
    136         // Correct offset in summer.
    137         checkOfLocal(LDT_P1, ZONE_VIENNA, OFFSET_P1, LDT_P1, OFFSET_P1);
    138         // Correct offset in winter.
    139         checkOfLocal(LDT_P2, ZONE_VIENNA, OFFSET_P2, LDT_P2, OFFSET_P2);
    140         // "Wrong" offset in winter.
    141         checkOfLocal(LDT_P1, ZONE_VIENNA, OFFSET_P2, LDT_P1, OFFSET_P1);
    142         // "Wrong" offset in summer.
    143         checkOfLocal(LDT_P2, ZONE_VIENNA, OFFSET_P1, LDT_P2, OFFSET_P2);
    144         // Very wrong offset in winter.
    145         checkOfLocal(LDT_P1, ZONE_VIENNA, ZoneOffset.ofHours(-10), LDT_P1, OFFSET_P1);
    146 
    147         // Neither of those combinations exist, so they are interpreted as after the gap.
    148         checkOfLocal(LDT_IN_GAP, ZONE_VIENNA, OFFSET_P1, LDT_IN_GAP.plusHours(1), OFFSET_P2);
    149         checkOfLocal(LDT_IN_GAP, ZONE_VIENNA, OFFSET_P2, LDT_IN_GAP.plusHours(1), OFFSET_P2);
    150 
    151         // Both combinations exist and are valid, so they produce exactly the input.
    152         checkOfLocal(LDT_IN_OVERLAP, ZONE_VIENNA, OFFSET_P1, LDT_IN_OVERLAP, OFFSET_P1);
    153         checkOfLocal(LDT_IN_OVERLAP, ZONE_VIENNA, OFFSET_P2, LDT_IN_OVERLAP, OFFSET_P2);
    154 
    155         // Passing in null for preferredOffset will be biased to the offset before the transition.
    156         checkOfLocal(LDT_IN_OVERLAP, ZONE_VIENNA, /* preferredOffset */ null,
    157                 LDT_IN_OVERLAP, OFFSET_P2);
    158         // Passing in an invalid offset will be biased to the offset before the transition.
    159         checkOfLocal(LDT_IN_OVERLAP, ZONE_VIENNA, ZoneOffset.ofHours(10),
    160                 LDT_IN_OVERLAP, OFFSET_P2);
    161     }
    162 
    163     /**
    164      * Assert that calling {@link ZonedDateTime#ofLocal(LocalDateTime, ZoneId, ZoneOffset)} with
    165      * the first three parameters produces a sane result with the localDateTime, and offset equal
    166      * to the last two.
    167      */
    168     private static void checkOfLocal(LocalDateTime localDateTime, ZoneId zone,
    169             ZoneOffset preferredOffset, LocalDateTime expectedDateTime, ZoneOffset expectedOffset) {
    170         ZonedDateTime zonedDateTime = ZonedDateTime.ofLocal(localDateTime, zone, preferredOffset);
    171         String message = String.format(" for ofLocal(%s, %s, %s) = %s, ",
    172                 localDateTime, zone, preferredOffset, zonedDateTime);
    173         // Note that localDateTime doesn't necessarily equal zoneDateTime.toLocalDateTime(),
    174         // specifically when offset is not a valid offset for zone at localDateTime (or ever).
    175         assertEquals("zone" + message, zone, zonedDateTime.getZone());
    176         assertEquals("offset" + message, expectedOffset, zonedDateTime.getOffset());
    177         assertEquals("localDateTime" + message, expectedDateTime, zonedDateTime.toLocalDateTime());
    178     }
    179 
    180     @Test(expected = NullPointerException.class)
    181     public void test_ofLocal_localDateTime_null() {
    182         ZonedDateTime.ofLocal(null, ZONE_VIENNA, OFFSET_P1);
    183     }
    184 
    185     @Test(expected = NullPointerException.class)
    186     public void test_ofLocal_zone_null() {
    187         ZonedDateTime.ofLocal(LDT_P1, null, OFFSET_P1);
    188     }
    189 }
    190