1 /*
   2  * Copyright (c) 2012, 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 8007572 8008161 8157792
  27  * @summary Test whether the TimeZone generated from JSR310 tzdb is the same
  28  * as the one from the tz data from javazic
  29  * @modules java.base/sun.util.calendar:+open
  30  * @build BackEnd Checksum DayOfWeek Gen GenDoc Main Mappings Month
  31  *        Rule RuleDay RuleRec Simple TestZoneInfo310 Time Timezone
  32  *        TzIDOldMapping Zone ZoneInfoFile ZoneInfoOld ZoneRec Zoneinfo
  33  * @run main TestZoneInfo310
  34  */
  35 
  36 import java.io.File;
  37 import java.lang.reflect.*;
  38 import java.nio.file.*;
  39 import java.util.*;
  40 import java.util.regex.*;
  41 import java.time.zone.*;
  42 import java.time.ZoneId;
  43 
  44 public class TestZoneInfo310 {
  45 
  46     public static void main(String[] args) throws Throwable {
  47 
  48         String TESTDIR = System.getProperty("test.dir", ".");
  49         String SRCDIR = System.getProperty("test.src", ".");
  50         String tzdir = SRCDIR + File.separator + "tzdata";
  51         String tzfiles = "africa antarctica asia australasia europe northamerica pacificnew southamerica backward etcetera systemv";
  52         String jdk_tzdir = SRCDIR + File.separator + "tzdata_jdk";
  53         String jdk_tzfiles = "gmt jdk11_backward";
  54         String zidir = TESTDIR + File.separator + "zi";
  55         File fZidir = new File(zidir);
  56         if (!fZidir.exists()) {
  57             fZidir.mkdirs();
  58         }
  59         Matcher m = Pattern.compile("tzdata(?<ver>[0-9]{4}[A-z])")
  60                            .matcher(new String(Files.readAllBytes(Paths.get(tzdir, "VERSION")), "ascii"));
  61         String ver = m.find() ? m.group("ver") : "NULL";
  62 
  63         ArrayList<String> alist = new ArrayList<>();
  64         alist.add("-V");
  65         alist.add(ver);
  66         alist.add("-d");
  67         alist.add(zidir);
  68         for (String f : tzfiles.split(" ")) {
  69             alist.add(tzdir + File.separator + f);
  70         }
  71         for (String f : jdk_tzfiles.split(" ")) {
  72             alist.add(jdk_tzdir + File.separator + f);
  73         }
  74         System.out.println("Compiling tz files!");
  75         Main.main(alist.toArray(new String[alist.size()]));
  76 
  77         //////////////////////////////////
  78         System.out.println("testing!");
  79         ZoneInfoFile.ziDir = zidir;
  80         long t0, t1;
  81 
  82         t0 = System.nanoTime();
  83         ZoneInfoOld.getTimeZone("America/Los_Angeles");
  84         t1 = System.nanoTime();
  85         System.out.printf("OLD.getZoneInfoOld()[1]=%d%n", (t1 - t0) / 1000);
  86 
  87         t0 = System.nanoTime();
  88         ZoneInfoOld.getTimeZone("America/New_York");
  89         t1 = System.nanoTime();
  90         System.out.printf("OLD.getZoneInfoOld()[2]=%d%n", (t1 - t0) / 1000);
  91 
  92         t0 = System.nanoTime();
  93         ZoneInfoOld.getTimeZone("America/Denver");
  94         t1 = System.nanoTime();
  95         System.out.printf("OLD.getZoneInfoOld()[3]=%d%n", (t1 - t0) / 1000);
  96 
  97         t0 = System.nanoTime();
  98         String[] zids_old = ZoneInfoOld.getAvailableIDs();
  99         t1 = System.nanoTime();
 100         System.out.printf("OLD.getAvailableIDs()=%d, total=%d%n",
 101                           (t1 - t0) / 1000, zids_old.length);
 102         Arrays.sort(zids_old);
 103 
 104         t0 = System.nanoTime();
 105         String[] alias_old = ZoneInfoOld.getAliasTable()
 106                                  .keySet().toArray(new String[0]);
 107         t1 = System.nanoTime();
 108         System.out.printf("OLD.getAliasTable()=%d, total=%d%n",
 109                           (t1 - t0) / 1000, alias_old.length);
 110         Arrays.sort(alias_old);
 111 
 112         t0 = System.currentTimeMillis();
 113         for (String zid : zids_old) {
 114             ZoneInfoOld.getTimeZone(zid);
 115         }
 116         t1 = System.currentTimeMillis();
 117         System.out.printf("OLD.TotalTZ()=%d (ms)%n", t1 - t0);
 118 
 119 /*
 120         t0 = System.nanoTime();
 121         ZoneId.of("America/Los_Angeles").getRules();
 122         t1 = System.nanoTime();
 123         System.out.printf("NEW.ZoneId.of()[1]=%d%n", (t1 - t0) / 1000);
 124 */
 125         t0 = System.nanoTime();
 126         TimeZone tz = TimeZone.getTimeZone("America/Los_Angeles");
 127         t1 = System.nanoTime();
 128         System.out.printf("NEW.getTimeZone()[1]=%d%n", (t1 - t0) / 1000);
 129 
 130         t0 = System.nanoTime();
 131         tz = TimeZone.getTimeZone("America/New_York");
 132         t1 = System.nanoTime();
 133         System.out.printf("NEW.getTimeZone()[2]=%d%n", (t1 - t0) / 1000);
 134 
 135         t0 = System.nanoTime();
 136         tz = TimeZone.getTimeZone("America/Denver");
 137         t1 = System.nanoTime();
 138         System.out.printf("NEW.getTimeZone()[3]=%d%n", (t1 - t0) / 1000);
 139 
 140         t0 = System.nanoTime();
 141         String[] zids_new = TimeZone.getAvailableIDs();
 142         t1 = System.nanoTime();
 143         System.out.printf("NEW.getAvailableIDs()=%d, total=%d%n",
 144                           (t1 - t0) / 1000, zids_new.length);
 145         Arrays.sort(zids_new);
 146 
 147         t0 = System.nanoTime();
 148         String[] alias_new = sun.util.calendar.ZoneInfo.getAliasTable()
 149                                  .keySet().toArray(new String[0]);
 150         t1 = System.nanoTime();
 151         System.out.printf("NEW.getAliasTable()=%d, total=%d%n",
 152                           (t1 - t0) / 1000, alias_new.length);
 153         Arrays.sort(alias_new);
 154 
 155         t0 = System.currentTimeMillis();
 156         for (String zid : zids_new) {
 157             TimeZone.getTimeZone(zid);
 158         }
 159         t1 = System.currentTimeMillis();
 160         System.out.printf("NEW.TotalTZ()=%d (ms)%n", t1 - t0);
 161 
 162         if (!Arrays.equals(zids_old, zids_new)) {
 163             throw new RuntimeException("  FAILED:  availableIds don't match");
 164         }
 165 
 166         if (!Arrays.equals(alias_old, alias_new)) {
 167             throw new RuntimeException("  FAILED:  aliases don't match");
 168         }
 169 
 170         for (String zid : zids_new) {
 171             ZoneInfoOld zi = toZoneInfoOld(TimeZone.getTimeZone(zid));
 172             ZoneInfoOld ziOLD = (ZoneInfoOld)ZoneInfoOld.getTimeZone(zid);
 173             if (! zi.equalsTo(ziOLD)) {
 174                 System.out.println(zi.diffsTo(ziOLD));
 175                 throw new RuntimeException("  FAILED:  " + zid);
 176             }
 177         }
 178         delete(fZidir);
 179 
 180         // test tzdb version
 181         if (!ver.equals(sun.util.calendar.ZoneInfoFile.getVersion())) {
 182             System.out.printf("  FAILED:  ver=%s, expected=%s%n",
 183                               sun.util.calendar.ZoneInfoFile.getVersion(), ver);
 184             throw new RuntimeException("Version test failed");
 185         }
 186 
 187         // test getAvailableIDs(raw);
 188         zids_new = TimeZone.getAvailableIDs(-8 * 60 * 60 * 1000);
 189         //Arrays.sort(zids_new);
 190         zids_old = ZoneInfoOld.getAvailableIDs(-8 * 60 * 60 * 1000);
 191         if (!Arrays.equals(zids_new, zids_old)) {
 192             System.out.println("------------------------");
 193             System.out.println("NEW.getAvailableIDs(-8:00)");
 194             for (String zid : zids_new) {
 195                 System.out.println(zid);
 196             }
 197             System.out.println("------------------------");
 198             System.out.println("OLD.getAvailableIDs(-8:00)");
 199             for (String zid : zids_old) {
 200                 System.out.println(zid);
 201             }
 202             throw new RuntimeException("  FAILED:  availableIds(offset) don't match");
 203         }
 204     }
 205 
 206     private static void delete(File f) {
 207         if (f.isDirectory()) {
 208             for (File f0 : f.listFiles()) {
 209                delete(f0);
 210             }
 211         }
 212         f.delete();
 213      }
 214 
 215     // to access sun.util.calendar.ZoneInfo's private fields
 216     static Class<?> ziClz;
 217     static Field rawOffset;
 218     static Field checksum;
 219     static Field dstSavings;
 220     static Field transitions;
 221     static Field offsets;
 222     static Field simpleTimeZoneParams;
 223     static Field willGMTOffsetChange;
 224     static {
 225         try {
 226             ziClz = Class.forName("sun.util.calendar.ZoneInfo");
 227             rawOffset = ziClz.getDeclaredField("rawOffset");
 228             checksum = ziClz.getDeclaredField("checksum");
 229             dstSavings = ziClz.getDeclaredField("dstSavings");
 230             transitions = ziClz.getDeclaredField("transitions");
 231             offsets = ziClz.getDeclaredField("offsets");
 232             simpleTimeZoneParams = ziClz.getDeclaredField("simpleTimeZoneParams");
 233             willGMTOffsetChange = ziClz.getDeclaredField("willGMTOffsetChange");
 234             rawOffset.setAccessible(true);
 235             checksum.setAccessible(true);
 236             dstSavings.setAccessible(true);
 237             transitions.setAccessible(true);
 238             offsets.setAccessible(true);
 239             simpleTimeZoneParams.setAccessible(true);
 240             willGMTOffsetChange.setAccessible(true);
 241         } catch (Exception x) {
 242             throw new RuntimeException(x);
 243         }
 244     }
 245 
 246     private static ZoneInfoOld toZoneInfoOld(TimeZone tz) throws Exception {
 247         return new ZoneInfoOld(tz.getID(),
 248                                rawOffset.getInt(tz),
 249                                dstSavings.getInt(tz),
 250                                checksum.getInt(tz),
 251                                (long[])transitions.get(tz),
 252                                (int[])offsets.get(tz),
 253                                (int[])simpleTimeZoneParams.get(tz),
 254                                willGMTOffsetChange.getBoolean(tz));
 255     }
 256 
 257 
 258 }