2708N/A/*
2708N/A * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
2708N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
2708N/A *
2708N/A * This code is free software; you can redistribute it and/or modify it
2708N/A * under the terms of the GNU General Public License version 2 only, as
2708N/A * published by the Free Software Foundation.
2708N/A *
2708N/A * This code is distributed in the hope that it will be useful, but WITHOUT
2708N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
2708N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
2708N/A * version 2 for more details (a copy is included in the LICENSE file that
2708N/A * accompanied this code).
2708N/A *
2708N/A * You should have received a copy of the GNU General Public License version
2708N/A * 2 along with this work; if not, write to the Free Software Foundation,
2708N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
2708N/A *
2708N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2708N/A * or visit www.oracle.com if you need additional information or have any
2708N/A * questions.
2708N/A */
2708N/A
2708N/A/*
2708N/A * @test
2708N/A * @bug 4919632
2708N/A * @summary Unit test for ISO8601 time zone format support
2708N/A */
2708N/A
2708N/Aimport java.text.*;
2708N/Aimport java.util.*;
2708N/A
2708N/Apublic class ISO8601ZoneTest {
2708N/A static final Date TIMESTAMP = new Date(1283758039020L);
2708N/A
2708N/A static final String[][] formatData = {
2708N/A // time zone name, expected output at TIMESTAMP
2708N/A { "America/Los_Angeles", "2010-09-06T00:27:19.020-07", },
2708N/A { "America/Los_Angeles", "2010-09-06T00:27:19.020-0700", },
2708N/A { "America/Los_Angeles", "2010-09-06T00:27:19.020-07:00", },
2708N/A { "Australia/Sydney", "2010-09-06T17:27:19.020+10", },
2708N/A { "Australia/Sydney", "2010-09-06T17:27:19.020+1000", },
2708N/A { "Australia/Sydney", "2010-09-06T17:27:19.020+10:00", },
2708N/A { "GMT-07:00", "2010-09-06T00:27:19.020-07", },
2708N/A { "GMT-07:00", "2010-09-06T00:27:19.020-0700", },
2708N/A { "GMT-07:00", "2010-09-06T00:27:19.020-07:00", },
2708N/A { "UTC", "2010-09-06T07:27:19.020Z", },
2708N/A { "UTC", "2010-09-06T07:27:19.020Z", },
2708N/A { "UTC", "2010-09-06T07:27:19.020Z", },
2708N/A };
2708N/A
2708N/A static final String[] zones = {
2708N/A "America/Los_Angeles", "Australia/Sydney", "GMT-07:00",
2708N/A "UTC", "GMT+05:30", "GMT-01:23",
2708N/A };
2708N/A
2708N/A static final String[] isoZoneFormats = {
2708N/A "yyyy-MM-dd'T'HH:mm:ss.SSSX",
2708N/A "yyyy-MM-dd'T'HH:mm:ss.SSSXX",
2708N/A "yyyy-MM-dd'T'HH:mm:ss.SSSXXX",
2708N/A };
2708N/A
3299N/A // badData[][0] - format
3299N/A // badData[][1] - (bad) text to be parsed
3299N/A // badData[][2] - subtext at the end of which a parse error is detected
2708N/A static final String[][] badData = {
3299N/A { "X", "1", "1" },
3299N/A { "X", "+1", "+1" },
3299N/A { "X", "-2", "-2" },
3299N/A { "X", "-24", "-2" },
3299N/A { "X", "+24", "+2" },
2708N/A
3299N/A { "XX", "9", "9" },
3299N/A { "XX", "23", "2" },
3299N/A { "XX", "234", "2" },
3299N/A { "XX", "3456", "3" },
3299N/A { "XX", "23456", "2" },
3299N/A { "XX", "+1", "+1" },
3299N/A { "XX", "-12", "-12" },
3299N/A { "XX", "+123", "+123" },
3299N/A { "XX", "-12:34", "-12" },
3299N/A { "XX", "+12:34", "+12" },
3299N/A { "XX", "-2423", "-2" },
3299N/A { "XX", "+2423", "+2" },
3299N/A { "XX", "-1260", "-126" },
3299N/A { "XX", "+1260", "+126" },
2708N/A
3299N/A { "XXX", "9", "9" },
3299N/A { "XXX", "23", "2" },
3299N/A { "XXX", "234", "2" },
3299N/A { "XXX", "3456", "3" },
3299N/A { "XXX", "23456", "2" },
3299N/A { "XXX", "2:34", "2" },
3299N/A { "XXX", "12:4", "1" },
3299N/A { "XXX", "12:34", "1" },
3299N/A { "XXX", "-1", "-1" },
3299N/A { "XXX", "+1", "+1" },
3299N/A { "XXX", "-12", "-12" },
3299N/A { "XXX", "+12", "+12" },
3299N/A { "XXX", "-123", "-12" },
3299N/A { "XXX", "+123", "+12" },
3299N/A { "XXX", "-1234", "-12" },
3299N/A { "XXX", "+1234", "+12" },
3299N/A { "XXX", "+24:23", "+2" },
3299N/A { "XXX", "+12:60", "+12:6" },
3299N/A { "XXX", "+1:23", "+1" },
3299N/A { "XXX", "+12:3", "+12:3" },
2708N/A };
2708N/A
2708N/A static String[] badFormats = {
2708N/A "XXXX", "XXXXX", "XXXXXX",
2708N/A };
2708N/A
2708N/A public static void main(String[] args) throws Exception {
2708N/A TimeZone tz = TimeZone.getDefault();
3299N/A Locale loc = Locale.getDefault();
3299N/A Locale.setDefault(Locale.US);
2708N/A
2708N/A try {
2708N/A for (int i = 0; i < formatData.length; i++) {
2708N/A TimeZone.setDefault(TimeZone.getTimeZone(formatData[i][0]));
2708N/A formatTest(isoZoneFormats[i % isoZoneFormats.length],
2708N/A formatData[i][1]);
2708N/A }
2708N/A
2708N/A for (String zone : zones) {
2708N/A TimeZone.setDefault(TimeZone.getTimeZone(zone));
2708N/A for (String fmt : isoZoneFormats) {
2708N/A roundtripTest(fmt);
2708N/A SimpleDateFormat f = new SimpleDateFormat(fmt);
2708N/A }
2708N/A
2708N/A }
2708N/A
2708N/A for (String[] d : badData) {
3299N/A badDataParsing(d[0], d[1], d[2].length());
2708N/A }
2708N/A
2708N/A for (String fmt : badFormats) {
2708N/A badFormat(fmt);
2708N/A }
2708N/A } finally {
2708N/A TimeZone.setDefault(tz);
3299N/A Locale.setDefault(loc);
2708N/A }
2708N/A
2708N/A }
2708N/A
2708N/A static void formatTest(String fmt, String expected) throws Exception {
2708N/A SimpleDateFormat sdf = new SimpleDateFormat(fmt);
2708N/A String s = sdf.format(TIMESTAMP);
2708N/A if (!expected.equals(s)) {
2708N/A throw new RuntimeException("formatTest: got " + s
2708N/A + ", expected " + expected);
2708N/A }
2708N/A
2708N/A Date d = sdf.parse(s);
2708N/A if (d.getTime() != TIMESTAMP.getTime()) {
2708N/A throw new RuntimeException("formatTest: parse(" + s
2708N/A + "), got " + d.getTime()
2708N/A + ", expected " + TIMESTAMP.getTime());
2708N/A }
2708N/A
2708N/A ParsePosition pos = new ParsePosition(0);
2708N/A d = sdf.parse(s + "123", pos);
2708N/A if (d.getTime() != TIMESTAMP.getTime()) {
2708N/A throw new RuntimeException("formatTest: parse(" + s
2708N/A + "), got " + d.getTime()
2708N/A + ", expected " + TIMESTAMP.getTime());
2708N/A }
2708N/A if (pos.getIndex() != s.length()) {
2708N/A throw new RuntimeException("formatTest: wrong resulting parse position: "
2708N/A + pos.getIndex() + ", expected " + s.length());
2708N/A }
2708N/A }
2708N/A
2708N/A static void roundtripTest(String fmt) throws Exception {
2708N/A SimpleDateFormat sdf = new SimpleDateFormat(fmt);
2708N/A Date date = new Date();
2708N/A
2708N/A int fractionalHour = sdf.getTimeZone().getOffset(date.getTime());
2708N/A fractionalHour %= 3600000; // fraction of hour
2708N/A
2708N/A String s = sdf.format(date);
2708N/A Date pd = sdf.parse(s);
2708N/A long diffsInMillis = pd.getTime() - date.getTime();
2708N/A if (diffsInMillis != 0) {
2708N/A if (diffsInMillis != fractionalHour) {
2708N/A throw new RuntimeException("fmt= " + fmt
2708N/A + ", diff="+diffsInMillis
2708N/A + ", fraction=" + fractionalHour);
2708N/A }
2708N/A }
2708N/A }
2708N/A
2708N/A
3299N/A static void badDataParsing(String fmt, String text, int expectedErrorIndex) {
3299N/A SimpleDateFormat sdf = new SimpleDateFormat(fmt);
2708N/A try {
2708N/A sdf.parse(text);
2708N/A throw new RuntimeException("didn't throw an exception: fmt=" + fmt
2708N/A + ", text=" + text);
2708N/A } catch (ParseException e) {
2708N/A // OK
2708N/A }
3299N/A
3299N/A ParsePosition pos = new ParsePosition(0);
3299N/A Date d = sdf.parse(text, pos);
3299N/A int errorIndex = pos.getErrorIndex();
3299N/A if (d != null || errorIndex != expectedErrorIndex) {
3299N/A throw new RuntimeException("Bad error index=" + errorIndex
3299N/A + ", expected=" + expectedErrorIndex
3299N/A + ", fmt=" + fmt + ", text=" + text);
3299N/A }
2708N/A }
2708N/A
2708N/A static void badFormat(String fmt) {
2708N/A try {
2708N/A SimpleDateFormat sdf = new SimpleDateFormat(fmt);
2708N/A throw new RuntimeException("Constructor didn't throw an exception: fmt=" + fmt);
2708N/A } catch (IllegalArgumentException e) {
2708N/A // OK
2708N/A }
2708N/A try {
2708N/A SimpleDateFormat sdf = new SimpleDateFormat();
2708N/A sdf.applyPattern(fmt);
2708N/A throw new RuntimeException("applyPattern didn't throw an exception: fmt=" + fmt);
2708N/A } catch (IllegalArgumentException e) {
2708N/A // OK
2708N/A }
2708N/A }
2708N/A}