1/*
2 * Copyright (C) 2010 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
17package libcore.java.util;
18
19import java.time.Instant;
20import java.util.Calendar;
21import java.util.Date;
22import java.util.Locale;
23import java.util.TimeZone;
24import junit.framework.TestCase;
25
26public class DateTest extends TestCase {
27    // http://code.google.com/p/android/issues/detail?id=6013
28    public void test_toString_us() throws Exception {
29        // Ensure that no matter where this is run, we know what time zone to expect.
30        Locale.setDefault(Locale.US);
31        TimeZone.setDefault(TimeZone.getTimeZone("America/Chicago"));
32        assertEquals("Wed Dec 31 18:00:00 CST 1969", new Date(0).toString());
33    }
34
35    // https://code.google.com/p/android/issues/detail?id=81924
36    public void test_toString_nonUs() {
37        // The string for the timezone depends on what the default locale is. Not every locale
38        // has a short-name for America/Chicago -> CST.
39        Locale.setDefault(Locale.CHINA);
40        TimeZone.setDefault(TimeZone.getTimeZone("America/Chicago"));
41        assertEquals("Wed Dec 31 18:00:00 CST 1969", new Date(0).toString());
42    }
43
44    public void test_toGMTString_us() throws Exception {
45        // Based on https://issues.apache.org/jira/browse/HARMONY-501
46        TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles"));
47        Locale.setDefault(Locale.US);
48
49        Calendar c = Calendar.getInstance();
50        c.clear();
51        c.set(Calendar.YEAR, 21);
52        assertEquals("Wed Jan 01 00:00:00 PST 21", c.getTime().toString());
53        assertEquals("1 Jan 21 08:00:00 GMT", c.getTime().toGMTString());
54        c.set(Calendar.YEAR, 321);
55        assertEquals("Sun Jan 01 00:00:00 PST 321", c.getTime().toString());
56        assertEquals("1 Jan 321 08:00:00 GMT", c.getTime().toGMTString());
57    }
58
59    public void test_toGMTString_nonUs() throws Exception {
60        TimeZone.setDefault(TimeZone.getTimeZone("America/Los_Angeles"));
61        Locale.setDefault(Locale.UK);
62
63        Calendar c = Calendar.getInstance();
64        c.clear();
65        c.set(Calendar.YEAR, 21);
66        assertEquals("Wed Jan 01 00:00:00 PST 21", c.getTime().toString());
67        assertEquals("1 Jan 21 08:00:00 GMT", c.getTime().toGMTString());
68        c.set(Calendar.YEAR, 321);
69        assertEquals("Sun Jan 01 00:00:00 PST 321", c.getTime().toString());
70        assertEquals("1 Jan 321 08:00:00 GMT", c.getTime().toGMTString());
71    }
72
73    public void test_parse_timezones() {
74       assertEquals(
75               Date.parse("Wed, 06 Jan 2016 11:55:59 GMT+05:00"),
76               Date.parse("Wed, 06 Jan 2016 11:55:59 GMT+0500"));
77
78        assertEquals(
79                Date.parse("Wed, 06 Jan 2016 11:55:59 GMT+05:00"),
80                Date.parse("Wed, 06 Jan 2016 11:55:59 GMT+05"));
81    }
82
83    /**
84     * Test that conversion between Date and Instant works when the
85     * Instant is based on a millisecond value (and thus can be
86     * represented as a Date).
87     */
88    public void test_convertFromAndToInstant_milliseconds() {
89        check_convertFromAndToInstant_milliseconds(Long.MIN_VALUE);
90        check_convertFromAndToInstant_milliseconds(Long.MAX_VALUE);
91
92        check_convertFromAndToInstant_milliseconds(-1);
93        check_convertFromAndToInstant_milliseconds(0);
94        check_convertFromAndToInstant_milliseconds(123456789);
95    }
96
97    private static void check_convertFromAndToInstant_milliseconds(long millis) {
98        assertEquals(new Date(millis), Date.from(Instant.ofEpochMilli(millis)));
99        assertEquals(new Date(millis).toInstant(), Instant.ofEpochMilli(millis));
100    }
101
102    /**
103     * Checks the minimum/maximum Instant values (based on seconds and
104     * nanos) that can be converted to a Date, i.e. that can be converted
105     * to milliseconds without overflowing a long. Note that the rounding
106     * is such that the lower bound is exactly Long.MIN_VALUE msec whereas
107     * the upper bound is 999,999 nanos beyond Long.MAX_VALUE msec. This
108     * makes some sense in that the magnitude of the upper/lower bound
109     * nanos differ only by 1, just like the magnitude of Long.MIN_VALUE /
110     * MAX_VALUE differ only by 1.
111     */
112    public void test_convertFromInstant_secondsAndNanos() {
113        // Documentation for how the below bounds relate to long boundaries for milliseconds
114        assertEquals(-808, Long.MIN_VALUE % 1000);
115        assertEquals(807, Long.MAX_VALUE % 1000);
116
117        // Lower bound
118        long minSecond = Long.MIN_VALUE / 1000;
119        Date.from(Instant.ofEpochSecond(minSecond));
120        // This instant exactly corresponds to Long.MIN_VALUE msec because
121        // Long.MIN_VALUE % 1000 == -808 == (-1000 + 192)
122        Date.from(Instant.ofEpochSecond(minSecond - 1, 192000000));
123        assertArithmeticOverflowDateFrom(Instant.ofEpochSecond(minSecond - 1, 0));
124        assertArithmeticOverflowDateFrom(Instant.ofEpochSecond(minSecond - 1, 191999999));
125
126        // Upper bound
127        long maxSecond = Long.MAX_VALUE / 1000;
128        Date.from(Instant.ofEpochSecond(maxSecond, 0));
129        // This Instant is 999,999 nanos beyond Long.MAX_VALUE msec because
130        // (Long.MAX_VALUE % 1000) == 807
131        Date.from(Instant.ofEpochSecond(maxSecond, 807999999));
132        assertArithmeticOverflowDateFrom(Instant.ofEpochSecond(maxSecond + 1, 0));
133        assertArithmeticOverflowDateFrom(Instant.ofEpochSecond(maxSecond, 808000000));
134    }
135
136    private static void assertArithmeticOverflowDateFrom(Instant instant) {
137        try {
138            Date.from(instant);
139            fail(instant + " should not have been convertible to Date");
140        } catch (IllegalArgumentException expected) {
141        }
142    }
143
144    /**
145     * Checks conversion between long, Date and Instant.
146     */
147    public void test_convertToInstantAndBack() {
148        check_convertToInstantAndBack(0);
149        check_convertToInstantAndBack(-1);
150        check_convertToInstantAndBack( 999999999);
151        check_convertToInstantAndBack(1000000000);
152        check_convertToInstantAndBack(1000000001);
153        check_convertToInstantAndBack(1000000002);
154        check_convertToInstantAndBack(1000000499);
155        check_convertToInstantAndBack(1000000500);
156        check_convertToInstantAndBack(1000000999);
157        check_convertToInstantAndBack(1000001000);
158        check_convertToInstantAndBack(Long.MIN_VALUE + 808); // minimum ofEpochMilli argument
159        check_convertToInstantAndBack(Long.MAX_VALUE);
160        check_convertToInstantAndBack(System.currentTimeMillis());
161        check_convertToInstantAndBack(Date.parse("Wed, 06 Jan 2016 11:55:59 GMT+0500"));
162    }
163
164    private static void check_convertToInstantAndBack(long millis) {
165        Date date = new Date(millis);
166        Instant instant = date.toInstant();
167        assertEquals(date, Date.from(instant));
168
169        assertEquals(instant, Instant.ofEpochMilli(millis));
170        assertEquals("Millis should be a millions of nanos", 0, instant.getNano() % 1000000);
171
172        assertEquals(millis, date.getTime());
173        assertEquals(millis, instant.toEpochMilli());
174    }
175}
176