001    /*
002     *  Copyright 2001-2005 Stephen Colebourne
003     *
004     *  Licensed under the Apache License, Version 2.0 (the "License");
005     *  you may not use this file except in compliance with the License.
006     *  You may obtain a copy of the License at
007     *
008     *      http://www.apache.org/licenses/LICENSE-2.0
009     *
010     *  Unless required by applicable law or agreed to in writing, software
011     *  distributed under the License is distributed on an "AS IS" BASIS,
012     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013     *  See the License for the specific language governing permissions and
014     *  limitations under the License.
015     */
016    package org.joda.time.tz;
017    
018    import java.io.ByteArrayInputStream;
019    import java.io.ByteArrayOutputStream;
020    import java.io.IOException;
021    
022    import junit.framework.TestCase;
023    import junit.framework.TestSuite;
024    
025    import org.joda.time.DateTime;
026    import org.joda.time.DateTimeZone;
027    import org.joda.time.format.DateTimeFormatter;
028    import org.joda.time.format.DateTimeFormatterBuilder;
029    
030    /**
031     * Test cases for DateTimeZoneBuilder.
032     *
033     * @author Brian S O'Neill
034     */
035    public class TestBuilder extends TestCase {
036        public static void main(String[] args) {
037            junit.textui.TestRunner.run(suite());
038        }
039    
040        public static TestSuite suite() {
041            return new TestSuite(TestBuilder.class);
042        }
043    
044        static final DateTimeFormatter OFFSET_FORMATTER = new DateTimeFormatterBuilder()
045            .appendTimeZoneOffset(null, true, 2, 4)
046            .toFormatter();
047    
048        // Each row is {transition, nameKey, standardOffset, offset}
049        static final String[][] AMERICA_LOS_ANGELES_DATA = {
050            {null,                            "LMT", "-07:52:58", "-07:52:58"},
051            {"1883-11-18T19:52:58.000Z",      "PST", "-08:00", "-08:00"},
052            {"1918-03-31T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
053            {"1918-10-27T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
054            {"1919-03-30T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
055            {"1919-10-26T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
056            {"1942-02-09T02:00:00.000-08:00", "PWT", "-08:00", "-07:00"},
057            {"1945-08-14T23:00:00.000Z",      "PPT", "-08:00", "-07:00"},
058            {"1945-09-30T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
059            {"1948-03-14T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
060            {"1949-01-01T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
061            {"1950-04-30T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
062            {"1950-09-24T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
063            {"1951-04-29T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
064            {"1951-09-30T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
065            {"1952-04-27T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
066            {"1952-09-28T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
067            {"1953-04-26T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
068            {"1953-09-27T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
069            {"1954-04-25T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
070            {"1954-09-26T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
071            {"1955-04-24T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
072            {"1955-09-25T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
073            {"1956-04-29T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
074            {"1956-09-30T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
075            {"1957-04-28T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
076            {"1957-09-29T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
077            {"1958-04-27T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
078            {"1958-09-28T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
079            {"1959-04-26T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
080            {"1959-09-27T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
081            {"1960-04-24T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
082            {"1960-09-25T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
083            {"1961-04-30T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
084            {"1961-09-24T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
085            {"1962-04-29T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
086            {"1962-10-28T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
087            {"1963-04-28T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
088            {"1963-10-27T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
089            {"1964-04-26T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
090            {"1964-10-25T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
091            {"1965-04-25T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
092            {"1965-10-31T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
093            {"1966-04-24T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
094            {"1966-10-30T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
095            {"1967-04-30T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
096            {"1967-10-29T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
097            {"1968-04-28T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
098            {"1968-10-27T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
099            {"1969-04-27T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
100            {"1969-10-26T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
101            {"1970-04-26T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
102            {"1970-10-25T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
103            {"1971-04-25T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
104            {"1971-10-31T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
105            {"1972-04-30T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
106            {"1972-10-29T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
107            {"1973-04-29T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
108            {"1973-10-28T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
109            {"1974-01-06T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
110            {"1974-10-27T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
111            {"1975-02-23T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
112            {"1975-10-26T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
113            {"1976-04-25T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
114            {"1976-10-31T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
115            {"1977-04-24T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
116            {"1977-10-30T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
117            {"1978-04-30T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
118            {"1978-10-29T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
119            {"1979-04-29T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
120            {"1979-10-28T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
121            {"1980-04-27T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
122            {"1980-10-26T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
123            {"1981-04-26T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
124            {"1981-10-25T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
125            {"1982-04-25T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
126            {"1982-10-31T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
127            {"1983-04-24T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
128            {"1983-10-30T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
129            {"1984-04-29T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
130            {"1984-10-28T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
131            {"1985-04-28T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
132            {"1985-10-27T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
133            {"1986-04-27T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
134            {"1986-10-26T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
135            {"1987-04-05T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
136            {"1987-10-25T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
137            {"1988-04-03T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
138            {"1988-10-30T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
139            {"1989-04-02T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
140            {"1989-10-29T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
141            {"1990-04-01T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
142            {"1990-10-28T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
143            {"1991-04-07T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
144            {"1991-10-27T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
145            {"1992-04-05T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
146            {"1992-10-25T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
147            {"1993-04-04T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
148            {"1993-10-31T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
149            {"1994-04-03T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
150            {"1994-10-30T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
151            {"1995-04-02T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
152            {"1995-10-29T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
153            {"1996-04-07T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
154            {"1996-10-27T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
155            {"1997-04-06T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
156            {"1997-10-26T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
157            {"1998-04-05T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
158            {"1998-10-25T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
159            {"1999-04-04T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
160            {"1999-10-31T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
161            {"2000-04-02T02:00:00.000-08:00", "PDT", "-08:00", "-07:00"},
162            {"2000-10-29T02:00:00.000-07:00", "PST", "-08:00", "-08:00"},
163        };
164    
165        static DateTimeZoneBuilder buildAmericaLosAngelesBuilder() {
166            return new DateTimeZoneBuilder()
167                .addCutover(-2147483648, 'w', 1, 1, 0, false, 0)
168                .setStandardOffset(-28378000)
169                .setFixedSavings("LMT", 0)
170                .addCutover(1883, 'w', 11, 18, 0, false, 43200000)
171                .setStandardOffset(-28800000)
172                .addRecurringSavings("PDT", 3600000, 1918, 1919, 'w',  3, -1, 7, false, 7200000)
173                .addRecurringSavings("PST",       0, 1918, 1919, 'w', 10, -1, 7, false, 7200000)
174                .addRecurringSavings("PWT", 3600000, 1942, 1942, 'w',  2,  9, 0, false, 7200000)
175                .addRecurringSavings("PPT", 3600000, 1945, 1945, 'u',  8, 14, 0, false, 82800000)
176                .addRecurringSavings("PST",       0, 1945, 1945, 'w',  9, 30, 0, false, 7200000)
177                .addRecurringSavings("PDT", 3600000, 1948, 1948, 'w',  3, 14, 0, false, 7200000)
178                .addRecurringSavings("PST",       0, 1949, 1949, 'w',  1,  1, 0, false, 7200000)
179                .addRecurringSavings("PDT", 3600000, 1950, 1966, 'w',  4, -1, 7, false, 7200000)
180                .addRecurringSavings("PST",       0, 1950, 1961, 'w',  9, -1, 7, false, 7200000)
181                .addRecurringSavings("PST",       0, 1962, 1966, 'w', 10, -1, 7, false, 7200000)
182                .addRecurringSavings("PST",       0, 1967, 2147483647, 'w', 10, -1, 7, false, 7200000)
183                .addRecurringSavings("PDT", 3600000, 1967, 1973, 'w', 4, -1,  7, false, 7200000)
184                .addRecurringSavings("PDT", 3600000, 1974, 1974, 'w', 1,  6,  0, false, 7200000)
185                .addRecurringSavings("PDT", 3600000, 1975, 1975, 'w', 2, 23,  0, false, 7200000)
186                .addRecurringSavings("PDT", 3600000, 1976, 1986, 'w', 4, -1,  7, false, 7200000)
187                .addRecurringSavings("PDT", 3600000, 1987, 2147483647, 'w', 4, 1, 7, true, 7200000);
188        }
189    
190        static DateTimeZone buildAmericaLosAngeles() {
191            return buildAmericaLosAngelesBuilder().toDateTimeZone("America/Los_Angeles", true);
192        }
193    
194        private DateTimeZone originalDateTimeZone = null;
195    
196        public TestBuilder(String name) {
197            super(name);
198        }
199    
200        protected void setUp() throws Exception {
201            originalDateTimeZone = DateTimeZone.getDefault();
202            DateTimeZone.setDefault(DateTimeZone.UTC);
203        }
204    
205        protected void tearDown() throws Exception {
206            DateTimeZone.setDefault(originalDateTimeZone);
207        }
208    
209        public void testID() {
210            DateTimeZone tz = buildAmericaLosAngeles();
211            assertEquals("America/Los_Angeles", tz.getID());
212            assertEquals(false, tz.isFixed());
213        }
214    
215        public void testForwardTransitions() {
216            DateTimeZone tz = buildAmericaLosAngeles();
217            testForwardTransitions(tz, AMERICA_LOS_ANGELES_DATA);
218        }
219    
220        static void testForwardTransitions(DateTimeZone tz, String[][] data) {
221            long instant = Long.MIN_VALUE;
222            for (int i=0; i<data.length; i++) {
223                String[] row = data[i];
224                long expectedInstant = instant;
225                if (row[0] != null) {
226                    instant = tz.nextTransition(instant);
227                    expectedInstant = new DateTime(row[0]).getMillis();
228                }
229    
230                String expectedKey = row[1];
231                int expectedStandardOffset = -(int) OFFSET_FORMATTER.parseMillis(row[2]);
232                int expectedOffset = -(int) OFFSET_FORMATTER.parseMillis(row[3]);
233    
234                assertEquals(expectedInstant, instant);
235                assertEquals(expectedKey, tz.getNameKey(instant));
236                assertEquals(expectedStandardOffset, tz.getStandardOffset(instant));
237                assertEquals(expectedOffset, tz.getOffset(instant));
238    
239                // Sample a few instants between transitions.
240                if (i < data.length - 1) {
241                    long nextInstant = new DateTime(data[i + 1][0]).getMillis();
242                    long span = (nextInstant - instant) / 10;
243                    for (int j=1; j<10; j++) {
244                        long between = instant + j * span;
245                        assertEquals(expectedKey, tz.getNameKey(between));
246                        assertEquals(expectedStandardOffset, tz.getStandardOffset(between));
247                        assertEquals(expectedOffset, tz.getOffset(between));
248                    }
249                }
250            }
251        }
252    
253        public void testReverseTransitions() {
254            DateTimeZone tz = buildAmericaLosAngeles();
255            testReverseTransitions(tz, AMERICA_LOS_ANGELES_DATA);
256        }
257    
258        static void testReverseTransitions(DateTimeZone tz, String[][] data) {
259            long instant = new DateTime(data[data.length - 1][0]).getMillis();
260            for (int i=data.length; --i>=1; ) {
261                String[] row = data[i];
262                String[] prevRow = data[i - 1];
263                instant = tz.previousTransition(instant);
264    
265                long expectedInstant = new DateTime(row[0]).getMillis() - 1;
266                String expectedKey = prevRow[1];
267                int expectedStandardOffset = -(int) OFFSET_FORMATTER.parseMillis(prevRow[2]);
268                int expectedOffset = -(int) OFFSET_FORMATTER.parseMillis(prevRow[3]);
269    
270                assertEquals(expectedInstant, instant);
271                assertEquals(expectedKey, tz.getNameKey(instant));
272                assertEquals(expectedStandardOffset, tz.getStandardOffset(instant));
273                assertEquals(expectedOffset, tz.getOffset(instant));
274            }
275        }
276    
277        public void testSerialization() throws IOException {
278            DateTimeZone tz = testSerialization
279                (buildAmericaLosAngelesBuilder(), "America/Los_Angeles");
280    
281            assertEquals(false, tz.isFixed());
282            testForwardTransitions(tz, AMERICA_LOS_ANGELES_DATA);
283            testReverseTransitions(tz, AMERICA_LOS_ANGELES_DATA);
284        }
285    
286        static DateTimeZone testSerialization(DateTimeZoneBuilder builder, String id)
287            throws IOException
288        {
289            ByteArrayOutputStream out = new ByteArrayOutputStream();
290            builder.writeTo("America/Los_Angeles", out);
291            ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
292            DateTimeZone tz = DateTimeZoneBuilder.readFrom(in, id);
293            assertEquals(id, tz.getID());
294            return tz;
295        }
296    
297        public void testFixed() throws IOException {
298            DateTimeZoneBuilder builder = new DateTimeZoneBuilder()
299                .setStandardOffset(3600000)
300                .setFixedSavings("LMT", 0);
301            DateTimeZone tz = builder.toDateTimeZone("Test", true);
302    
303            for (int i=0; i<2; i++) {
304                assertEquals("Test", tz.getID());
305                assertEquals(true, tz.isFixed());
306                assertEquals(3600000, tz.getOffset(0));
307                assertEquals(3600000, tz.getStandardOffset(0));
308                assertEquals(0, tz.nextTransition(0));
309                assertEquals(0, tz.previousTransition(0));
310    
311                tz = testSerialization(builder, "Test");
312            }
313        }
314    }