1/* 2 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24/* 25 * @test 26 * @bug 4919632 27 * @summary Unit test for ISO8601 time zone format support 28 */ 29 30import java.text.*; 31import java.util.*; 32 33public class ISO8601ZoneTest { 34 static final Date TIMESTAMP = new Date(1283758039020L); 35 36 static final String[][] formatData = { 37 // time zone name, expected output at TIMESTAMP 38 { "America/Los_Angeles", "2010-09-06T00:27:19.020-07", }, 39 { "America/Los_Angeles", "2010-09-06T00:27:19.020-0700", }, 40 { "America/Los_Angeles", "2010-09-06T00:27:19.020-07:00", }, 41 { "Australia/Sydney", "2010-09-06T17:27:19.020+10", }, 42 { "Australia/Sydney", "2010-09-06T17:27:19.020+1000", }, 43 { "Australia/Sydney", "2010-09-06T17:27:19.020+10:00", }, 44 { "GMT-07:00", "2010-09-06T00:27:19.020-07", }, 45 { "GMT-07:00", "2010-09-06T00:27:19.020-0700", }, 46 { "GMT-07:00", "2010-09-06T00:27:19.020-07:00", }, 47 { "UTC", "2010-09-06T07:27:19.020Z", }, 48 { "UTC", "2010-09-06T07:27:19.020Z", }, 49 { "UTC", "2010-09-06T07:27:19.020Z", }, 50 }; 51 52 static final String[] zones = { 53 "America/Los_Angeles", "Australia/Sydney", "GMT-07:00", 54 "UTC", "GMT+05:30", "GMT-01:23", 55 }; 56 57 static final String[] isoZoneFormats = { 58 "yyyy-MM-dd'T'HH:mm:ss.SSSX", 59 "yyyy-MM-dd'T'HH:mm:ss.SSSXX", 60 "yyyy-MM-dd'T'HH:mm:ss.SSSXXX", 61 }; 62 63 // badData[][0] - format 64 // badData[][1] - (bad) text to be parsed 65 // badData[][2] - subtext at the end of which a parse error is detected 66 static final String[][] badData = { 67 { "X", "1", "1" }, 68 { "X", "+1", "+1" }, 69 { "X", "-2", "-2" }, 70 { "X", "-24", "-2" }, 71 { "X", "+24", "+2" }, 72 73 { "XX", "9", "9" }, 74 { "XX", "23", "2" }, 75 { "XX", "234", "2" }, 76 { "XX", "3456", "3" }, 77 { "XX", "23456", "2" }, 78 { "XX", "+1", "+1" }, 79 { "XX", "-12", "-12" }, 80 { "XX", "+123", "+123" }, 81 { "XX", "-12:34", "-12" }, 82 { "XX", "+12:34", "+12" }, 83 { "XX", "-2423", "-2" }, 84 { "XX", "+2423", "+2" }, 85 { "XX", "-1260", "-126" }, 86 { "XX", "+1260", "+126" }, 87 88 { "XXX", "9", "9" }, 89 { "XXX", "23", "2" }, 90 { "XXX", "234", "2" }, 91 { "XXX", "3456", "3" }, 92 { "XXX", "23456", "2" }, 93 { "XXX", "2:34", "2" }, 94 { "XXX", "12:4", "1" }, 95 { "XXX", "12:34", "1" }, 96 { "XXX", "-1", "-1" }, 97 { "XXX", "+1", "+1" }, 98 { "XXX", "-12", "-12" }, 99 { "XXX", "+12", "+12" }, 100 { "XXX", "-123", "-12" }, 101 { "XXX", "+123", "+12" }, 102 { "XXX", "-1234", "-12" }, 103 { "XXX", "+1234", "+12" }, 104 { "XXX", "+24:23", "+2" }, 105 { "XXX", "+12:60", "+12:6" }, 106 { "XXX", "+1:23", "+1" }, 107 { "XXX", "+12:3", "+12:3" }, 108 }; 109 110 static String[] badFormats = { 111 "XXXX", "XXXXX", "XXXXXX", 112 }; 113 114 public static void main(String[] args) throws Exception { 115 TimeZone tz = TimeZone.getDefault(); 116 Locale loc = Locale.getDefault(); 117 Locale.setDefault(Locale.US); 118 119 try { 120 for (int i = 0; i < formatData.length; i++) { 121 TimeZone.setDefault(TimeZone.getTimeZone(formatData[i][0])); 122 formatTest(isoZoneFormats[i % isoZoneFormats.length], 123 formatData[i][1]); 124 } 125 126 for (String zone : zones) { 127 TimeZone.setDefault(TimeZone.getTimeZone(zone)); 128 for (String fmt : isoZoneFormats) { 129 roundtripTest(fmt); 130 SimpleDateFormat f = new SimpleDateFormat(fmt); 131 } 132 133 } 134 135 for (String[] d : badData) { 136 badDataParsing(d[0], d[1], d[2].length()); 137 } 138 139 for (String fmt : badFormats) { 140 badFormat(fmt); 141 } 142 } finally { 143 TimeZone.setDefault(tz); 144 Locale.setDefault(loc); 145 } 146 147 } 148 149 static void formatTest(String fmt, String expected) throws Exception { 150 SimpleDateFormat sdf = new SimpleDateFormat(fmt); 151 String s = sdf.format(TIMESTAMP); 152 if (!expected.equals(s)) { 153 throw new RuntimeException("formatTest: got " + s 154 + ", expected " + expected); 155 } 156 157 Date d = sdf.parse(s); 158 if (d.getTime() != TIMESTAMP.getTime()) { 159 throw new RuntimeException("formatTest: parse(" + s 160 + "), got " + d.getTime() 161 + ", expected " + TIMESTAMP.getTime()); 162 } 163 164 ParsePosition pos = new ParsePosition(0); 165 d = sdf.parse(s + "123", pos); 166 if (d.getTime() != TIMESTAMP.getTime()) { 167 throw new RuntimeException("formatTest: parse(" + s 168 + "), got " + d.getTime() 169 + ", expected " + TIMESTAMP.getTime()); 170 } 171 if (pos.getIndex() != s.length()) { 172 throw new RuntimeException("formatTest: wrong resulting parse position: " 173 + pos.getIndex() + ", expected " + s.length()); 174 } 175 } 176 177 static void roundtripTest(String fmt) throws Exception { 178 SimpleDateFormat sdf = new SimpleDateFormat(fmt); 179 Date date = new Date(); 180 181 int fractionalHour = sdf.getTimeZone().getOffset(date.getTime()); 182 fractionalHour %= 3600000; // fraction of hour 183 184 String s = sdf.format(date); 185 Date pd = sdf.parse(s); 186 long diffsInMillis = pd.getTime() - date.getTime(); 187 if (diffsInMillis != 0) { 188 if (diffsInMillis != fractionalHour) { 189 throw new RuntimeException("fmt= " + fmt 190 + ", diff="+diffsInMillis 191 + ", fraction=" + fractionalHour); 192 } 193 } 194 } 195 196 197 static void badDataParsing(String fmt, String text, int expectedErrorIndex) { 198 SimpleDateFormat sdf = new SimpleDateFormat(fmt); 199 try { 200 sdf.parse(text); 201 throw new RuntimeException("didn't throw an exception: fmt=" + fmt 202 + ", text=" + text); 203 } catch (ParseException e) { 204 // OK 205 } 206 207 ParsePosition pos = new ParsePosition(0); 208 Date d = sdf.parse(text, pos); 209 int errorIndex = pos.getErrorIndex(); 210 if (d != null || errorIndex != expectedErrorIndex) { 211 throw new RuntimeException("Bad error index=" + errorIndex 212 + ", expected=" + expectedErrorIndex 213 + ", fmt=" + fmt + ", text=" + text); 214 } 215 } 216 217 static void badFormat(String fmt) { 218 try { 219 SimpleDateFormat sdf = new SimpleDateFormat(fmt); 220 throw new RuntimeException("Constructor didn't throw an exception: fmt=" + fmt); 221 } catch (IllegalArgumentException e) { 222 // OK 223 } 224 try { 225 SimpleDateFormat sdf = new SimpleDateFormat(); 226 sdf.applyPattern(fmt); 227 throw new RuntimeException("applyPattern didn't throw an exception: fmt=" + fmt); 228 } catch (IllegalArgumentException e) { 229 // OK 230 } 231 } 232} 233