1 /*
   2  * Copyright (c) 2001, 2016, 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 4322313 4833268 6302990 6304305
  27  * @library /java/text/testlib
  28  * @summary Make sure that new implementation for
  29  * SimpleDateFormat.parse('z' or 'Z') and format('z' or 'Z') work correctly.
  30  */
  31 
  32 import java.io.*;
  33 import java.text.*;
  34 import java.util.*;
  35 
  36 public class Bug4322313 extends IntlTest {
  37 
  38     public void Test4322313() {
  39         Locale savedLocale = Locale.getDefault();
  40         TimeZone savedTimeZone = TimeZone.getDefault();
  41         boolean err = false;
  42         long mpm = 60 * 1000;   /* Milliseconds per a minute */
  43 
  44         Locale[] locs = {Locale.US, Locale.JAPAN, Locale.UK, new Locale("ar")};
  45 
  46         String[] formats = {
  47             "z",
  48             "Z",
  49         };
  50 
  51         Object[][] valids = {
  52           /* given ID      offset                format('z'), ('Z')    index */
  53             {"GMT+03:04",  new Long(-184 * mpm), "GMT+03:04", "+0304", new Integer(9)},
  54             {"GMT+13:42",  new Long(-822 * mpm), "GMT+13:42", "+1342", new Integer(9)},
  55             {"GMT+00:00",  new Long(0),          "GMT+00:00", "+0000", new Integer(9)},
  56             {"GMT+1:11",   new Long(-71 * mpm),  "GMT+01:11", "+0111", new Integer(8)},
  57             {"GMT +13:42", new Long(0),          "GMT",       "+0000", new Integer(3)},
  58             {" GMT",       new Long(0),          "GMT",       "+0000", new Integer(4)},
  59             {"+0304",      new Long(-184 * mpm), "GMT+03:04", "+0304", new Integer(5)},
  60             {"+1342",      new Long(-822 * mpm), "GMT+13:42", "+1342", new Integer(5)},
  61             {"+0000",      new Long(0),          "GMT+00:00", "+0000", new Integer(5)},
  62             {" +1342",     new Long(-822 * mpm), "GMT+13:42", "+1342", new Integer(6)},
  63             /* ISO-LATIN-1 digits */
  64             {"GMT+\u0030\u0031:\u0032\u0033", new Long(-83 * mpm), "GMT+01:23", "+0123", new Integer(9)},
  65 
  66            /* In fact, this test case is skipped because TimeZone class can't
  67             * recognize TimeZone IDs like "+00234" or "-00234".
  68             */
  69             {"+00234",     new Long(-23 * mpm), "GMT+00:23", "+0023", new Integer(5)},
  70 
  71             {"GMT-03:04",  new Long(184 * mpm), "GMT-03:04", "-0304", new Integer(9)},
  72             {"GMT-13:42",  new Long(822 * mpm), "GMT-13:42", "-1342", new Integer(9)},
  73             {"GMT-00:00",  new Long(0),         "GMT+00:00", "+0000", new Integer(9)},
  74             {"GMT-1:11",   new Long(71 * mpm),  "GMT-01:11", "-0111", new Integer(8)},
  75             {"GMT -13:42", new Long(0),         "GMT",       "+0000", new Integer(3)},
  76             {"-0304",      new Long(184 * mpm), "GMT-03:04", "-0304", new Integer(5)},
  77             {"-1342",      new Long(822 * mpm), "GMT-13:42", "-1342", new Integer(5)},
  78             {" -1342",     new Long(822 * mpm), "GMT-13:42", "-1342", new Integer(6)},
  79             /* ISO-LATIN-1 digits */
  80             {"GMT-\u0030\u0031:\u0032\u0033", new Long(83 * mpm), "GMT-01:23", "-0123", new Integer(9)},
  81            /* In fact, this test case is skipped because TimeZone class can't
  82             * recognize TimeZone IDs like "+00234" or "-00234".
  83             */
  84             {"-00234",     new Long(23 * mpm),  "GMT+00:23", "-0023", new Integer(5)},
  85         };
  86 
  87         Object[][] invalids = {
  88           /* given ID       error index   */
  89             {"GMT+8",       new Integer(5)},
  90             {"GMT+18",      new Integer(6)},
  91             {"GMT+208",     new Integer(6)},
  92             {"GMT+0304",    new Integer(6)},
  93             {"GMT+42195",   new Integer(5)},
  94             {"GMT+5:8",     new Integer(7)},
  95             {"GMT+23:60",   new Integer(8)},
  96             {"GMT+11:1",    new Integer(8)},
  97             {"GMT+24:13",   new Integer(5)},
  98             {"GMT+421:950", new Integer(5)},
  99             {"GMT+0a:0A",   new Integer(5)},
 100             {"GMT+ 13:42",  new Integer(4)},
 101             {"GMT+13 :42",  new Integer(6)},
 102             {"GMT+13: 42",  new Integer(7)},
 103             {"GMT+-13:42",  new Integer(4)},
 104             {"G M T",       new Integer(0)},
 105             {"+8",          new Integer(2)},
 106             {"+18",         new Integer(3)},
 107             {"+208",        new Integer(4)},
 108             {"+2360",       new Integer(4)},
 109             {"+2413",       new Integer(2)},
 110             {"+42195",      new Integer(2)},
 111             {"+0AbC",       new Integer(2)},
 112             {"+ 1342",      new Integer(1)},
 113             {"+-1342",      new Integer(1)},
 114             {"1342",        new Integer(0)},
 115           /* Arabic-Indic digits */
 116             {"GMT+\u0660\u0661:\u0662\u0663", new Integer(4)},
 117           /* Extended Arabic-Indic digits */
 118             {"GMT+\u06f0\u06f1:\u06f2\u06f3", new Integer(4)},
 119           /* Devanagari digits */
 120             {"GMT+\u0966\u0967:\u0968\u0969", new Integer(4)},
 121           /* Fullwidth digits */
 122             {"GMT+\uFF10\uFF11:\uFF12\uFF13", new Integer(4)},
 123 
 124             {"GMT-8",       new Integer(5)},
 125             {"GMT-18",      new Integer(6)},
 126             {"GMT-208",     new Integer(6)},
 127             {"GMT-0304",    new Integer(6)},
 128             {"GMT-42195",   new Integer(5)},
 129             {"GMT-5:8",     new Integer(7)},
 130             {"GMT-23:60",   new Integer(8)},
 131             {"GMT-11:1",    new Integer(8)},
 132             {"GMT-24:13",   new Integer(5)},
 133             {"GMT-421:950", new Integer(5)},
 134             {"GMT-0a:0A",   new Integer(5)},
 135             {"GMT- 13:42",  new Integer(4)},
 136             {"GMT-13 :42",  new Integer(6)},
 137             {"GMT-13: 42",  new Integer(7)},
 138             {"GMT-+13:42",  new Integer(4)},
 139             {"-8",          new Integer(2)},
 140             {"-18",         new Integer(3)},
 141             {"-208",        new Integer(4)},
 142             {"-2360",       new Integer(4)},
 143             {"-2413",       new Integer(2)},
 144             {"-42195",      new Integer(2)},
 145             {"-0AbC",       new Integer(2)},
 146             {"- 1342",      new Integer(1)},
 147             {"--1342",      new Integer(1)},
 148             {"-802",        new Integer(2)},
 149           /* Arabic-Indic digits */
 150             {"GMT-\u0660\u0661:\u0662\u0663", new Integer(4)},
 151           /* Extended Arabic-Indic digits */
 152             {"GMT-\u06f0\u06f1:\u06f2\u06f3", new Integer(4)},
 153           /* Devanagari digits */
 154             {"GMT-\u0966\u0967:\u0968\u0969", new Integer(4)},
 155           /* Fullwidth digits */
 156             {"GMT-\uFF10\uFF11:\uFF12\uFF13", new Integer(4)},
 157         };
 158 
 159         try {
 160             for (int i=0; i < locs.length; i++) {
 161                 Locale locale = locs[i];
 162                 Locale.setDefault(locale);
 163 
 164                 for (int j=0; j < formats.length; j++) {
 165                     TimeZone.setDefault(TimeZone.getTimeZone("GMT"));
 166                     SimpleDateFormat sdf = new SimpleDateFormat(formats[j]);
 167                     Date date;
 168 
 169                     /* Okay case */
 170                     for (int k=0; k < valids.length; k++) {
 171                         ParsePosition pos = new ParsePosition(0);
 172                         try {
 173                             date = sdf.parse((String)valids[k][0], pos);
 174                         }
 175                         catch (Exception e) {
 176                             err = true;
 177                             System.err.println("\tParse  Error [Locale=" +
 178                                 locale + ", " + formats[j] +
 179                                 "/\"" + valids[k][0] +
 180                                 "\"] Unexpected Exception occurred: " + e);
 181                             continue;
 182                         }
 183 
 184                         int offset = pos.getIndex();
 185                         if (offset != ((Integer)valids[k][4]).intValue()) {
 186                             err = true;
 187                             System.err.println("\tParse  Error [Locale=" +
 188                                 locale + ", " + formats[j] +
 189                                 "/\"" + valids[k][0] +
 190                                 "\"] invalid index: expected:" + valids[k][4] +
 191                                 ", got:" + offset);
 192                         }
 193 
 194                         if (date.getTime() != ((Long)valids[k][1]).longValue()) {
 195                             err = true;
 196                             System.err.println("\tParse  Error [Locale=" +
 197                                 locale + ", " + formats[j] +
 198                                 "/\"" + valids[k][0] +
 199                                 "\"] expected:" + valids[k][1] +
 200                                 ", got:" + date.getTime() + ", " + date);
 201                         } else {
 202 /*
 203                             logln("\tParse  Okay  [Locale=" +
 204                                 locale) + ", " + formats[j] +
 205                                 "/\"" + valids[k][0] +
 206                                 "\"] expected:" + valids[k][1] +
 207                                 ", got:" + date.getTime() + ", " + date);
 208 */
 209 
 210                             try {
 211                                 date = sdf.parse((String)valids[k][0]);
 212                             }
 213                             catch (Exception e) {
 214                                 err = true;
 215                                 System.err.println("\tParse  Error [Locale=" +
 216                                     locale + ", " + formats[j] +
 217                                     "/\"" + valids[k][0] +
 218                                     "\"] Unexpected Exception occurred: " + e);
 219                                 continue;
 220                             }
 221 
 222                             /* Since TimeZone.getTimeZone() don't treat
 223                              * "+00234" or "-00234" as a valid ID, skips.
 224                              */
 225                             if (((String)valids[k][0]).length() == 6) {
 226                                 continue;
 227                             }
 228 
 229                             /* Since TimeZone.getTimeZone() don't recognize
 230                              * +hhmm/-hhmm format, add "GMT" as prefix.
 231                              */
 232                             sdf.setTimeZone(TimeZone.getTimeZone(
 233                                 (((((String)valids[k][0]).charAt(0) != 'G') ?
 234                                 "GMT" : "") + valids[k][0])));
 235                             StringBuffer s = new StringBuffer();
 236                             sdf.format(date, s, new FieldPosition(0));
 237                             sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
 238 
 239                             String got = s.toString();
 240                             String expected = (String)valids[k][2+j];
 241                             if (!got.equals(expected) &&
 242                                 // special case to allow the difference between
 243                                 // DateFormatSymbols.getZoneStrings() and
 244                                 // TimeZone.getDisplayName() for "GMT+-00:00"
 245                                 !(got.equals("GMT-00:00") &&
 246                                   expected.equals("GMT+00:00"))) {
 247                                 err = true;
 248                                 System.err.println("\tFormat Error [Locale=" +
 249                                     locale + ", " +
 250                                     formats[j] + "/\"" + valids[k][0] +
 251                                     "\"] expected:" + valids[k][2+j] +
 252                                     ", got:" + s + ", " + date);
 253                             } else {
 254 /*
 255                                 logln("\tFormat Okay  [Locale=" +
 256                                     locale + ", " +
 257                                     formats[j] + "/\"" + valids[k][0] +
 258                                     "\"] expected:" + valids[k][2+j] +
 259                                     ", got:" + s + ", " + date);
 260 */
 261                             }
 262                         }
 263                     }
 264 
 265                     /* Error case 1
 266                      *   using SimpleDateFormat.parse(String, ParsePosition)
 267                      */
 268                     for (int k=0; k < invalids.length; k++) {
 269                         ParsePosition pos = new ParsePosition(0);
 270                         try {
 271                             date = sdf.parse((String)invalids[k][0], pos);
 272                             if (date != null) {
 273                                 err = true;
 274                                 System.err.println("\tParse  Error [Locale=" +
 275                                     locale + ", " + formats[j] +
 276                                     "/\"" + invalids[k][0] +
 277                                     "\"] expected:null , got:" + date);
 278                             }
 279                             int offset = pos.getErrorIndex();
 280                             if (offset != ((Integer)invalids[k][1]).intValue()) {
 281                                 err = true;
 282                                 System.err.println("\tParse  Error [Locale=" +
 283                                     locale + ", " + formats[j] +
 284                                     "/\"" + invalids[k][0] +
 285                                     "\"] incorrect offset. expected:" +
 286                                     invalids[k][1] + ", got: " + offset);
 287                             } else {
 288 /*
 289                                 logln("\tParse  Okay  [Locale=" +
 290                                     locale + ", " + formats[j] +
 291                                     "/\"" + invalids[k][0] +
 292                                     "\"] correct offset: " + offset);
 293 */
 294                             }
 295                         }
 296                         catch (Exception e) {
 297                             err = true;
 298                             System.err.println("\tParse  Error [Locale=" +
 299                                 locale + ", " + formats[j] +
 300                                 "/\"" + invalids[k][0] +
 301                                 "\"] Unexpected Exception occurred: " + e);
 302                         }
 303                     }
 304 
 305                     /* Error case 2
 306                      *   using DateFormat.parse(String)
 307                      */
 308                     boolean correctParseException = false;
 309                     for (int k=0; k < invalids.length; k++) {
 310                         try {
 311                             date = sdf.parse((String)invalids[k][0]);
 312                         }
 313                         catch (ParseException e) {
 314                             correctParseException = true;
 315                             int offset = e.getErrorOffset();
 316                             if (offset != ((Integer)invalids[k][1]).intValue()) {
 317                                 err = true;
 318                                 System.err.println("\tParse  Error [Locale=" +
 319                                     locale + ", " + formats[j] +
 320                                     "/\"" + invalids[k][0] +
 321                                     "\"] Expected exception occurred with an incorrect offset. expected:" +
 322                                     invalids[k][1] + ", got: " + offset);
 323                             } else {
 324 /*
 325                                 logln("\tParse  Okay  [Locale=" +
 326                                     locale + ", " + formats[j] +
 327                                     "/\"" + invalids[k][0] +
 328                                     "\"] Expected exception occurred with an correct offset: "
 329                                     + offset);
 330 */
 331                             }
 332                         }
 333                         catch (Exception e) {
 334                             err = true;
 335                             System.err.println("\tParse  Error [Locale=" +
 336                                 locale + ", " + formats[j] +
 337                                 "/\"" + invalids[k][0] +
 338                                 "\"] Invalid exception occurred: " + e);
 339                         }
 340                         finally {
 341                             if (!correctParseException) {
 342                                 err = true;
 343                                 System.err.println("\tParse  Error: [Locale=" +
 344                                     locale + ", " + formats[j] +
 345                                     "/\"" + invalids[k][0] +
 346                                     "\"] Expected exception didn't occur.");
 347                             }
 348                         }
 349                     }
 350                 }
 351             }
 352         }
 353         finally {
 354             Locale.setDefault(savedLocale);
 355             TimeZone.setDefault(savedTimeZone);
 356             if (err) {
 357                 errln("SimpleDateFormat.parse()/format() test failed");
 358             }
 359         }
 360     }
 361 
 362     public static void main(String[] args) throws Exception {
 363         new Bug4322313().run(args);
 364     }
 365 }