blob: 3ab3b3e634d7ff9dcc76e4b9916b701a52a9f7be [file] [log] [blame]
/**
*******************************************************************************
* Copyright (C) 2000-2009, International Business Machines Corporation and *
* others. All Rights Reserved. *
*******************************************************************************
*/
package com.ibm.icu.dev.test.timezone;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import com.ibm.icu.dev.test.TestFmwk;
import com.ibm.icu.impl.ICUResourceBundle;
import com.ibm.icu.text.SimpleDateFormat;
import com.ibm.icu.util.Calendar;
import com.ibm.icu.util.GregorianCalendar;
import com.ibm.icu.util.SimpleTimeZone;
import com.ibm.icu.util.TimeZone;
import com.ibm.icu.util.ULocale;
import com.ibm.icu.util.UResourceBundle;
/**
* @test 1.22 99/09/21
* @bug 4028006 4044013 4096694 4107276 4107570 4112869 4130885
* @summary test TimeZone
* @build TimeZoneTest
*/
public class TimeZoneTest extends TestFmwk
{
static final int millisPerHour = 3600000;
// TODO: We should probably read following data at runtime, so we can update
// the these values every release with necessary data changes.
// Some test case data is current date/tzdata version sensitive and producing errors
// when year/rule are changed.
static final int REFERENCE_YEAR = 2009;
static final String REFERENCE_DATA_VERSION = "2009d";
public static void main(String[] args) throws Exception {
new TimeZoneTest().run(args);
}
/**
* NOTE: As of ICU 2.8, the mapping of 3-letter legacy aliases
* to `real' Olson IDs is under control of the underlying JDK.
* This test may fail on one JDK and pass on another; don't be
* too concerned. Alan
*
* Bug 4130885
* Certain short zone IDs, used since 1.1.x, are incorrect.
*
* The worst of these is:
*
* "CAT" (Central African Time) should be GMT+2:00, but instead returns a
* zone at GMT-1:00. The zone at GMT-1:00 should be called EGT, CVT, EGST,
* or AZOST, depending on which zone is meant, but in no case is it CAT.
*
* Other wrong zone IDs:
*
* ECT (European Central Time) GMT+1:00: ECT is Ecuador Time,
* GMT-5:00. European Central time is abbreviated CEST.
*
* SST (Solomon Island Time) GMT+11:00. SST is actually Samoa Standard Time,
* GMT-11:00. Solomon Island time is SBT.
*
* NST (New Zealand Time) GMT+12:00. NST is the abbreviation for
* Newfoundland Standard Time, GMT-3:30. New Zealanders use NZST.
*
* AST (Alaska Standard Time) GMT-9:00. [This has already been noted in
* another bug.] It should be "AKST". AST is Atlantic Standard Time,
* GMT-4:00.
*
* PNT (Phoenix Time) GMT-7:00. PNT usually means Pitcairn Time,
* GMT-8:30. There is no standard abbreviation for Phoenix time, as distinct
* from MST with daylight savings.
*
* In addition to these problems, a number of zones are FAKE. That is, they
* don't match what people use in the real world.
*
* FAKE zones:
*
* EET (should be EEST)
* ART (should be EEST)
* MET (should be IRST)
* NET (should be AMST)
* PLT (should be PKT)
* BST (should be BDT)
* VST (should be ICT)
* CTT (should be CST) +
* ACT (should be CST) +
* AET (should be EST) +
* MIT (should be WST) +
* IET (should be EST) +
* PRT (should be AST) +
* CNT (should be NST)
* AGT (should be ARST)
* BET (should be EST) +
*
* + A zone with the correct name already exists and means something
* else. E.g., EST usually indicates the US Eastern zone, so it cannot be
* used for Brazil (BET).
*/
public void TestShortZoneIDs() throws Exception {
// This test case is tzdata version sensitive.
boolean isNonReferenceTzdataVersion = false;
String tzdataVer = TimeZone.getTZDataVersion();
if (!tzdataVer.equals(REFERENCE_DATA_VERSION)) {
// Note: We want to display a warning message here if
// REFERENCE_DATA_VERSION is out of date - so we
// do not forget to update the value before GA.
isNonReferenceTzdataVersion = true;
logln("Warning: Active tzdata version (" + tzdataVer +
") does not match the reference tzdata version ("
+ REFERENCE_DATA_VERSION + ") for this test case data.");
}
// Note: If the default TimeZone type is JDK, some time zones
// may differ from the test data below. For example, "MST" on
// IBM JRE is an alias of "America/Denver" for supporting Java 1.1
// backward compatibility, while Olson tzdata (and ICU) treat it
// as -7hour fixed offset/no DST.
boolean isJDKTimeZone = (TimeZone.getDefaultTimeZoneType() == TimeZone.TIMEZONE_JDK);
if (isJDKTimeZone) {
logln("Warning: Using JDK TimeZone. Some test cases may not return expected results.");
}
// Note: useDaylightTime returns true if DST is observed
// in the time zone in the current calendar year. The test
// data is valid for the date after the reference year below.
// If system clock is before the year, some test cases may
// fail.
GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("Etc/GMT"));
cal.set(REFERENCE_YEAR, Calendar.JANUARY, 2); // day 2 in GMT
boolean isDateBeforeReferenceYear = System.currentTimeMillis() < cal.getTimeInMillis();
if (isDateBeforeReferenceYear) {
logln("Warning: Past time is set to the system clock. Some test cases may not return expected results.");
}
ZoneDescriptor[] REFERENCE_LIST = {
new ZoneDescriptor("MIT", -660, false),
new ZoneDescriptor("HST", -600, false),
new ZoneDescriptor("AST", -540, true),
new ZoneDescriptor("PST", -480, true),
new ZoneDescriptor("PNT", -420, false),
new ZoneDescriptor("MST", -420, false),// updated Aug 2003 aliu
new ZoneDescriptor("CST", -360, true),
new ZoneDescriptor("IET", -300, true), // updated Feb 2006 srl
new ZoneDescriptor("EST", -300, false),// updated Aug 2003 aliu
new ZoneDescriptor("PRT", -240, false),
new ZoneDescriptor("CNT", -210, true),
new ZoneDescriptor("AGT", -180, true), // updated by tzdata 2007k
new ZoneDescriptor("BET", -180, true),
new ZoneDescriptor("GMT", 0, false),
new ZoneDescriptor("UTC", 0, false),
new ZoneDescriptor("ECT", 60, true),
new ZoneDescriptor("MET", 60, true),
new ZoneDescriptor("CAT", 120, false), // Africa/Harare
new ZoneDescriptor("ART", 120, true),
new ZoneDescriptor("EET", 120, true),
new ZoneDescriptor("EAT", 180, false),
new ZoneDescriptor("NET", 240, true),
new ZoneDescriptor("PLT", 300, false), // updated by tzdata 2008c - no DST after 2008
new ZoneDescriptor("IST", 330, false),
new ZoneDescriptor("BST", 360, false),
new ZoneDescriptor("VST", 420, false),
new ZoneDescriptor("CTT", 480, false), // updated Oct 2003 aliu
new ZoneDescriptor("JST", 540, false),
new ZoneDescriptor("ACT", 570, false), // updated Oct 2003 aliu
new ZoneDescriptor("AET", 600, true),
new ZoneDescriptor("SST", 660, false),
new ZoneDescriptor("NST", 720, true), // Pacific/Auckland
new ZoneDescriptor("Etc/Unknown", 0, false),
new ZoneDescriptor("SystemV/AST4ADT", -240, true),
new ZoneDescriptor("SystemV/EST5EDT", -300, true),
new ZoneDescriptor("SystemV/CST6CDT", -360, true),
new ZoneDescriptor("SystemV/MST7MDT", -420, true),
new ZoneDescriptor("SystemV/PST8PDT", -480, true),
new ZoneDescriptor("SystemV/YST9YDT", -540, true),
new ZoneDescriptor("SystemV/AST4", -240, false),
new ZoneDescriptor("SystemV/EST5", -300, false),
new ZoneDescriptor("SystemV/CST6", -360, false),
new ZoneDescriptor("SystemV/MST7", -420, false),
new ZoneDescriptor("SystemV/PST8", -480, false),
new ZoneDescriptor("SystemV/YST9", -540, false),
new ZoneDescriptor("SystemV/HST10", -600, false),
};
for (int i=0; i<REFERENCE_LIST.length; ++i) {
ZoneDescriptor referenceZone = REFERENCE_LIST[i];
ZoneDescriptor currentZone = new ZoneDescriptor(TimeZone.getTimeZone(referenceZone.getID()));
if (referenceZone.equals(currentZone)) {
logln("ok " + referenceZone);
}
else {
if (isNonReferenceTzdataVersion
|| isJDKTimeZone || isDateBeforeReferenceYear) {
logln("Warning: Expected " + referenceZone +
"; got " + currentZone);
} else {
errln("Fail: Expected " + referenceZone +
"; got " + currentZone);
}
}
}
}
/**
* A descriptor for a zone; used to regress the short zone IDs.
*/
static class ZoneDescriptor {
String id;
int offset; // In minutes
boolean daylight;
ZoneDescriptor(TimeZone zone) {
this.id = zone.getID();
this.offset = zone.getRawOffset() / 60000;
this.daylight = zone.useDaylightTime();
}
ZoneDescriptor(String id, int offset, boolean daylight) {
this.id = id;
this.offset = offset;
this.daylight = daylight;
}
public String getID() { return id; }
public boolean equals(Object o) {
ZoneDescriptor that = (ZoneDescriptor)o;
return that != null &&
id.equals(that.id) &&
offset == that.offset &&
daylight == that.daylight;
}
public String toString() {
int min = offset;
char sign = '+';
if (min < 0) { sign = '-'; min = -min; }
return "Zone[\"" + id + "\", GMT" + sign + (min/60) + ':' +
(min%60<10?"0":"") + (min%60) + ", " +
(daylight ? "Daylight" : "Standard") + "]";
}
public static int compare(Object o1, Object o2) {
ZoneDescriptor i1 = (ZoneDescriptor)o1;
ZoneDescriptor i2 = (ZoneDescriptor)o2;
if (i1.offset > i2.offset) return 1;
if (i1.offset < i2.offset) return -1;
if (i1.daylight && !i2.daylight) return 1;
if (!i1.daylight && i2.daylight) return -1;
return i1.id.compareTo(i2.id);
}
}
/**
* As part of the VM fix (see CCC approved RFE 4028006, bug
* 4044013), TimeZone.getTimeZone() has been modified to recognize
* generic IDs of the form GMT[+-]hh:mm, GMT[+-]hhmm, and
* GMT[+-]hh. Test this behavior here.
*
* Bug 4044013
*/
public void TestCustomParse() {
String[] DATA = {
// ID offset(sec) output ID
"GMT", "0", "GMT", // system ID
"GMT-YOUR.AD.HERE", "0", "GMT",
"GMT0", "0", "GMT0", // system ID
"GMT+0", "0", "GMT+0", // system ID
"GMT+1", "3600", "GMT+01:00",
"GMT-0030", "-1800", "GMT-00:30",
"GMT+15:99", "0", "GMT",
"GMT+", "0", "GMT",
"GMT-", "0", "GMT",
"GMT+0:", "0", "GMT",
"GMT-:", "0", "GMT",
"GMT+0010", "600", "GMT+00:10",
"GMT-10", "-36000", "GMT-10:00",
"GMT+30", "0", "GMT",
"GMT-3:30", "-12600", "GMT-03:30",
"GMT-230", "-9000", "GMT-02:30",
"GMT+05:13:05", "18785", "GMT+05:13:05",
"GMT-71023", "-25823", "GMT-07:10:23",
"GMT+01:23:45:67", "0", "GMT",
"GMT+01:234", "0", "GMT",
"GMT-2:31:123", "0", "GMT",
"GMT+3:75", "0", "GMT",
"GMT-01010101", "0", "GMT",
};
for (int i = 0; i < DATA.length; i += 3) {
String id = DATA[i];
int offset = Integer.parseInt(DATA[i+1]);
String expId = DATA[i+2];
TimeZone zone = TimeZone.getTimeZone(id);
String gotID = zone.getID();
int gotOffset = zone.getRawOffset()/1000;
logln(id + " -> " + gotID + " " + gotOffset);
if (offset != gotOffset) {
errln("FAIL: Unexpected offset for " + id + " - returned:" + gotOffset + " expected:" + offset);
}
if (!expId.equals(gotID)) {
if (TimeZone.getDefaultTimeZoneType() != TimeZone.TIMEZONE_ICU) {
logln("ID for " + id + " - returned:" + gotID + " expected:" + expId);
} else {
errln("FAIL: Unexpected ID for " + id + " - returned:" + gotID + " expected:" + expId);
}
}
}
}
/**
* Test the basic functionality of the getDisplayName() API.
*
* Bug 4112869
* Bug 4028006
*
* See also API change request A41.
*
* 4/21/98 - make smarter, so the test works if the ext resources
* are present or not.
*/
public void TestDisplayName() {
TimeZone zone = TimeZone.getTimeZone("PST");
String name = zone.getDisplayName(Locale.ENGLISH);
logln("PST->" + name);
// dlf - we now (3.4.1) return generic time
if (!name.equals("Pacific Time"))
errln("Fail: Expected \"Pacific Time\", got " + name +
" for " + zone);
//*****************************************************************
// THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES
// THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES
// THE FOLLOWING LINES MUST BE UPDATED IF THE LOCALE DATA CHANGES
//*****************************************************************
// todo: check to see whether we can test for all of pst, pdt, pt
Object[] DATA = {
Boolean.FALSE, new Integer(TimeZone.SHORT), "PST",
Boolean.TRUE, new Integer(TimeZone.SHORT), "PDT",
Boolean.FALSE, new Integer(TimeZone.LONG), "Pacific Standard Time",
Boolean.TRUE, new Integer(TimeZone.LONG), "Pacific Daylight Time",
};
for (int i=0; i<DATA.length; i+=3) {
name = zone.getDisplayName(((Boolean)DATA[i]).booleanValue(),
((Integer)DATA[i+1]).intValue(),
Locale.ENGLISH);
if (!name.equals(DATA[i+2]))
errln("Fail: Expected " + DATA[i+2] + "; got " + name);
}
// Make sure that we don't display the DST name by constructing a fake
// PST zone that has DST all year long.
// dlf - this test is no longer relevant, we display generic time now
// so the behavior of the timezone doesn't matter
SimpleTimeZone zone2 = new SimpleTimeZone(0, "PST");
zone2.setStartRule(Calendar.JANUARY, 1, 0);
zone2.setEndRule(Calendar.DECEMBER, 31, 86399999);
logln("Modified PST inDaylightTime->" + zone2.inDaylightTime(new Date()));
name = zone2.getDisplayName(Locale.ENGLISH);
logln("Modified PST->" + name);
if (!name.equals("Pacific Time"))
errln("Fail: Expected \"Pacific Time\"");
// Make sure we get the default display format for Locales
// with no display name data.
Locale mt_MT = new Locale("mt", "MT");
name = zone.getDisplayName(mt_MT);
//*****************************************************************
// THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES
// THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES
// THE FOLLOWING LINE MUST BE UPDATED IF THE LOCALE DATA CHANGES
//*****************************************************************
logln("PST(mt_MT)->" + name);
// Now be smart -- check to see if zh resource is even present.
// If not, we expect the en fallback behavior.
// in icu4j 2.1 we know we have the zh_CN locale data, though it's incomplete
// /"DateFormatZoneData",
UResourceBundle enRB = UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME,Locale.ENGLISH);
UResourceBundle mtRB = UResourceBundle.getBundleInstance(ICUResourceBundle.ICU_BASE_NAME, mt_MT);
boolean noZH = enRB == mtRB;
if (noZH) {
logln("Warning: Not testing the mt_MT behavior because resource is absent");
if (!name.equals("Pacific Standard Time"))
errln("Fail: Expected Pacific Standard Time for PST in mt_MT but got ");
}
// dlf - we will use generic time, or if unavailable, GMT for standard time in the zone
// - we now (3.4.1) have localizations for this zone, so change test string
else if(!name.equals("Stati Uniti (Los Angeles)") &&
!name.equals("GMT-08:00") &&
!name.equals("GMT-8:00") &&
!name.equals("GMT-0800") &&
!name.equals("GMT-800")) {
errln("Fail: got '" + name + "', expected GMT-08:00 or something similar\n" +
"************************************************************\n" +
"THE ABOVE FAILURE MAY JUST MEAN THE LOCALE DATA HAS CHANGED\n" +
"************************************************************");
}
// Now try a non-existent zone
zone2 = new SimpleTimeZone(90*60*1000, "xyzzy");
name = zone2.getDisplayName(Locale.ENGLISH);
logln("GMT+90min->" + name);
if (!name.equals("GMT+01:30") &&
!name.equals("GMT+1:30") &&
!name.equals("GMT+0130") &&
!name.equals("GMT+130"))
errln("Fail: Expected GMT+01:30 or something similar");
// cover getDisplayName() - null arg
ULocale save = ULocale.getDefault();
ULocale.setDefault(ULocale.US);
name = zone2.getDisplayName();
logln("GMT+90min->" + name + "for default display locale");
if (!name.equals("GMT+01:30") &&
!name.equals("GMT+1:30") &&
!name.equals("GMT+0130") &&
!name.equals("GMT+130"))
errln("Fail: Expected GMT+01:30 or something similar");
ULocale.setDefault(save);
}
public void TestDisplayName2() {
Date now = new Date();
String[] timezones = {"America/Chicago", "Europe/Moscow", "Europe/Rome", "Asia/Shanghai", "WET" };
String[] locales = {"en", "fr", "de", "ja", "zh_TW", "zh_Hans" };
for (int j = 0; j < locales.length; ++j) {
ULocale locale = new ULocale(locales[j]);
for (int i = 0; i < timezones.length; ++i) {
TimeZone tz = TimeZone.getTimeZone(timezones[i]);
String displayName0 = tz.getDisplayName(locale); // doesn't work???
SimpleDateFormat dt = new SimpleDateFormat("vvvv", locale);
dt.setTimeZone(tz);
String displayName1 = dt.format(now); // date value _does_ matter if we fallback to GMT
logln(locale.getDisplayName() + ", " + tz.getID() + ": " + displayName0);
if (!displayName1.equals(displayName0)) {
errln(locale.getDisplayName() + ", " + tz.getID() +
": expected " + displayName1 + " but got: " + displayName0);
}
}
}
}
public void TestGenericAPI() {
String id = "NewGMT";
int offset = 12345;
SimpleTimeZone zone = new SimpleTimeZone(offset, id);
if (zone.useDaylightTime()) errln("FAIL: useDaylightTime should return false");
TimeZone zoneclone = (TimeZone)zone.clone();
if (!zoneclone.equals(zone)) errln("FAIL: clone or operator== failed");
zoneclone.setID("abc");
if (zoneclone.equals(zone)) errln("FAIL: clone or operator!= failed");
// delete zoneclone;
zoneclone = (TimeZone)zone.clone();
if (!zoneclone.equals(zone)) errln("FAIL: clone or operator== failed");
zoneclone.setRawOffset(45678);
if (zoneclone.equals(zone)) errln("FAIL: clone or operator!= failed");
// C++ only
/*
SimpleTimeZone copy(*zone);
if (!(copy == *zone)) errln("FAIL: copy constructor or operator== failed");
copy = *(SimpleTimeZone*)zoneclone;
if (!(copy == *zoneclone)) errln("FAIL: assignment operator or operator== failed");
*/
TimeZone saveDefault = TimeZone.getDefault();
TimeZone.setDefault(zone);
TimeZone defaultzone = TimeZone.getDefault();
if (defaultzone == zone) errln("FAIL: Default object is identical, not clone");
if (!defaultzone.equals(zone)) errln("FAIL: Default object is not equal");
TimeZone.setDefault(saveDefault);
// delete defaultzone;
// delete zoneclone;
// // ICU 2.6 Coverage
// logln(zone.toString());
// logln(zone.getDisplayName());
// SimpleTimeZoneAdapter stza = new SimpleTimeZoneAdapter((SimpleTimeZone) TimeZone.getTimeZone("GMT"));
// stza.setID("Foo");
// if (stza.hasSameRules(java.util.TimeZone.getTimeZone("GMT"))) {
// errln("FAIL: SimpleTimeZoneAdapter.hasSameRules");
// }
// stza.setRawOffset(3000);
// offset = stza.getOffset(GregorianCalendar.BC, 2001, Calendar.DECEMBER,
// 25, Calendar.TUESDAY, 12*60*60*1000);
// if (offset != 3000) {
// errln("FAIL: SimpleTimeZoneAdapter.getOffset");
// }
// SimpleTimeZoneAdapter dup = (SimpleTimeZoneAdapter) stza.clone();
// if (stza.hashCode() != dup.hashCode()) {
// errln("FAIL: SimpleTimeZoneAdapter.hashCode");
// }
// if (!stza.equals(dup)) {
// errln("FAIL: SimpleTimeZoneAdapter.equals");
// }
// logln(stza.toString());
String tzver = TimeZone.getTZDataVersion();
if (tzver.length() != 5 /* 4 digits + 1 letter */) {
errln("FAIL: getTZDataVersion returned " + tzver);
} else {
logln("PASS: tzdata version: " + tzver);
}
}
public void TestRuleAPI()
{
// ErrorCode status = ZERO_ERROR;
int offset = (int)(60*60*1000*1.75); // Pick a weird offset
SimpleTimeZone zone = new SimpleTimeZone(offset, "TestZone");
if (zone.useDaylightTime()) errln("FAIL: useDaylightTime should return false");
// Establish our expected transition times. Do this with a non-DST
// calendar with the (above) declared local offset.
GregorianCalendar gc = new GregorianCalendar(zone);
gc.clear();
gc.set(1990, Calendar.MARCH, 1);
long marchOneStd = gc.getTime().getTime(); // Local Std time midnight
gc.clear();
gc.set(1990, Calendar.JULY, 1);
long julyOneStd = gc.getTime().getTime(); // Local Std time midnight
// Starting and ending hours, WALL TIME
int startHour = (int)(2.25 * 3600000);
int endHour = (int)(3.5 * 3600000);
zone.setStartRule(Calendar.MARCH, 1, 0, startHour);
zone.setEndRule (Calendar.JULY, 1, 0, endHour);
gc = new GregorianCalendar(zone);
// if (failure(status, "new GregorianCalendar")) return;
long marchOne = marchOneStd + startHour;
long julyOne = julyOneStd + endHour - 3600000; // Adjust from wall to Std time
long expMarchOne = 636251400000L;
if (marchOne != expMarchOne)
{
errln("FAIL: Expected start computed as " + marchOne +
" = " + new Date(marchOne));
logln(" Should be " + expMarchOne +
" = " + new Date(expMarchOne));
}
long expJulyOne = 646793100000L;
if (julyOne != expJulyOne)
{
errln("FAIL: Expected start computed as " + julyOne +
" = " + new Date(julyOne));
logln(" Should be " + expJulyOne +
" = " + new Date(expJulyOne));
}
Calendar cal1 = Calendar.getInstance();
cal1.set(1990, Calendar.JANUARY, 1);
Calendar cal2 = Calendar.getInstance();
cal2.set(1990, Calendar.JUNE, 1);
_testUsingBinarySearch(zone, cal1.getTimeInMillis(),
cal2.getTimeInMillis(), marchOne);
cal1.set(1990, Calendar.JUNE, 1);
cal2.set(1990, Calendar.DECEMBER, 31);
_testUsingBinarySearch(zone, cal1.getTimeInMillis(),
cal2.getTimeInMillis(), julyOne);
if (zone.inDaylightTime(new Date(marchOne - 1000)) ||
!zone.inDaylightTime(new Date(marchOne)))
errln("FAIL: Start rule broken");
if (!zone.inDaylightTime(new Date(julyOne - 1000)) ||
zone.inDaylightTime(new Date(julyOne)))
errln("FAIL: End rule broken");
zone.setStartYear(1991);
if (zone.inDaylightTime(new Date(marchOne)) ||
zone.inDaylightTime(new Date(julyOne - 1000)))
errln("FAIL: Start year broken");
// failure(status, "TestRuleAPI");
// delete gc;
// delete zone;
}
void _testUsingBinarySearch(SimpleTimeZone tz, long min, long max, long expectedBoundary)
{
// ErrorCode status = ZERO_ERROR;
boolean startsInDST = tz.inDaylightTime(new Date(min));
// if (failure(status, "SimpleTimeZone::inDaylightTime")) return;
if (tz.inDaylightTime(new Date(max)) == startsInDST) {
logln("Error: inDaylightTime(" + new Date(max) + ") != " + (!startsInDST));
return;
}
// if (failure(status, "SimpleTimeZone::inDaylightTime")) return;
while ((max - min) > INTERVAL) {
long mid = (min + max) / 2;
if (tz.inDaylightTime(new Date(mid)) == startsInDST) {
min = mid;
}
else {
max = mid;
}
// if (failure(status, "SimpleTimeZone::inDaylightTime")) return;
}
logln("Binary Search Before: " + min + " = " + new Date(min));
logln("Binary Search After: " + max + " = " + new Date(max));
long mindelta = expectedBoundary - min;
// not used long maxdelta = max - expectedBoundary;
if (mindelta >= 0 &&
mindelta <= INTERVAL &&
mindelta >= 0 &&
mindelta <= INTERVAL)
logln("PASS: Expected bdry: " + expectedBoundary + " = " + new Date(expectedBoundary));
else
errln("FAIL: Expected bdry: " + expectedBoundary + " = " + new Date(expectedBoundary));
}
static final int INTERVAL = 100;
// Bug 006; verify the offset for a specific zone.
public void TestPRTOffset()
{
TimeZone tz = TimeZone.getTimeZone( "PRT" );
if( tz == null ) {
errln( "FAIL: TimeZone(PRT) is null" );
}
else{
if (tz.getRawOffset() != (-4*millisPerHour))
warnln("FAIL: Offset for PRT should be -4, got " +
tz.getRawOffset() / (double)millisPerHour);
}
}
// Test various calls
public void TestVariousAPI518()
{
TimeZone time_zone = TimeZone.getTimeZone("PST");
Calendar cal = Calendar.getInstance();
cal.set(1997, Calendar.APRIL, 30);
Date d = cal.getTime();
logln("The timezone is " + time_zone.getID());
if (time_zone.inDaylightTime(d) != true)
errln("FAIL: inDaylightTime returned false");
if (time_zone.useDaylightTime() != true)
errln("FAIL: useDaylightTime returned false");
if (time_zone.getRawOffset() != -8*millisPerHour)
errln( "FAIL: getRawOffset returned wrong value");
GregorianCalendar gc = new GregorianCalendar();
gc.setTime(d);
if (time_zone.getOffset(GregorianCalendar.AD, gc.get(GregorianCalendar.YEAR), gc.get(GregorianCalendar.MONTH),
gc.get(GregorianCalendar.DAY_OF_MONTH),
gc.get(GregorianCalendar.DAY_OF_WEEK), 0)
!= -7*millisPerHour)
errln("FAIL: getOffset returned wrong value");
}
// Test getAvailableID API
public void TestGetAvailableIDs913()
{
StringBuffer buf = new StringBuffer("TimeZone.getAvailableIDs() = { ");
String[] s = TimeZone.getAvailableIDs();
for (int i=0; i<s.length; ++i)
{
if (i > 0) buf.append(", ");
buf.append(s[i]);
}
buf.append(" };");
logln(buf.toString());
buf.setLength(0);
buf.append("TimeZone.getAvailableIDs(GMT+02:00) = { ");
s = TimeZone.getAvailableIDs(+2 * 60 * 60 * 1000);
for (int i=0; i<s.length; ++i)
{
if (i > 0) buf.append(", ");
buf.append(s[i]);
}
buf.append(" };");
logln(buf.toString());
TimeZone tz = TimeZone.getTimeZone("PST");
if (tz != null)
logln("getTimeZone(PST) = " + tz.getID());
else
errln("FAIL: getTimeZone(PST) = null");
tz = TimeZone.getTimeZone("America/Los_Angeles");
if (tz != null)
logln("getTimeZone(America/Los_Angeles) = " + tz.getID());
else
errln("FAIL: getTimeZone(PST) = null");
// Bug 4096694
tz = TimeZone.getTimeZone("NON_EXISTENT");
if (tz == null)
errln("FAIL: getTimeZone(NON_EXISTENT) = null");
else if (!tz.getID().equals("GMT"))
errln("FAIL: getTimeZone(NON_EXISTENT) = " + tz.getID());
}
/**
* Bug 4107276
*/
public void TestDSTSavings() {
// It might be better to find a way to integrate this test into the main TimeZone
// tests above, but I don't have time to figure out how to do this (or if it's
// even really a good idea). Let's consider that a future. --rtg 1/27/98
SimpleTimeZone tz = new SimpleTimeZone(-5 * millisPerHour, "dstSavingsTest",
Calendar.MARCH, 1, 0, 0, Calendar.SEPTEMBER, 1, 0, 0,
(int)(0.5 * millisPerHour));
if (tz.getRawOffset() != -5 * millisPerHour)
errln("Got back a raw offset of " + (tz.getRawOffset() / millisPerHour) +
" hours instead of -5 hours.");
if (!tz.useDaylightTime())
errln("Test time zone should use DST but claims it doesn't.");
if (tz.getDSTSavings() != 0.5 * millisPerHour)
errln("Set DST offset to 0.5 hour, but got back " + (tz.getDSTSavings() /
millisPerHour) + " hours instead.");
int offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.JANUARY, 1,
Calendar.THURSDAY, 10 * millisPerHour);
if (offset != -5 * millisPerHour)
errln("The offset for 10 AM, 1/1/98 should have been -5 hours, but we got "
+ (offset / millisPerHour) + " hours.");
offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.JUNE, 1, Calendar.MONDAY,
10 * millisPerHour);
if (offset != -4.5 * millisPerHour)
errln("The offset for 10 AM, 6/1/98 should have been -4.5 hours, but we got "
+ (offset / millisPerHour) + " hours.");
tz.setDSTSavings(millisPerHour);
offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.JANUARY, 1,
Calendar.THURSDAY, 10 * millisPerHour);
if (offset != -5 * millisPerHour)
errln("The offset for 10 AM, 1/1/98 should have been -5 hours, but we got "
+ (offset / millisPerHour) + " hours.");
offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.JUNE, 1, Calendar.MONDAY,
10 * millisPerHour);
if (offset != -4 * millisPerHour)
errln("The offset for 10 AM, 6/1/98 (with a 1-hour DST offset) should have been -4 hours, but we got "
+ (offset / millisPerHour) + " hours.");
}
/**
* Bug 4107570
*/
public void TestAlternateRules() {
// Like TestDSTSavings, this test should probably be integrated somehow with the main
// test at the top of this class, but I didn't have time to figure out how to do that.
// --rtg 1/28/98
SimpleTimeZone tz = new SimpleTimeZone(-5 * millisPerHour, "alternateRuleTest");
// test the day-of-month API
tz.setStartRule(Calendar.MARCH, 10, 12 * millisPerHour);
tz.setEndRule(Calendar.OCTOBER, 20, 12 * millisPerHour);
int offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.MARCH, 5,
Calendar.THURSDAY, 10 * millisPerHour);
if (offset != -5 * millisPerHour)
errln("The offset for 10AM, 3/5/98 should have been -5 hours, but we got "
+ (offset / millisPerHour) + " hours.");
offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.MARCH, 15,
Calendar.SUNDAY, 10 * millisPerHour);
if (offset != -4 * millisPerHour)
errln("The offset for 10AM, 3/15/98 should have been -4 hours, but we got "
+ (offset / millisPerHour) + " hours.");
offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.OCTOBER, 15,
Calendar.THURSDAY, 10 * millisPerHour);
if (offset != -4 * millisPerHour)
errln("The offset for 10AM, 10/15/98 should have been -4 hours, but we got "
+ (offset / millisPerHour) + " hours.");
offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.OCTOBER, 25,
Calendar.SUNDAY, 10 * millisPerHour);
if (offset != -5 * millisPerHour)
errln("The offset for 10AM, 10/25/98 should have been -5 hours, but we got "
+ (offset / millisPerHour) + " hours.");
// test the day-of-week-after-day-in-month API
tz.setStartRule(Calendar.MARCH, 10, Calendar.FRIDAY, 12 * millisPerHour, true);
tz.setEndRule(Calendar.OCTOBER, 20, Calendar.FRIDAY, 12 * millisPerHour, false);
offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.MARCH, 11,
Calendar.WEDNESDAY, 10 * millisPerHour);
if (offset != -5 * millisPerHour)
errln("The offset for 10AM, 3/11/98 should have been -5 hours, but we got "
+ (offset / millisPerHour) + " hours.");
offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.MARCH, 14,
Calendar.SATURDAY, 10 * millisPerHour);
if (offset != -4 * millisPerHour)
errln("The offset for 10AM, 3/14/98 should have been -4 hours, but we got "
+ (offset / millisPerHour) + " hours.");
offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.OCTOBER, 15,
Calendar.THURSDAY, 10 * millisPerHour);
if (offset != -4 * millisPerHour)
errln("The offset for 10AM, 10/15/98 should have been -4 hours, but we got "
+ (offset / millisPerHour) + " hours.");
offset = tz.getOffset(GregorianCalendar.AD, 1998, Calendar.OCTOBER, 17,
Calendar.SATURDAY, 10 * millisPerHour);
if (offset != -5 * millisPerHour)
errln("The offset for 10AM, 10/17/98 should have been -5 hours, but we got "
+ (offset / millisPerHour) + " hours.");
}
public void TestEquivalencyGroups() {
String id = "America/Los_Angeles";
int n = TimeZone.countEquivalentIDs(id);
if (n < 2) {
errln("FAIL: countEquivalentIDs(" + id + ") returned " + n +
", expected >= 2");
}
for (int i=0; i<n; ++i) {
String s = TimeZone.getEquivalentID(id, i);
if (s.length() == 0) {
errln("FAIL: getEquivalentID(" + id + ", " + i +
") returned \"" + s + "\", expected valid ID");
} else {
logln("" + i + ":" + s);
}
}
// JB#5480 - equivalent IDs should not be empty within range
String[] ids = TimeZone.getAvailableIDs();
for (int i = 0; i < ids.length; i++) {
int nEquiv = TimeZone.countEquivalentIDs(ids[i]);
// Each equivalent ID must not be empty
for (int j = 0; j < nEquiv; j++) {
String equivID = TimeZone.getEquivalentID(ids[i], j);
if (equivID.length() == 0) {
errln("FAIL: getEquivalentID(" + ids[i] + ", " + i +
") returned \"" + equivID + "\", expected valid ID");
}
}
// equivalent ID out of range must be empty
String outOfRangeID = TimeZone.getEquivalentID(ids[i], nEquiv);
if (outOfRangeID.length() != 0) {
errln("FAIL: getEquivalentID(" + ids[i] + ", " + i +
") returned \"" + outOfRangeID + "\", expected empty string");
}
}
}
public void TestCountries() {
// Make sure America/Los_Angeles is in the "US" group, and
// Asia/Tokyo isn't. Vice versa for the "JP" group.
String[] s = TimeZone.getAvailableIDs("US");
boolean la = false, tokyo = false;
String laZone = "America/Los_Angeles", tokyoZone = "Asia/Tokyo";
for (int i=0; i<s.length; ++i) {
if (s[i].equals(laZone)) {
la = true;
}
if (s[i].equals(tokyoZone)) {
tokyo = true;
}
}
if (!la ) {
errln("FAIL: " + laZone + " in US = " + la);
}
if (tokyo) {
errln("FAIL: " + tokyoZone + " in US = " + tokyo);
}
s = TimeZone.getAvailableIDs("JP");
la = false; tokyo = false;
for (int i=0; i<s.length; ++i) {
if (s[i].equals(laZone)) {
la = true;
}
if (s[i].equals(tokyoZone)) {
tokyo = true;
}
}
if (la) {
errln("FAIL: " + laZone + " in JP = " + la);
}
if (!tokyo) {
errln("FAIL: " + tokyoZone + " in JP = " + tokyo);
}
}
public void TestFractionalDST() {
String tzName = "Australia/Lord_Howe"; // 30 min offset
java.util.TimeZone tz_java = java.util.TimeZone.getTimeZone(tzName);
int dst_java = 0;
try {
// hack so test compiles and runs in both JDK 1.3 and JDK 1.4
final Object[] args = new Object[0];
final Class[] argtypes = new Class[0];
java.lang.reflect.Method m = tz_java.getClass().getMethod("getDSTSavings", argtypes);
dst_java = ((Integer) m.invoke(tz_java, args)).intValue();
if (dst_java <= 0 || dst_java >= 3600000) { // didn't get the fractional time zone we wanted
errln("didn't get fractional time zone!");
}
} catch (NoSuchMethodException e) {
// see JDKTimeZone for the reason for this code
dst_java = 3600000;
} catch (IllegalAccessException e) {
// see JDKTimeZone for the reason for this code
errln(e.getMessage());
dst_java = 3600000;
} catch (InvocationTargetException e) {
// see JDKTimeZone for the reason for this code
errln(e.getMessage());
dst_java = 3600000;
} catch (SecurityException e) {
warnln(e.getMessage());
return;
}
com.ibm.icu.util.TimeZone tz_icu = com.ibm.icu.util.TimeZone.getTimeZone(tzName);
int dst_icu = tz_icu.getDSTSavings();
if (dst_java != dst_icu) {
warnln("java reports dst savings of " + dst_java +
" but icu reports " + dst_icu +
" for tz " + tz_icu.getID());
} else {
logln("both java and icu report dst savings of " + dst_java + " for tz " + tz_icu.getID());
}
}
public void TestGetOffsetDate() {
Calendar cal = Calendar.getInstance();
cal.set(1997, Calendar.JANUARY, 30);
long date = cal.getTimeInMillis();
TimeZone tz_icu = TimeZone.getTimeZone("America/Los_Angeles");
int offset = tz_icu.getOffset(date);
if (offset != -28800000) {
errln("expected offset -28800000, got: " + offset);
}
cal.set(1997, Calendar.JULY, 30);
date = cal.getTimeInMillis();
offset = tz_icu.getOffset(date);
if (offset != -25200000) {
errln("expected offset -25200000, got: " + offset);
}
}
// jb4484
public void TestSimpleTimeZoneSerialization()
{
SimpleTimeZone stz0 = new SimpleTimeZone(32400000, "MyTimeZone");
SimpleTimeZone stz1 = new SimpleTimeZone(32400000, "Asia/Tokyo");
SimpleTimeZone stz2 = new SimpleTimeZone(32400000, "Asia/Tokyo");
stz2.setRawOffset(0);
SimpleTimeZone stz3 = new SimpleTimeZone(32400000, "Asia/Tokyo");
stz3.setStartYear(100);
SimpleTimeZone stz4 = new SimpleTimeZone(32400000, "Asia/Tokyo");
stz4.setStartYear(1000);
stz4.setDSTSavings(1800000);
stz4.setStartRule(3, 4, 180000);
stz4.setEndRule(6, 3, 4, 360000);
SimpleTimeZone stz5 = new SimpleTimeZone(32400000, "Asia/Tokyo");
stz5.setStartRule(2, 3, 4, 360000);
stz5.setEndRule(6, 3, 4, 360000);
SimpleTimeZone[] stzs = { stz0, stz1, stz2, stz3, stz4, stz5, };
for (int i = 0; i < stzs.length; ++i) {
SimpleTimeZone stz = stzs[i];
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(stz);
oos.close();
byte[] bytes = baos.toByteArray();
logln("id: " + stz.getID() + " length: " + bytes.length);
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
SimpleTimeZone stzDeserialized = (SimpleTimeZone)ois.readObject();
ois.close();
assertEquals("time zones", stz, stzDeserialized);
}
catch (ClassCastException cce) {
cce.printStackTrace();
errln("could not deserialize SimpleTimeZone");
}
catch (IOException ioe) {
errln(ioe.getMessage());
}
catch (ClassNotFoundException cnfe) {
errln(cnfe.getMessage());
}
}
}
// jb4175
/* Generated by org.unicode.cldr.tool.CountItems */
private static final String[] timeZoneTestNames = {
"America/Argentina/Buenos_Aires", "America/Buenos_Aires",
"America/Argentina/Catamarca", "America/Catamarca",
"America/Argentina/Cordoba", "America/Cordoba",
"America/Argentina/Jujuy", "America/Jujuy",
"America/Argentina/Mendoza", "America/Mendoza",
"America/Atka", "America/Adak",
"America/Ensenada", "America/Tijuana",
"America/Fort_Wayne", "America/Indianapolis",
"America/Indiana/Indianapolis", "America/Indianapolis",
"America/Kentucky/Louisville", "America/Louisville",
"America/Knox_IN", "America/Indiana/Knox",
"America/Porto_Acre", "America/Rio_Branco",
"America/Rosario", "America/Cordoba",
"America/Virgin", "America/St_Thomas",
"Asia/Ashkhabad", "Asia/Ashgabat",
"Asia/Chungking", "Asia/Chongqing",
"Asia/Dacca", "Asia/Dhaka",
"Asia/Istanbul", "Europe/Istanbul",
"Asia/Macao", "Asia/Macau",
"Asia/Tel_Aviv", "Asia/Jerusalem",
"Asia/Thimbu", "Asia/Thimphu",
"Asia/Ujung_Pandang", "Asia/Makassar",
"Asia/Ulan_Bator", "Asia/Ulaanbaatar",
"Australia/ACT", "Australia/Sydney",
"Australia/Canberra", "Australia/Sydney",
"Australia/LHI", "Australia/Lord_Howe",
"Australia/NSW", "Australia/Sydney",
"Australia/North", "Australia/Darwin",
"Australia/Queensland", "Australia/Brisbane",
"Australia/South", "Australia/Adelaide",
"Australia/Tasmania", "Australia/Hobart",
"Australia/Victoria", "Australia/Melbourne",
"Australia/West", "Australia/Perth",
"Australia/Yancowinna", "Australia/Broken_Hill",
"Brazil/Acre", "America/Rio_Branco",
"Brazil/DeNoronha", "America/Noronha",
"Brazil/East", "America/Sao_Paulo",
"Brazil/West", "America/Manaus",
"CST6CDT", "America/Chicago",
"Canada/Atlantic", "America/Halifax",
"Canada/Central", "America/Winnipeg",
"Canada/East-Saskatchewan", "America/Regina",
"Canada/Eastern", "America/Toronto",
"Canada/Mountain", "America/Edmonton",
"Canada/Newfoundland", "America/St_Johns",
"Canada/Pacific", "America/Vancouver",
"Canada/Saskatchewan", "America/Regina",
"Canada/Yukon", "America/Whitehorse",
"Chile/Continental", "America/Santiago",
"Chile/EasterIsland", "Pacific/Easter",
"Cuba", "America/Havana",
"EST", "America/Indianapolis",
"EST5EDT", "America/New_York",
"Egypt", "Africa/Cairo",
"Eire", "Europe/Dublin",
"Etc/GMT+0", "Etc/GMT",
"Etc/GMT-0", "Etc/GMT",
"Etc/GMT0", "Etc/GMT",
"Etc/Greenwich", "Etc/GMT",
"Etc/UCT", "Etc/GMT",
"Etc/UTC", "Etc/GMT",
"Etc/Universal", "Etc/GMT",
"Etc/Zulu", "Etc/GMT",
"Europe/Nicosia", "Asia/Nicosia",
"Europe/Tiraspol", "Europe/Chisinau",
"GB", "Europe/London",
"GB-Eire", "Europe/London",
"GMT", "Etc/GMT",
"GMT+0", "Etc/GMT",
"GMT-0", "Etc/GMT",
"GMT0", "Etc/GMT",
"Greenwich", "Etc/GMT",
"HST", "Pacific/Honolulu",
"Hongkong", "Asia/Hong_Kong",
"Iceland", "Atlantic/Reykjavik",
"Iran", "Asia/Tehran",
"Israel", "Asia/Jerusalem",
"Jamaica", "America/Jamaica",
"Japan", "Asia/Tokyo",
"Kwajalein", "Pacific/Kwajalein",
"Libya", "Africa/Tripoli",
"MST", "America/Phoenix",
"MST7MDT", "America/Denver",
"Mexico/BajaNorte", "America/Tijuana",
"Mexico/BajaSur", "America/Mazatlan",
"Mexico/General", "America/Mexico_City",
"NZ", "Pacific/Auckland",
"NZ-CHAT", "Pacific/Chatham",
"Navajo", "America/Shiprock", /* fixed from Mark's original */
"PRC", "Asia/Shanghai",
"PST8PDT", "America/Los_Angeles",
"Pacific/Samoa", "Pacific/Pago_Pago",
"Poland", "Europe/Warsaw",
"Portugal", "Europe/Lisbon",
"ROC", "Asia/Taipei",
"ROK", "Asia/Seoul",
"Singapore", "Asia/Singapore",
"SystemV/AST4", "America/Puerto_Rico",
"SystemV/AST4ADT", "America/Halifax",
"SystemV/CST6", "America/Regina",
"SystemV/CST6CDT", "America/Chicago",
"SystemV/EST5", "America/Indianapolis",
"SystemV/EST5EDT", "America/New_York",
"SystemV/HST10", "Pacific/Honolulu",
"SystemV/MST7", "America/Phoenix",
"SystemV/MST7MDT", "America/Denver",
"SystemV/PST8", "Pacific/Pitcairn",
"SystemV/PST8PDT", "America/Los_Angeles",
"SystemV/YST9", "Pacific/Gambier",
"SystemV/YST9YDT", "America/Anchorage",
"Turkey", "Europe/Istanbul",
"UCT", "Etc/GMT",
"US/Alaska", "America/Anchorage",
"US/Aleutian", "America/Adak",
"US/Arizona", "America/Phoenix",
"US/Central", "America/Chicago",
"US/East-Indiana", "America/Indianapolis",
"US/Eastern", "America/New_York",
"US/Hawaii", "Pacific/Honolulu",
"US/Indiana-Starke", "America/Indiana/Knox",
"US/Michigan", "America/Detroit",
"US/Mountain", "America/Denver",
"US/Pacific", "America/Los_Angeles",
"US/Pacific-New", "America/Los_Angeles",
"US/Samoa", "Pacific/Pago_Pago",
"UTC", "Etc/GMT",
"Universal", "Etc/GMT",
"W-SU", "Europe/Moscow",
"Zulu", "Etc/GMT",
};
public void TestOddTimeZoneNames() {
for (int i = 0; i < timeZoneTestNames.length; i += 2) {
String funkyName = timeZoneTestNames[i];
String correctName = timeZoneTestNames[i+1];
TimeZone ftz = TimeZone.getTimeZone(funkyName);
TimeZone ctz = TimeZone.getTimeZone(correctName);
String fdn = ftz.getDisplayName();
long fro = ftz.getRawOffset();
long fds = ftz.getDSTSavings();
boolean fdy = ftz.useDaylightTime();
String cdn = ctz.getDisplayName();
long cro = ctz.getRawOffset();
long cds = ctz.getDSTSavings();
boolean cdy = ctz.useDaylightTime();
if (!fdn.equals(cdn)) {
logln("display name (" + funkyName + ", " + correctName + ") expected: " + cdn + " but got: " + fdn);
} else if (fro != cro) {
logln("offset (" + funkyName + ", " + correctName + ") expected: " + cro + " but got: " + fro);
} else if (fds != cds) {
logln("daylight (" + funkyName + ", " + correctName + ") expected: " + cds + " but got: " + fds);
} else if (fdy != cdy) {
logln("uses daylight (" + funkyName + ", " + correctName + ") expected: " + cdy + " but got: " + fdy);
} else {
// no error, assume we're referencing the same internal java object
}
}
}
public void TestCoverage(){
class StubTimeZone extends TimeZone{
/**
* For serialization
*/
private static final long serialVersionUID = 8658654217433379343L;
public int getOffset(int era, int year, int month, int day, int dayOfWeek, int milliseconds) {return 0;}
public void setRawOffset(int offsetMillis) {}
public int getRawOffset() {return 0;}
public boolean useDaylightTime() {return false;}
public boolean inDaylightTime(Date date) {return false;}
}
StubTimeZone stub = new StubTimeZone();
StubTimeZone stub2 = (StubTimeZone) stub.clone();
if (stub.getDSTSavings() != 0){
errln("TimeZone.getDSTSavings() should return 0");
}
if (!stub.hasSameRules(stub2)){
errln("TimeZone.clone() object should hasSameRules");
}
}
public void TestMark(){
String tzid = "America/Argentina/ComodRivadavia";
TimeZone tz = TimeZone.getTimeZone(tzid);
int offset = tz.getOffset(new Date().getTime());
logln(tzid + ":\t" + offset);
List list = Arrays.asList(TimeZone.getAvailableIDs());
if(!list.contains(tzid)){
errln("Could create the time zone but it is not in getAvailableIDs");
}
}
public void TestZoneMeta() {
java.util.TimeZone save = java.util.TimeZone.getDefault();
java.util.TimeZone newZone = java.util.TimeZone.getTimeZone("GMT-08:00");
com.ibm.icu.util.TimeZone.setDefault(null);
java.util.TimeZone.setDefault(newZone);
SimpleTimeZone zone = new SimpleTimeZone(0, "GMT");
com.ibm.icu.util.TimeZone defaultZone = com.ibm.icu.util.TimeZone.getDefault();
if(defaultZone==null){
errln("TimeZone.getDefault() failed for GMT-08:00");
}
if(zone==null){
errln("SimpleTimeZone(0, GMT-08:00) failed for GMT-08:00");
}
//reset
java.util.TimeZone.setDefault(save);
}
// Copied from the protected constant in TimeZone.
private static final int MILLIS_PER_HOUR = 60*60*1000;
// Test that a transition at the end of February is handled correctly.
public void TestFebruary() {
// Time zone with daylight savings time from the first Sunday in November
// to the last Sunday in February.
// Similar to the new rule for Brazil (Sao Paulo) in tzdata2006n.
//
// Note: In tzdata2007h, the rule had changed, so no actual zones uses
// lastSun in Feb anymore.
SimpleTimeZone tz1 = new SimpleTimeZone(
-3 * MILLIS_PER_HOUR, // raw offset: 3h before (west of) GMT
"nov-feb",
Calendar.NOVEMBER, 1, Calendar.SUNDAY, // start: November, first, Sunday
0, // midnight wall time
Calendar.FEBRUARY, -1, Calendar.SUNDAY, // end: February, last, Sunday
0); // midnight wall time
// Now hardcode the same rules as for Brazil in tzdata 2006n, so that
// we cover the intended code even when in the future zoneinfo hardcodes
// these transition dates.
SimpleTimeZone tz2= new SimpleTimeZone(
-3 * MILLIS_PER_HOUR, // raw offset: 3h before (west of) GMT
"nov-feb2",
Calendar.NOVEMBER, 1, -Calendar.SUNDAY, // start: November, 1 or after, Sunday
0, // midnight wall time
Calendar.FEBRUARY, -29, -Calendar.SUNDAY,// end: February, 29 or before, Sunday
0); // midnight wall time
// Gregorian calendar with the UTC time zone for getting sample test date/times.
GregorianCalendar gc = new GregorianCalendar(TimeZone.getTimeZone("Etc/GMT"));
// "Unable to create the UTC calendar: %s"
int[] data = {
// UTC time (6 fields) followed by
// expected time zone offset in hours after GMT (negative=before GMT).
// int year, month, day, hour, minute, second, offsetHours
2006, Calendar.NOVEMBER, 5, 02, 59, 59, -3,
2006, Calendar.NOVEMBER, 5, 03, 00, 00, -2,
2007, Calendar.FEBRUARY, 25, 01, 59, 59, -2,
2007, Calendar.FEBRUARY, 25, 02, 00, 00, -3,
2007, Calendar.NOVEMBER, 4, 02, 59, 59, -3,
2007, Calendar.NOVEMBER, 4, 03, 00, 00, -2,
2008, Calendar.FEBRUARY, 24, 01, 59, 59, -2,
2008, Calendar.FEBRUARY, 24, 02, 00, 00, -3,
2008, Calendar.NOVEMBER, 2, 02, 59, 59, -3,
2008, Calendar.NOVEMBER, 2, 03, 00, 00, -2,
2009, Calendar.FEBRUARY, 22, 01, 59, 59, -2,
2009, Calendar.FEBRUARY, 22, 02, 00, 00, -3,
2009, Calendar.NOVEMBER, 1, 02, 59, 59, -3,
2009, Calendar.NOVEMBER, 1, 03, 00, 00, -2,
2010, Calendar.FEBRUARY, 28, 01, 59, 59, -2,
2010, Calendar.FEBRUARY, 28, 02, 00, 00, -3
};
TimeZone timezones[] = { tz1, tz2 };
TimeZone tz;
Date dt;
int t, i, raw, dst;
int[] offsets = new int[2]; // raw = offsets[0], dst = offsets[1]
for (t = 0; t < timezones.length; ++t) {
tz = timezones[t];
for (i = 0; i < data.length; i+=7) {
gc.set(data[i], data[i+1], data[i+2],
data[i+3], data[i+4], data[i+5]);
dt = gc.getTime();
tz.getOffset(dt.getTime(), false, offsets);
raw = offsets[0];
dst = offsets[1];
if ((raw + dst) != data[i+6] * MILLIS_PER_HOUR) {
errln("test case " + t + "." + (i/7) + ": " +
"tz.getOffset(" + data[i] + "-" + (data[i+1] + 1) + "-" + data[i+2] + " " +
data[i+3] + ":" + data[i+4] + ":" + data[i+5] +
") returns " + raw + "+" + dst + " != " + data[i+6] * MILLIS_PER_HOUR);
}
}
}
}
public void TestCanonicalID() {
// Some canonical IDs in CLDR are defined as "Link"
// in Olson tzdata.
final String[][] excluded1 = {
{"America/Shiprock", "America/Denver"}, // America/Shiprock is defined as a Link to America/Denver in tzdata
{"America/Marigot", "America/Guadeloupe"},
{"America/St_Barthelemy", "America/Guadeloupe"},
{"Antarctica/South_Pole", "Antarctica/McMurdo"},
{"Atlantic/Jan_Mayen", "Europe/Oslo"},
{"Arctic/Longyearbyen", "Europe/Oslo"},
{"Europe/Guernsey", "Europe/London"},
{"Europe/Isle_of_Man", "Europe/London"},
{"Europe/Jersey", "Europe/London"},
{"Europe/Ljubljana", "Europe/Belgrade"},
{"Europe/Podgorica", "Europe/Belgrade"},
{"Europe/Sarajevo", "Europe/Belgrade"},
{"Europe/Skopje", "Europe/Belgrade"},
{"Europe/Zagreb", "Europe/Belgrade"},
{"Europe/Bratislava", "Europe/Prague"},
{"Europe/Mariehamn", "Europe/Helsinki"},
{"Europe/San_Marino", "Europe/Rome"},
{"Europe/Vatican", "Europe/Rome"},
};
// Following IDs are aliases of Etc/GMT in CLDR,
// but Olson tzdata has 3 independent definitions
// for Etc/GMT, Etc/UTC, Etc/UCT.
// Until we merge them into one equivalent group
// in zoneinfo.res, we exclude them in the test
// below.
final String[] excluded2 = {
"Etc/UCT", "UCT",
"Etc/UTC", "UTC",
"Etc/Universal", "Universal",
"Etc/Zulu", "Zulu",
};
// Walk through equivalency groups
String[] ids = TimeZone.getAvailableIDs();
for (int i = 0; i < ids.length; i++) {
int nEquiv = TimeZone.countEquivalentIDs(ids[i]);
if (nEquiv == 0) {
continue;
}
String canonicalID = null;
boolean bFoundCanonical = false;
// Make sure getCanonicalID returns the exact same result
// for all entries within a same equivalency group with some
// exceptions listed in exluded1.
// Also, one of them must be canonical id.
for (int j = 0; j < nEquiv; j++) {
String tmp = TimeZone.getEquivalentID(ids[i], j);
String tmpCanonical = TimeZone.getCanonicalID(tmp);
if (tmpCanonical == null) {
errln("FAIL: getCanonicalID(\"" + tmp + "\") returned null");
continue;
}
// Some exceptional cases
for (int k = 0; k < excluded1.length; k++) {
if (tmpCanonical.equals(excluded1[k][0])) {
tmpCanonical = excluded1[k][1];
}
}
if (j == 0) {
canonicalID = tmpCanonical;
} else if (!canonicalID.equals(tmpCanonical)) {
errln("FAIL: getCanonicalID(\"" + tmp + "\") returned " + tmpCanonical + " expected:" + canonicalID);
}
if (canonicalID.equals(tmp)) {
bFoundCanonical = true;
}
}
// At least one ID in an equvalency group must match the
// canonicalID
if (!bFoundCanonical) {
// test exclusion because of differences between Olson tzdata and CLDR
boolean isExcluded = false;
for (int k = 0; k < excluded1.length; k++) {
if (ids[i].equals(excluded2[k])) {
isExcluded = true;
break;
}
}
if (isExcluded) {
continue;
}
errln("FAIL: No timezone ids match the canonical ID " + canonicalID);
}
}
// Testing some special cases
final String[][] data = {
{"GMT-03", "GMT-03:00", null},
{"GMT+4", "GMT+04:00", null},
{"GMT-055", "GMT-00:55", null},
{"GMT+430", "GMT+04:30", null},
{"GMT-12:15", "GMT-12:15", null},
{"GMT-091015", "GMT-09:10:15", null},
{"GMT+1:90", null, null},
{"America/Argentina/Buenos_Aires", "America/Buenos_Aires", "true"},
{"bogus", null, null},
{"", null, null},
{null, null, null},
};
boolean[] isSystemID = new boolean[1];
for (int i = 0; i < data.length; i++) {
String canonical = TimeZone.getCanonicalID(data[i][0], isSystemID);
if (canonical != null && !canonical.equals(data[i][1])
|| canonical == null && data[i][1] != null) {
errln("FAIL: getCanonicalID(\"" + data[i][0] + "\") returned " + canonical
+ " - expected: " + data[i][1]);
}
if ("true".equalsIgnoreCase(data[i][2]) != isSystemID[0]) {
errln("FAIL: getCanonicalID(\"" + data[i][0] + "\") set " + isSystemID[0]
+ " to isSystemID");
}
}
}
public void TestSetDefault() {
java.util.TimeZone save = java.util.TimeZone.getDefault();
/*
* America/Caracs (Venezuela) changed the base offset from -4:00 to
* -4:30 on Dec 9, 2007.
*/
TimeZone icuCaracas = TimeZone.getTimeZone("America/Caracas", TimeZone.TIMEZONE_ICU);
java.util.TimeZone jdkCaracas = java.util.TimeZone.getTimeZone("America/Caracas");
// Set JDK America/Caracas as the default
java.util.TimeZone.setDefault(jdkCaracas);
java.util.Calendar jdkCal = java.util.Calendar.getInstance();
jdkCal.clear();
jdkCal.set(2007, java.util.Calendar.JANUARY, 1);
int rawOffset = jdkCal.get(java.util.Calendar.ZONE_OFFSET);
int dstSavings = jdkCal.get(java.util.Calendar.DST_OFFSET);
int[] offsets = new int[2];
icuCaracas.getOffset(jdkCal.getTime().getTime()/*jdkCal.getTimeInMillis()*/, false, offsets);
boolean isTimeZoneSynchronized = true;
if (rawOffset != offsets[0] || dstSavings != offsets[1]) {
// JDK time zone rule is out of sync...
logln("Rule for JDK America/Caracas is not same with ICU. Skipping the rest.");
isTimeZoneSynchronized = false;
}
if (isTimeZoneSynchronized) {
// If JDK America/Caracas uses the same rule with ICU,
// the following code should work well.
TimeZone.setDefault(icuCaracas);
// Create a new JDK calendar instance again.
// This calendar should reflect the new default
// set by ICU TimeZone#setDefault.
jdkCal = java.util.Calendar.getInstance();
jdkCal.clear();
jdkCal.set(2007, java.util.Calendar.JANUARY, 1);
rawOffset = jdkCal.get(java.util.Calendar.ZONE_OFFSET);
dstSavings = jdkCal.get(java.util.Calendar.DST_OFFSET);
if (rawOffset != offsets[0] || dstSavings != offsets[1]) {
errln("ERROR: Got offset [raw:" + rawOffset + "/dst:" + dstSavings
+ "] Expected [raw:" + offsets[0] + "/dst:" + offsets[1] + "]");
}
}
// Restore the original JDK time zone
java.util.TimeZone.setDefault(save);
}
/*
* Test Display Names, choosing zones and lcoales where there are multiple
* meta-zones defined.
*/
public void TestDisplayNamesMeta() {
final Integer TZSHORT = new Integer(TimeZone.SHORT);
final Integer TZLONG = new Integer(TimeZone.LONG);
final Object[][] zoneDisplayTestData = {
// zone id locale summer format expected display name
{"Europe/London", "en", Boolean.FALSE, TZSHORT, "GMT"},
{"Europe/London", "en", Boolean.FALSE, TZLONG, "Greenwich Mean Time"},
{"Europe/London", "en", Boolean.TRUE, TZSHORT, "GMT+01:00" /*"BST"*/},
{"Europe/London", "en", Boolean.TRUE, TZLONG, "British Summer Time"},
{"America/Anchorage", "en", Boolean.FALSE, TZSHORT, "AKST"},
{"America/Anchorage", "en", Boolean.FALSE, TZLONG, "Alaska Standard Time"},
{"America/Anchorage", "en", Boolean.TRUE, TZSHORT, "AKDT"},
{"America/Anchorage", "en", Boolean.TRUE, TZLONG, "Alaska Daylight Time"},
// Southern Hemisphere, all data from meta:Australia_Western
{"Australia/Perth", "en", Boolean.FALSE, TZSHORT, "GMT+08:00"/*"AWST"*/},
{"Australia/Perth", "en", Boolean.FALSE, TZLONG, "Australian Western Standard Time"},
{"Australia/Perth", "en", Boolean.TRUE, TZSHORT, "GMT+09:00"/*"AWDT"*/},
{"Australia/Perth", "en", Boolean.TRUE, TZLONG, "Australian Western Daylight Time"},
{"America/Sao_Paulo", "en", Boolean.FALSE, TZSHORT, "GMT-03:00"/*"BRT"*/},
{"America/Sao_Paulo", "en", Boolean.FALSE, TZLONG, "Brasilia Time"},
{"America/Sao_Paulo", "en", Boolean.TRUE, TZSHORT, "GMT-02:00"/*"BRST"*/},
{"America/Sao_Paulo", "en", Boolean.TRUE, TZLONG, "Brasilia Summer Time"},
// No Summer Time, but had it before 1983.
{"Pacific/Honolulu", "en", Boolean.FALSE, TZSHORT, "HST"},
{"Pacific/Honolulu", "en", Boolean.FALSE, TZLONG, "Hawaii-Aleutian Standard Time"},
{"Pacific/Honolulu", "en", Boolean.TRUE, TZSHORT, "HST"},
{"Pacific/Honolulu", "en", Boolean.TRUE, TZLONG, "Hawaii-Aleutian Standard Time"},
// Northern, has Summer, not commonly used.
{"Europe/Helsinki", "en", Boolean.FALSE, TZSHORT, "GMT+02:00"/*"EET"*/},
{"Europe/Helsinki", "en", Boolean.FALSE, TZLONG, "Eastern European Time"},
{"Europe/Helsinki", "en", Boolean.TRUE, TZSHORT, "GMT+03:00"/*"EEST"*/},
{"Europe/Helsinki", "en", Boolean.TRUE, TZLONG, "Eastern European Summer Time"},
// Repeating the test data for DST. The test data below trigger the problem reported
// by Ticket#6644
{"Europe/London", "en", Boolean.TRUE, TZSHORT, "GMT+01:00" /*"BST"*/},
{"Europe/London", "en", Boolean.TRUE, TZLONG, "British Summer Time"},
};
boolean isReferenceYear = true;
GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("Etc/GMT"));
if (cal.get(Calendar.YEAR) != REFERENCE_YEAR) {
isReferenceYear = false;
}
boolean sawAnError = false;
for (int testNum = 0; testNum < zoneDisplayTestData.length; testNum++) {
ULocale locale = new ULocale((String)zoneDisplayTestData[testNum][1]);
TimeZone zone = TimeZone.getTimeZone((String)zoneDisplayTestData[testNum][0]);
String displayName = zone.getDisplayName(((Boolean)zoneDisplayTestData[testNum][2]).booleanValue(),
((Integer)zoneDisplayTestData[testNum][3]).intValue());
if (!displayName.equals(zoneDisplayTestData[testNum][4])) {
if (isReferenceYear) {
sawAnError = true;
errln("Incorrect time zone display name. zone = "
+ zoneDisplayTestData[testNum][0] + ",\n"
+ " locale = " + locale
+ ", style = " + (zoneDisplayTestData[testNum][3] == TZSHORT ? "SHORT" : "LONG")
+ ", Summertime = " + zoneDisplayTestData[testNum][2] + "\n"
+ " Expected " + zoneDisplayTestData[testNum][4]
+ ", Got " + displayName);
} else {
logln("Incorrect time zone display name. zone = "
+ zoneDisplayTestData[testNum][0] + ",\n"
+ " locale = " + locale
+ ", style = " + (zoneDisplayTestData[testNum][3] == TZSHORT ? "SHORT" : "LONG")
+ ", Summertime = " + zoneDisplayTestData[testNum][2] + "\n"
+ " Expected " + zoneDisplayTestData[testNum][4]
+ ", Got " + displayName);
}
}
}
if (sawAnError) {
logln("Note: Errors could be the result of changes to zoneStrings locale data");
}
}
}
//eof