1 /*
   2  * Copyright (c) 1997, 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 4028006 4044013 4096694 4107276 4107570 4112869 4130885 7039469 7126465 7158483
  27  *      8008577 8077685 8098547 8133321 8138716 8148446 8151876 8159684 8166875
  28  * @modules java.base/sun.util.resources
  29  * @library /java/text/testlib
  30  * @summary test TimeZone
  31  */
  32 
  33 import java.io.*;
  34 import java.text.*;
  35 import java.util.*;
  36 import sun.util.resources.LocaleData;
  37 
  38 public class TimeZoneTest extends IntlTest
  39 {
  40     static final int millisPerHour = 3600000;
  41 
  42     public static void main(String[] args) throws Exception {
  43         new TimeZoneTest().run(args);
  44     }
  45 
  46     /**
  47      * Bug 4130885
  48      * Certain short zone IDs, used since 1.1.x, are incorrect.
  49      *
  50      * The worst of these is:
  51      *
  52      * "CAT" (Central African Time) should be GMT+2:00, but instead returns a
  53      * zone at GMT-1:00. The zone at GMT-1:00 should be called EGT, CVT, EGST,
  54      * or AZOST, depending on which zone is meant, but in no case is it CAT.
  55      *
  56      * Other wrong zone IDs:
  57      *
  58      * ECT (European Central Time) GMT+1:00: ECT is Ecuador Time,
  59      * GMT-5:00. European Central time is abbreviated CEST.
  60      *
  61      * SST (Solomon Island Time) GMT+11:00. SST is actually Samoa Standard Time,
  62      * GMT-11:00. Solomon Island time is SBT.
  63      *
  64      * NST (New Zealand Time) GMT+12:00. NST is the abbreviation for
  65      * Newfoundland Standard Time, GMT-3:30. New Zealanders use NZST.
  66      *
  67      * AST (Alaska Standard Time) GMT-9:00. [This has already been noted in
  68      * another bug.] It should be "AKST". AST is Atlantic Standard Time,
  69      * GMT-4:00.
  70      *
  71      * PNT (Phoenix Time) GMT-7:00. PNT usually means Pitcairn Time,
  72      * GMT-8:30. There is no standard abbreviation for Phoenix time, as distinct
  73      * from MST with daylight savings.
  74      *
  75      * In addition to these problems, a number of zones are FAKE. That is, they
  76      * don't match what people use in the real world.
  77      *
  78      * FAKE zones:
  79      *
  80      * EET (should be EEST)
  81      * ART (should be EET)
  82      * MET (should be IRST)
  83      * NET (should be AMST)
  84      * PLT (should be PKT)
  85      * BST (should be BDT)
  86      * VST (should be ICT)
  87      * CTT (should be CST) +
  88      * ACT (should be CST) +
  89      * AET (should be EST) +
  90      * MIT (should be WST) +
  91      * IET (should be EST) +
  92      * PRT (should be AST) +
  93      * CNT (should be NST)
  94      * AGT (should be ARST)
  95      * BET (should be EST) +
  96      *
  97      * + A zone with the correct name already exists and means something
  98      * else. E.g., EST usually indicates the US Eastern zone, so it cannot be
  99      * used for Brazil (BET).
 100      */
 101     public void TestShortZoneIDs() throws Exception {
 102 
 103         ZoneDescriptor[] JDK_116_REFERENCE_LIST = {
 104             new ZoneDescriptor("MIT", 780, true),
 105             new ZoneDescriptor("HST", -600, false),
 106             new ZoneDescriptor("AST", -540, true),
 107             new ZoneDescriptor("PST", -480, true),
 108             new ZoneDescriptor("PNT", -420, false),
 109             new ZoneDescriptor("MST", -420, false),
 110             new ZoneDescriptor("CST", -360, true),
 111             new ZoneDescriptor("IET", -300, true),
 112             new ZoneDescriptor("EST", -300, false),
 113             new ZoneDescriptor("PRT", -240, false),
 114             new ZoneDescriptor("CNT", -210, true),
 115             new ZoneDescriptor("AGT", -180, false),
 116             new ZoneDescriptor("BET", -180, true),
 117             // new ZoneDescriptor("CAT", -60, false), // Wrong:
 118             // As of bug 4130885, fix CAT (Central Africa)
 119             new ZoneDescriptor("CAT", 120, false), // Africa/Harare
 120             new ZoneDescriptor("GMT", 0, false),
 121             new ZoneDescriptor("UTC", 0, false),
 122             new ZoneDescriptor("ECT", 60, true),
 123             new ZoneDescriptor("ART", 120, false),
 124             new ZoneDescriptor("EET", 120, true),
 125             new ZoneDescriptor("EAT", 180, false),
 126             new ZoneDescriptor("MET", 60, true),
 127             new ZoneDescriptor("NET", 240, false),
 128             new ZoneDescriptor("PLT", 300, false),
 129             new ZoneDescriptor("IST", 330, false),
 130             new ZoneDescriptor("BST", 360, false),
 131             new ZoneDescriptor("VST", 420, false),
 132             new ZoneDescriptor("CTT", 480, false),
 133             new ZoneDescriptor("JST", 540, false),
 134             new ZoneDescriptor("ACT", 570, false),
 135             new ZoneDescriptor("AET", 600, true),
 136             new ZoneDescriptor("SST", 660, false),
 137             // new ZoneDescriptor("NST", 720, false),
 138             // As of bug 4130885, fix NST (New Zealand)
 139             new ZoneDescriptor("NST", 720, true), // Pacific/Auckland
 140         };
 141 
 142         Map<String, ZoneDescriptor> hash = new HashMap<>();
 143 
 144         String[] ids = TimeZone.getAvailableIDs();
 145         for (String id : ids) {
 146             if (id.length() == 3) {
 147                 hash.put(id, new ZoneDescriptor(TimeZone.getTimeZone(id)));
 148             }
 149         }
 150 
 151         for (int i = 0; i < JDK_116_REFERENCE_LIST.length; ++i) {
 152             ZoneDescriptor referenceZone = JDK_116_REFERENCE_LIST[i];
 153             ZoneDescriptor currentZone = hash.get(referenceZone.getID());
 154             if (referenceZone.equals(currentZone)) {
 155                 logln("ok " + referenceZone);
 156             }
 157             else {
 158                 errln("Fail: Expected " + referenceZone +
 159                       "; got " + currentZone);
 160             }
 161         }
 162     }
 163 
 164     /**
 165      * A descriptor for a zone; used to regress the short zone IDs.
 166      */
 167     static class ZoneDescriptor {
 168         String id;
 169         int offset; // In minutes
 170         boolean daylight;
 171 
 172         ZoneDescriptor(TimeZone zone) {
 173             this.id = zone.getID();
 174             this.offset = zone.getRawOffset() / 60000;
 175             this.daylight = zone.useDaylightTime();
 176         }
 177 
 178         ZoneDescriptor(String id, int offset, boolean daylight) {
 179             this.id = id;
 180             this.offset = offset;
 181             this.daylight = daylight;
 182         }
 183 
 184         public String getID() { return id; }
 185 
 186         @Override
 187         public boolean equals(Object o) {
 188             ZoneDescriptor that = (ZoneDescriptor)o;
 189             return that != null &&
 190                 id.equals(that.id) &&
 191                 offset == that.offset &&
 192                 daylight == that.daylight;
 193         }
 194 
 195         @Override
 196         public int hashCode() {
 197             return id.hashCode() ^ offset | (daylight ? 1 : 0);
 198         }
 199 
 200         @Override
 201         public String toString() {
 202             int min = offset;
 203             char sign = '+';
 204             if (min < 0) { sign = '-'; min = -min; }
 205 
 206             return "Zone[\"" + id + "\", GMT" + sign + (min/60) + ':' +
 207                 (min%60<10?"0":"") + (min%60) + ", " +
 208                 (daylight ? "Daylight" : "Standard") + "]";
 209         }
 210 
 211         public static int compare(Object o1, Object o2) {
 212             ZoneDescriptor i1 = (ZoneDescriptor)o1;
 213             ZoneDescriptor i2 = (ZoneDescriptor)o2;
 214             if (i1.offset > i2.offset) return 1;
 215             if (i1.offset < i2.offset) return -1;
 216             if (i1.daylight && !i2.daylight) return 1;
 217             if (!i1.daylight && i2.daylight) return -1;
 218             return i1.id.compareTo(i2.id);
 219         }
 220     }
 221 
 222     static final String formatMinutes(int min) {
 223         char sign = '+';
 224         if (min < 0) { sign = '-'; min = -min; }
 225         int h = min/60;
 226         min = min%60;
 227         return "" + sign + h + ":" + ((min<10) ? "0" : "") + min;
 228     }
 229     /**
 230      * As part of the VM fix (see CCC approved RFE 4028006, bug
 231      * 4044013), TimeZone.getTimeZone() has been modified to recognize
 232      * generic IDs of the form GMT[+-]hh:mm, GMT[+-]hhmm, and
 233      * GMT[+-]hh.  Test this behavior here.
 234      *
 235      * Bug 4044013
 236      *
 237      * ID "Custom" is no longer used for TimeZone objects created with
 238      * a custom time zone ID, such as "GMT-8". See 4322313.
 239      */
 240     public void TestCustomParse() throws Exception {
 241         Object[] DATA = {
 242             // ID        Expected offset in minutes
 243             "GMT",       null,
 244             "GMT+0",     new Integer(0),
 245             "GMT+1",     new Integer(60),
 246             "GMT-0030",  new Integer(-30),
 247             "GMT+15:99", null,
 248             "GMT+",      null,
 249             "GMT-",      null,
 250             "GMT+0:",    null,
 251             "GMT-:",     null,
 252             "GMT+0010",  new Integer(10), // Interpret this as 00:10
 253             "GMT-10",    new Integer(-10*60),
 254             "GMT+30",    null,
 255             "GMT-3:30",  new Integer(-(3*60+30)),
 256             "GMT-230",   new Integer(-(2*60+30)),
 257         };
 258         for (int i=0; i<DATA.length; i+=2) {
 259             String id = (String)DATA[i];
 260             Integer exp = (Integer)DATA[i+1];
 261             TimeZone zone = TimeZone.getTimeZone(id);
 262             if (zone.getID().equals("GMT")) {
 263                 logln(id + " -> generic GMT");
 264                 // When TimeZone.getTimeZone() can't parse the id, it
 265                 // returns GMT -- a dubious practice, but required for
 266                 // backward compatibility.
 267                 if (exp != null) {
 268                     throw new Exception("Expected offset of " + formatMinutes(exp.intValue()) +
 269                                         " for " + id + ", got parse failure");
 270                 }
 271             }
 272             else {
 273                 int ioffset = zone.getRawOffset()/60000;
 274                 String offset = formatMinutes(ioffset);
 275                 logln(id + " -> " + zone.getID() + " GMT" + offset);
 276                 if (exp == null) {
 277                     throw new Exception("Expected parse failure for " + id +
 278                                         ", got offset of " + offset +
 279                                         ", id " + zone.getID());
 280                 }
 281                 else if (ioffset != exp.intValue()) {
 282                     throw new Exception("Expected offset of " + formatMinutes(exp.intValue()) +
 283                                         ", id Custom, for " + id +
 284                                         ", got offset of " + offset +
 285                                         ", id " + zone.getID());
 286                 }
 287             }
 288         }
 289     }
 290 
 291     /**
 292      * Test the basic functionality of the getDisplayName() API.
 293      *
 294      * Bug 4112869
 295      * Bug 4028006
 296      *
 297      * See also API change request A41.
 298      *
 299      * 4/21/98 - make smarter, so the test works if the ext resources
 300      * are present or not.
 301      */
 302     public void TestDisplayName() {
 303         TimeZone zone = TimeZone.getTimeZone("PST");
 304         String name = zone.getDisplayName(Locale.ENGLISH);
 305         logln("PST->" + name);
 306         if (!name.equals("Pacific Standard Time"))
 307             errln("Fail: Expected \"Pacific Standard Time\"");
 308 
 309         //*****************************************************************
 310         // THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES
 311         // THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES
 312         // THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES
 313         //*****************************************************************
 314         Object[] DATA = {
 315             new Boolean(false), new Integer(TimeZone.SHORT), "PST",
 316             new Boolean(true),  new Integer(TimeZone.SHORT), "PDT",
 317             new Boolean(false), new Integer(TimeZone.LONG),  "Pacific Standard Time",
 318             new Boolean(true),  new Integer(TimeZone.LONG),  "Pacific Daylight Time",
 319         };
 320 
 321         for (int i=0; i<DATA.length; i+=3) {
 322             name = zone.getDisplayName(((Boolean)DATA[i]).booleanValue(),
 323                                        ((Integer)DATA[i+1]).intValue(),
 324                                        Locale.ENGLISH);
 325             if (!name.equals(DATA[i+2]))
 326                 errln("Fail: Expected " + DATA[i+2] + "; got " + name);
 327         }
 328 
 329         // Make sure that we don't display the DST name by constructing a fake
 330         // PST zone that has DST all year long.
 331         SimpleTimeZone zone2 = new SimpleTimeZone(0, "PST");
 332         zone2.setStartRule(Calendar.JANUARY, 1, 0);
 333         zone2.setEndRule(Calendar.DECEMBER, 31, 0);
 334         logln("Modified PST inDaylightTime->" + zone2.inDaylightTime(new Date()));
 335         name = zone2.getDisplayName(Locale.ENGLISH);
 336         logln("Modified PST->" + name);
 337         if (!name.equals("Pacific Standard Time"))
 338             errln("Fail: Expected \"Pacific Standard Time\"");
 339 
 340         // Make sure we get the default display format for Locales
 341         // with no display name data.
 342         Locale zh_CN = Locale.SIMPLIFIED_CHINESE;
 343         name = zone.getDisplayName(zh_CN);
 344         //*****************************************************************
 345         // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES
 346         // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES
 347         // THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES
 348         //*****************************************************************
 349         logln("PST(zh_CN)->" + name);
 350 
 351         // Now be smart -- check to see if zh resource is even present.
 352         // If not, we expect the en fallback behavior.
 353         ResourceBundle enRB = LocaleData.getBundle("sun.util.resources.TimeZoneNames",
 354                                                    Locale.ENGLISH);
 355         ResourceBundle zhRB = LocaleData.getBundle("sun.util.resources.TimeZoneNames",
 356                                                    zh_CN);
 357 
 358         boolean noZH = enRB == zhRB;
 359 
 360         if (noZH) {
 361             logln("Warning: Not testing the zh_CN behavior because resource is absent");
 362             if (!name.equals("Pacific Standard Time"))
 363                 errln("Fail: Expected Pacific Standard Time");
 364         }
 365         else if (!name.equals("Pacific Standard Time") &&
 366                  !name.equals("\u592a\u5e73\u6d0b\u6807\u51c6\u65f6\u95f4") &&
 367                  !name.equals("GMT-08:00") &&
 368                  !name.equals("GMT-8:00") &&
 369                  !name.equals("GMT-0800") &&
 370                  !name.equals("GMT-800")) {
 371             errln("Fail: Expected GMT-08:00 or something similar");
 372             errln("************************************************************");
 373             errln("THE ABOVE FAILURE MAY JUST MEAN THE LOCALE DATA HAS CHANGED");
 374             errln("************************************************************");
 375         }
 376 
 377         // Now try a non-existent zone
 378         zone2 = new SimpleTimeZone(90*60*1000, "xyzzy");
 379         name = zone2.getDisplayName(Locale.ENGLISH);
 380         logln("GMT+90min->" + name);
 381         if (!name.equals("GMT+01:30") &&
 382             !name.equals("GMT+1:30") &&
 383             !name.equals("GMT+0130") &&
 384             !name.equals("GMT+130"))
 385             errln("Fail: Expected GMT+01:30 or something similar");
 386     }
 387 
 388     public void TestGenericAPI() {
 389         String id = "NewGMT";
 390         int offset = 12345;
 391 
 392         SimpleTimeZone zone = new SimpleTimeZone(offset, id);
 393         if (zone.useDaylightTime()) {
 394             errln("FAIL: useDaylightTime should return false");
 395         }
 396 
 397         TimeZone zoneclone = (TimeZone)zone.clone();
 398         if (!zoneclone.equals(zone)) {
 399             errln("FAIL: clone or operator== failed");
 400         }
 401         zoneclone.setID("abc");
 402         if (zoneclone.equals(zone)) {
 403             errln("FAIL: clone or operator!= failed");
 404         }
 405 
 406         zoneclone = (TimeZone)zone.clone();
 407         if (!zoneclone.equals(zone)) {
 408             errln("FAIL: clone or operator== failed");
 409         }
 410         zoneclone.setRawOffset(45678);
 411         if (zoneclone.equals(zone)) {
 412             errln("FAIL: clone or operator!= failed");
 413         }
 414 
 415         TimeZone saveDefault = TimeZone.getDefault();
 416         try {
 417             TimeZone.setDefault(zone);
 418             TimeZone defaultzone = TimeZone.getDefault();
 419             if (defaultzone == zone) {
 420                 errln("FAIL: Default object is identical, not clone");
 421             }
 422             if (!defaultzone.equals(zone)) {
 423                 errln("FAIL: Default object is not equal");
 424             }
 425         }
 426         finally {
 427             TimeZone.setDefault(saveDefault);
 428         }
 429     }
 430 
 431     @SuppressWarnings("deprecation")
 432     public void TestRuleAPI()
 433     {
 434         // ErrorCode status = ZERO_ERROR;
 435 
 436         int offset = (int)(60*60*1000*1.75); // Pick a weird offset
 437         SimpleTimeZone zone = new SimpleTimeZone(offset, "TestZone");
 438         if (zone.useDaylightTime()) errln("FAIL: useDaylightTime should return false");
 439 
 440         // Establish our expected transition times.  Do this with a non-DST
 441         // calendar with the (above) declared local offset.
 442         GregorianCalendar gc = new GregorianCalendar(zone);
 443         gc.clear();
 444         gc.set(1990, Calendar.MARCH, 1);
 445         long marchOneStd = gc.getTime().getTime(); // Local Std time midnight
 446         gc.clear();
 447         gc.set(1990, Calendar.JULY, 1);
 448         long julyOneStd = gc.getTime().getTime(); // Local Std time midnight
 449 
 450         // Starting and ending hours, WALL TIME
 451         int startHour = (int)(2.25 * 3600000);
 452         int endHour   = (int)(3.5  * 3600000);
 453 
 454         zone.setStartRule(Calendar.MARCH, 1, 0, startHour);
 455         zone.setEndRule  (Calendar.JULY,  1, 0, endHour);
 456 
 457         gc = new GregorianCalendar(zone);
 458         // if (failure(status, "new GregorianCalendar")) return;
 459 
 460         long marchOne = marchOneStd + startHour;
 461         long julyOne = julyOneStd + endHour - 3600000; // Adjust from wall to Std time
 462 
 463         long expMarchOne = 636251400000L;
 464         if (marchOne != expMarchOne)
 465         {
 466             errln("FAIL: Expected start computed as " + marchOne +
 467                   " = " + new Date(marchOne));
 468             logln("      Should be                  " + expMarchOne +
 469                   " = " + new Date(expMarchOne));
 470         }
 471 
 472         long expJulyOne = 646793100000L;
 473         if (julyOne != expJulyOne)
 474         {
 475             errln("FAIL: Expected start computed as " + julyOne +
 476                   " = " + new Date(julyOne));
 477             logln("      Should be                  " + expJulyOne +
 478                   " = " + new Date(expJulyOne));
 479         }
 480 
 481         testUsingBinarySearch(zone, new Date(90, Calendar.JANUARY, 1).getTime(),
 482                               new Date(90, Calendar.JUNE, 15).getTime(), marchOne);
 483         testUsingBinarySearch(zone, new Date(90, Calendar.JUNE, 1).getTime(),
 484                               new Date(90, Calendar.DECEMBER, 31).getTime(), julyOne);
 485 
 486         if (zone.inDaylightTime(new Date(marchOne - 1000)) ||
 487             !zone.inDaylightTime(new Date(marchOne)))
 488             errln("FAIL: Start rule broken");
 489         if (!zone.inDaylightTime(new Date(julyOne - 1000)) ||
 490             zone.inDaylightTime(new Date(julyOne)))
 491             errln("FAIL: End rule broken");
 492 
 493         zone.setStartYear(1991);
 494         if (zone.inDaylightTime(new Date(marchOne)) ||
 495             zone.inDaylightTime(new Date(julyOne - 1000)))
 496             errln("FAIL: Start year broken");
 497 
 498         // failure(status, "TestRuleAPI");
 499         // delete gc;
 500         // delete zone;
 501     }
 502 
 503     void testUsingBinarySearch(SimpleTimeZone tz, long min, long max, long expectedBoundary)
 504     {
 505         // ErrorCode status = ZERO_ERROR;
 506         boolean startsInDST = tz.inDaylightTime(new Date(min));
 507         // if (failure(status, "SimpleTimeZone::inDaylightTime")) return;
 508         if (tz.inDaylightTime(new Date(max)) == startsInDST) {
 509             logln("Error: inDaylightTime(" + new Date(max) + ") != " + (!startsInDST));
 510             return;
 511         }
 512         // if (failure(status, "SimpleTimeZone::inDaylightTime")) return;
 513         while ((max - min) > INTERVAL) {
 514             long mid = (min + max) / 2;
 515             if (tz.inDaylightTime(new Date(mid)) == startsInDST) {
 516                 min = mid;
 517             }
 518             else {
 519                 max = mid;
 520             }
 521             // if (failure(status, "SimpleTimeZone::inDaylightTime")) return;
 522         }
 523         logln("Binary Search Before: " + min + " = " + new Date(min));
 524         logln("Binary Search After:  " + max + " = " + new Date(max));
 525         long mindelta = expectedBoundary - min;
 526         long maxdelta = max - expectedBoundary;
 527         if (mindelta >= 0 &&
 528             mindelta <= INTERVAL &&
 529             mindelta >= 0 &&
 530             mindelta <= INTERVAL)
 531             logln("PASS: Expected bdry:  " + expectedBoundary + " = " + new Date(expectedBoundary));
 532         else
 533             errln("FAIL: Expected bdry:  " + expectedBoundary + " = " + new Date(expectedBoundary));
 534     }
 535 
 536     static final int INTERVAL = 100;
 537 
 538     // Bug 006; verify the offset for a specific zone.
 539     public void TestPRTOffset()
 540     {
 541         TimeZone tz = TimeZone.getTimeZone( "PRT" );
 542         if( tz == null ) {
 543             errln( "FAIL: TimeZone(PRT) is null" );
 544         }
 545         else{
 546             if (tz.getRawOffset() != (-4*millisPerHour))
 547                 errln("FAIL: Offset for PRT should be -4");
 548         }
 549 
 550     }
 551 
 552     // Test various calls
 553     @SuppressWarnings("deprecation")
 554     public void TestVariousAPI518()
 555     {
 556         TimeZone time_zone = TimeZone.getTimeZone("PST");
 557         Date d = new Date(97, Calendar.APRIL, 30);
 558 
 559         logln("The timezone is " + time_zone.getID());
 560 
 561         if (time_zone.inDaylightTime(d) != true)
 562             errln("FAIL: inDaylightTime returned false");
 563 
 564         if (time_zone.useDaylightTime() != true)
 565             errln("FAIL: useDaylightTime returned false");
 566 
 567         if (time_zone.getRawOffset() != -8*millisPerHour)
 568             errln( "FAIL: getRawOffset returned wrong value");
 569 
 570         GregorianCalendar gc = new GregorianCalendar();
 571         gc.setTime(d);
 572         if (time_zone.getOffset(gc.AD, gc.get(gc.YEAR), gc.get(gc.MONTH),
 573                                 gc.get(gc.DAY_OF_MONTH),
 574                                 gc.get(gc.DAY_OF_WEEK), 0)
 575             != -7*millisPerHour)
 576             errln("FAIL: getOffset returned wrong value");
 577     }
 578 
 579     // Test getAvailableID API
 580     public void TestGetAvailableIDs913()
 581     {
 582         StringBuffer buf = new StringBuffer("TimeZone.getAvailableIDs() = { ");
 583         String[] s = TimeZone.getAvailableIDs();
 584         for (int i=0; i<s.length; ++i)
 585         {
 586             if (i > 0) buf.append(", ");
 587             buf.append(s[i]);
 588         }
 589         buf.append(" };");
 590         logln(buf.toString());
 591 
 592         buf.setLength(0);
 593         buf.append("TimeZone.getAvailableIDs(GMT+02:00) = { ");
 594         s = TimeZone.getAvailableIDs(+2 * 60 * 60 * 1000);
 595         for (int i=0; i<s.length; ++i)
 596         {
 597             if (i > 0) buf.append(", ");
 598             buf.append(s[i]);
 599         }
 600         buf.append(" };");
 601         logln(buf.toString());
 602 
 603         TimeZone tz = TimeZone.getTimeZone("PST");
 604         if (tz != null)
 605             logln("getTimeZone(PST) = " + tz.getID());
 606         else
 607             errln("FAIL: getTimeZone(PST) = null");
 608 
 609         tz = TimeZone.getTimeZone("America/Los_Angeles");
 610         if (tz != null)
 611             logln("getTimeZone(America/Los_Angeles) = " + tz.getID());
 612         else
 613             errln("FAIL: getTimeZone(PST) = null");
 614 
 615         // Bug 4096694
 616         tz = TimeZone.getTimeZone("NON_EXISTENT");
 617         if (tz == null)
 618             errln("FAIL: getTimeZone(NON_EXISTENT) = null");
 619         else if (!tz.getID().equals("GMT"))
 620             errln("FAIL: getTimeZone(NON_EXISTENT) = " + tz.getID());
 621     }
 622 
 623     /**
 624      * Bug 4107276
 625      */
 626     public void TestDSTSavings() {
 627         // It might be better to find a way to integrate this test into the main TimeZone
 628         // tests above, but I don't have time to figure out how to do this (or if it's
 629         // even really a good idea).  Let's consider that a future.  --rtg 1/27/98
 630         SimpleTimeZone tz = new SimpleTimeZone(-5 * millisPerHour, "dstSavingsTest",
 631                                                Calendar.MARCH, 1, 0, 0, Calendar.SEPTEMBER, 1, 0, 0,
 632                                                (int)(0.5 * millisPerHour));
 633 
 634         if (tz.getRawOffset() != -5 * millisPerHour)
 635             errln("Got back a raw offset of " + (tz.getRawOffset() / millisPerHour) +
 636                   " hours instead of -5 hours.");
 637         if (!tz.useDaylightTime())
 638             errln("Test time zone should use DST but claims it doesn't.");
 639         if (tz.getDSTSavings() != 0.5 * millisPerHour)
 640             errln("Set DST offset to 0.5 hour, but got back " + (tz.getDSTSavings() /
 641                                                                  millisPerHour) + " hours instead.");
 642 
 643         int offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.JANUARY, 1,
 644                                   Calendar.THURSDAY, 10 * millisPerHour);
 645         if (offset != -5 * millisPerHour)
 646             errln("The offset for 10 AM, 1/1/98 should have been -5 hours, but we got "
 647                   + (offset / millisPerHour) + " hours.");
 648 
 649         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.JUNE, 1, Calendar.MONDAY,
 650                               10 * millisPerHour);
 651         if (offset != -4.5 * millisPerHour)
 652             errln("The offset for 10 AM, 6/1/98 should have been -4.5 hours, but we got "
 653                   + (offset / millisPerHour) + " hours.");
 654 
 655         tz.setDSTSavings(millisPerHour);
 656         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.JANUARY, 1,
 657                               Calendar.THURSDAY, 10 * millisPerHour);
 658         if (offset != -5 * millisPerHour)
 659             errln("The offset for 10 AM, 1/1/98 should have been -5 hours, but we got "
 660                   + (offset / millisPerHour) + " hours.");
 661 
 662         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.JUNE, 1, Calendar.MONDAY,
 663                               10 * millisPerHour);
 664         if (offset != -4 * millisPerHour)
 665             errln("The offset for 10 AM, 6/1/98 (with a 1-hour DST offset) should have been -4 hours, but we got "
 666                   + (offset / millisPerHour) + " hours.");
 667     }
 668 
 669     /**
 670      * Bug 4107570
 671      */
 672     public void TestAlternateRules() {
 673         // Like TestDSTSavings, this test should probably be integrated somehow with the main
 674         // test at the top of this class, but I didn't have time to figure out how to do that.
 675         //                      --rtg 1/28/98
 676 
 677         SimpleTimeZone tz = new SimpleTimeZone(-5 * millisPerHour, "alternateRuleTest");
 678 
 679         // test the day-of-month API
 680         tz.setStartRule(Calendar.MARCH, 10, 12 * millisPerHour);
 681         tz.setEndRule(Calendar.OCTOBER, 20, 12 * millisPerHour);
 682 
 683         int offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.MARCH, 5,
 684                                   Calendar.THURSDAY, 10 * millisPerHour);
 685         if (offset != -5 * millisPerHour)
 686             errln("The offset for 10AM, 3/5/98 should have been -5 hours, but we got "
 687                   + (offset / millisPerHour) + " hours.");
 688 
 689         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.MARCH, 15,
 690                               Calendar.SUNDAY, 10 * millisPerHour);
 691         if (offset != -4 * millisPerHour)
 692             errln("The offset for 10AM, 3/15/98 should have been -4 hours, but we got "
 693                   + (offset / millisPerHour) + " hours.");
 694 
 695         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.OCTOBER, 15,
 696                               Calendar.THURSDAY, 10 * millisPerHour);
 697         if (offset != -4 * millisPerHour)
 698             errln("The offset for 10AM, 10/15/98 should have been -4 hours, but we got "
 699                   + (offset / millisPerHour) + " hours.");
 700 
 701         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.OCTOBER, 25,
 702                               Calendar.SUNDAY, 10 * millisPerHour);
 703         if (offset != -5 * millisPerHour)
 704             errln("The offset for 10AM, 10/25/98 should have been -5 hours, but we got "
 705                   + (offset / millisPerHour) + " hours.");
 706 
 707         // test the day-of-week-after-day-in-month API
 708         tz.setStartRule(Calendar.MARCH, 10, Calendar.FRIDAY, 12 * millisPerHour, true);
 709         tz.setEndRule(Calendar.OCTOBER, 20, Calendar.FRIDAY, 12 * millisPerHour, false);
 710 
 711         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.MARCH, 11,
 712                               Calendar.WEDNESDAY, 10 * millisPerHour);
 713         if (offset != -5 * millisPerHour)
 714             errln("The offset for 10AM, 3/11/98 should have been -5 hours, but we got "
 715                   + (offset / millisPerHour) + " hours.");
 716 
 717         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.MARCH, 14,
 718                               Calendar.SATURDAY, 10 * millisPerHour);
 719         if (offset != -4 * millisPerHour)
 720             errln("The offset for 10AM, 3/14/98 should have been -4 hours, but we got "
 721                   + (offset / millisPerHour) + " hours.");
 722 
 723         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.OCTOBER, 15,
 724                               Calendar.THURSDAY, 10 * millisPerHour);
 725         if (offset != -4 * millisPerHour)
 726             errln("The offset for 10AM, 10/15/98 should have been -4 hours, but we got "
 727                   + (offset / millisPerHour) + " hours.");
 728 
 729         offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.OCTOBER, 17,
 730                               Calendar.SATURDAY, 10 * millisPerHour);
 731         if (offset != -5 * millisPerHour)
 732             errln("The offset for 10AM, 10/17/98 should have been -5 hours, but we got "
 733                   + (offset / millisPerHour) + " hours.");
 734     }
 735 }
 736 
 737 //eof