Fixed issue with Date years. Formatted files to match TeaVM conventions. TimeZone tests now pass in browser. CalendarTests still failing.

This commit is contained in:
Steve Hannah 2015-04-10 16:49:38 -07:00
parent 2bc1a99d53
commit 7a5b76f3dc
8 changed files with 507 additions and 236 deletions

View File

@ -94,7 +94,7 @@ public class DateNativeGenerator implements Generator, DependencyPlugin {
} }
private void generateBuildNumericUTC(GeneratorContext context, SourceWriter writer) throws IOException { private void generateBuildNumericUTC(GeneratorContext context, SourceWriter writer) throws IOException {
writer.append("return Date.UTC(").append(context.getParameterName(1)); writer.append("Date.UTC(").append(context.getParameterName(1));
for (int i = 2; i <= 6; ++i) { for (int i = 2; i <= 6; ++i) {
writer.append(',').ws().append(context.getParameterName(i)); writer.append(',').ws().append(context.getParameterName(i));
} }

View File

@ -15,6 +15,7 @@
*/ */
package org.teavm.classlib.java.util; package org.teavm.classlib.java.util;
import java.util.TimeZone;
import org.teavm.classlib.java.lang.TComparable; import org.teavm.classlib.java.lang.TComparable;
import org.teavm.classlib.java.lang.TSystem; import org.teavm.classlib.java.lang.TSystem;
import org.teavm.dependency.PluggableDependency; import org.teavm.dependency.PluggableDependency;
@ -51,6 +52,7 @@ public class TDate implements TComparable<TDate> {
@Deprecated @Deprecated
public TDate(int year, int month, int date, int hrs, int min, int sec) { public TDate(int year, int month, int date, int hrs, int min, int sec) {
this((long)buildNumericTime(year, month, date, hrs, min, sec)); this((long)buildNumericTime(year, month, date, hrs, min, sec));
setFullYear(value, year+1900);
} }
public TDate(String s) { public TDate(String s) {
@ -78,12 +80,12 @@ public class TDate implements TComparable<TDate> {
@Deprecated @Deprecated
public int getYear() { public int getYear() {
return getFullYear(value); return getFullYear(value)-1900;
} }
@Deprecated @Deprecated
public void setYear(int year) { public void setYear(int year) {
this.value = (long)setFullYear(value, year); this.value = (long)setFullYear(value, year+1900);
} }
@Deprecated @Deprecated
@ -193,7 +195,8 @@ public class TDate implements TComparable<TDate> {
@Deprecated @Deprecated
public int getTimezoneOffset() { public int getTimezoneOffset() {
return getTimezoneOffset(value); //return getTimezoneOffset(value);
return -TimeZone.getDefault().getOffset(value) / (1000*60);
} }
@GeneratedBy(DateNativeGenerator.class) @GeneratedBy(DateNativeGenerator.class)

View File

@ -18,6 +18,7 @@
package org.teavm.classlib.java.util; package org.teavm.classlib.java.util;
public class TGregorianCalendar extends TCalendar { public class TGregorianCalendar extends TCalendar {
public static final int BC = 0; public static final int BC = 0;
public static final int AD = 1; public static final int AD = 1;
@ -84,7 +85,7 @@ public class TGregorianCalendar extends TCalendar {
setTimeInMillis(System.currentTimeMillis()); setTimeInMillis(System.currentTimeMillis());
} }
public TGregorianCalendar(TTimeZone zone, TLocale locale){ public TGregorianCalendar(TTimeZone zone, TLocale locale) {
this(locale); this(locale);
setTimeZone(zone); setTimeZone(zone);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 shannah. * Copyright 2015 Steve Hannah.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -31,15 +31,6 @@ package org.teavm.classlib.java.util;
*/ */
public class TSimpleTimeZone extends TTimeZone { public class TSimpleTimeZone extends TTimeZone {
// BEGIN android-removed
// private static com.ibm.icu.util.TimeZone getICUTimeZone(final String name){
// return AccessController.doPrivileged(new PrivilegedAction<com.ibm.icu.util.TimeZone>(){
// public com.ibm.icu.util.TimeZone run() {
// return com.ibm.icu.util.TimeZone.getTimeZone(name);
// }
// });
// }
// END android-removed
private int rawOffset; private int rawOffset;
@ -127,16 +118,7 @@ public class TSimpleTimeZone extends TTimeZone {
public TSimpleTimeZone(int offset, final String name) { public TSimpleTimeZone(int offset, final String name) {
setID(name); setID(name);
rawOffset = offset; rawOffset = offset;
// BEGIN android-removed
// icuTZ = getICUTimeZone(name);
// if (icuTZ instanceof com.ibm.icu.util.SimpleTimeZone) {
// isSimple = true;
// icuTZ.setRawOffset(offset);
// } else {
// isSimple = false;
// }
// useDaylight = icuTZ.useDaylightTime();
// END android-removed
} }
/** /**
@ -260,20 +242,6 @@ public class TSimpleTimeZone extends TTimeZone {
public TSimpleTimeZone(int offset, String name, int startMonth, public TSimpleTimeZone(int offset, String name, int startMonth,
int startDay, int startDayOfWeek, int startTime, int endMonth, int startDay, int startDayOfWeek, int startTime, int endMonth,
int endDay, int endDayOfWeek, int endTime, int daylightSavings) { int endDay, int endDayOfWeek, int endTime, int daylightSavings) {
// BEGIN android-changed
// icuTZ = getICUTimeZone(name);
// if (icuTZ instanceof com.ibm.icu.util.SimpleTimeZone) {
// isSimple = true;
// com.ibm.icu.util.SimpleTimeZone tz = (com.ibm.icu.util.SimpleTimeZone)icuTZ;
// tz.setRawOffset(offset);
// tz.setStartRule(startMonth, startDay, startDayOfWeek, startTime);
// tz.setEndRule(endMonth, endDay, endDayOfWeek, endTime);
// tz.setDSTSavings(daylightSavings);
// } else {
// isSimple = false;
// }
// setID(name);
// rawOffset = offset;
this(offset, name); this(offset, name);
// END android-changed // END android-changed
if (daylightSavings <= 0) { if (daylightSavings <= 0) {
@ -283,10 +251,6 @@ public class TSimpleTimeZone extends TTimeZone {
setStartRule(startMonth, startDay, startDayOfWeek, startTime); setStartRule(startMonth, startDay, startDayOfWeek, startTime);
setEndRule(endMonth, endDay, endDayOfWeek, endTime); setEndRule(endMonth, endDay, endDayOfWeek, endTime);
// BEGIN android-removed
// useDaylight = daylightSavings > 0 || icuTZ.useDaylightTime();
// END android-removed
} }
/** /**
@ -747,12 +711,6 @@ public class TSimpleTimeZone extends TTimeZone {
endDayOfWeek = 0; // Initialize this value for hasSameRules() endDayOfWeek = 0; // Initialize this value for hasSameRules()
endTime = time; endTime = time;
setEndMode(); setEndMode();
// BEGIN android-removed
// if (isSimple) {
// ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setEndRule(month,
// dayOfMonth, time);
// }
// END android-removed
} }
/** /**
@ -776,12 +734,6 @@ public class TSimpleTimeZone extends TTimeZone {
endDayOfWeek = dayOfWeek; endDayOfWeek = dayOfWeek;
endTime = time; endTime = time;
setEndMode(); setEndMode();
// BEGIN android-removed
// if (isSimple) {
// ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setEndRule(month, day,
// dayOfWeek, time);
// }
// END android-removed
} }
/** /**
@ -906,12 +858,6 @@ public class TSimpleTimeZone extends TTimeZone {
startDayOfWeek = dayOfWeek; startDayOfWeek = dayOfWeek;
startTime = time; startTime = time;
setStartMode(); setStartMode();
// BEGIN android-removed
// if (isSimple) {
// ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setStartRule(month, day,
// dayOfWeek, time);
// }
// END android-removed
} }
/** /**
@ -937,12 +883,6 @@ public class TSimpleTimeZone extends TTimeZone {
startDayOfWeek = -dayOfWeek; startDayOfWeek = -dayOfWeek;
startTime = time; startTime = time;
setStartMode(); setStartMode();
// BEGIN android-removed
// if (isSimple) {
// ((com.ibm.icu.util.SimpleTimeZone) icuTZ).setStartRule(month, day,
// dayOfWeek, time, after);
// }
// END android-removed
} }
/** /**

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 shannah. * Copyright 2015 Steve Hannah.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -18,45 +18,87 @@ package org.teavm.classlib.java.util;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.List; import java.util.List;
import org.teavm.jso.JSBody; import static org.teavm.classlib.java.util.TGregorianCalendar.AD;
import static org.teavm.classlib.java.util.TGregorianCalendar.BC;
import org.teavm.jso.JS;
import org.teavm.jso.JSConstructor;
import org.teavm.jso.JSObject;
import org.teavm.platform.PlatformTimezone; import org.teavm.platform.PlatformTimezone;
/** /**
* TimeZone represents a time zone offset, and also figures out daylight savings. * TimeZone represents a time zone offset, and also figures out daylight savings.
* Typically, you get a TimeZone using getDefault which creates a TimeZone based on the time zone where the program is running. For example, for a program running in Japan, getDefault creates a TimeZone object based on Japanese Standard Time. * Typically, you get a TimeZone using getDefault which creates a TimeZone based on the
* You can also get a TimeZone using getTimeZone along with a time zone ID. For instance, the time zone ID for the Pacific Standard Time zone is "PST". So, you can get a PST TimeZone object with: * time zone where the program is running. For example, for a program running in Japan,
* getDefault creates a TimeZone object based on Japanese Standard Time.
* You can also get a TimeZone using getTimeZone along with a time zone ID. For instance,
* the time zone ID for the Pacific Standard Time zone is "PST". So, you can get a PST
* TimeZone object with:
* This class is a pure subset of the java.util.TimeZone class in JDK 1.3. * This class is a pure subset of the java.util.TimeZone class in JDK 1.3.
* The only time zone ID that is required to be supported is "GMT". * The only time zone ID that is required to be supported is "GMT".
* Apart from the methods and variables being subset, the semantics of the getTimeZone() method may also be subset: custom IDs such as "GMT-8:00" are not required to be supported. * Apart from the methods and variables being subset, the semantics of the getTimeZone()
* method may also be subset: custom IDs such as "GMT-8:00" are not required to be supported.
* Version: CLDC 1.1 02/01/2002 (Based on JDK 1.3) See Also:Calendar, Date * Version: CLDC 1.1 02/01/2002 (Based on JDK 1.3) See Also:Calendar, Date
*/ */
public abstract class TTimeZone { public abstract class TTimeZone {
public static class GMT extends PlatformTimezone { // For the Local Timezone we need to use the Javascript Date object
// Directly, so here is a makeshift JSO for it. If this object already
@Override // has a JSO or it is deemed adventageous to move this to a more centralized
public String getTimezoneId() { // location, then refactor by all means.
return "GMT"; interface JSDate extends JSObject {
} int getDate();
int getDay();
@Override int getFullYear();
public int getTimezoneOffset(int year, int month, int day, int timeOfDayMillis) { void setFullYear(int year);
return 0; int getHours();
} int getMilliseconds();
int getMinutes();
@Override int getMonth();
public int getTimezoneRawOffset() { int getSeconds();
return 0; double getTime();
} int getTimezoneOffset();
void setDate(int day);
@Override
public boolean isTimezoneDST(long millis) {
return false;
}
} }
interface JSDateFactory extends JSObject {
@JSConstructor("Date")
JSDate createDate();
@JSConstructor("Date")
JSDate createDate(double millis);
@JSConstructor("Date")
JSDate createDate(String dateString);
@JSConstructor("Date")
JSDate createDate(int year, int month, int day, int hours, int minutes, int seconds, int milliseconds);
}
static JSDate createJSDate() {
return ((JSDateFactory)JS.getGlobal()).createDate();
}
static JSDate createJSDate(long millis) {
return ((JSDateFactory)JS.getGlobal()).createDate((double)millis);
}
static JSDate createJSDate(String dateString) {
return ((JSDateFactory)JS.getGlobal()).createDate(dateString);
}
static JSDate createJSDate(int year, int month, int day, int hours, int minutes, int seconds, int milliseconds) {
JSDate out = ((JSDateFactory)JS.getGlobal()).createDate(year, month, day, hours, minutes, seconds, milliseconds);
out.setFullYear(year);
return out;
}
// End Private Javascript Date Object JSO stuff
/**
* A special "local" timezone that represents the timezone of the Javascript
* environment. Javascript doesn't allow us to see the name of this timezone.
* We use this as the default platform timezone and set its ID as "Local".
*/
public static class Local extends PlatformTimezone { public static class Local extends PlatformTimezone {
@Override @Override
@ -69,16 +111,16 @@ public abstract class TTimeZone {
int hours = (int)Math.floor(timeOfDayMillis/1000/60/60); int hours = (int)Math.floor(timeOfDayMillis/1000/60/60);
int minutes = (int)Math.floor(timeOfDayMillis/1000/60)%60; int minutes = (int)Math.floor(timeOfDayMillis/1000/60)%60;
int seconds = (int)Math.floor(timeOfDayMillis/1000)%60; int seconds = (int)Math.floor(timeOfDayMillis/1000)%60;
TDate d = new TDate(year, month, day, hours, minutes, seconds); JSDate d = createJSDate(year, month, day, hours, minutes, seconds, timeOfDayMillis % 1000);
return -TDate.getTimezoneOffset(d.getTime()) * 1000 * 60; return d.getTimezoneOffset();
} }
@Override @Override
public int getTimezoneRawOffset() { public int getTimezoneRawOffset() {
TDate now = new TDate(); JSDate now = createJSDate();
TDate jan = new TDate(now.getYear(), 0, 1); JSDate jan = createJSDate(now.getFullYear(), 0, 1, 0, 0, 0, 0);
TDate jul = new TDate(now.getYear(), 6, 1); JSDate jul = createJSDate(now.getFullYear(), 6, 1, 0, 0, 0, 0);
if (isTimezoneDST(jan.getTime())){ if (isTimezoneDST((long)jan.getTime())) {
return jul.getTimezoneOffset(); return jul.getTimezoneOffset();
} else { } else {
return jan.getTimezoneOffset(); return jan.getTimezoneOffset();
@ -88,20 +130,19 @@ public abstract class TTimeZone {
@Override @Override
public boolean isTimezoneDST(long millis) { public boolean isTimezoneDST(long millis) {
TDate now = new TDate(); JSDate now = createJSDate();
TDate jan = new TDate(now.getYear(), 0, 1); JSDate jan = createJSDate(now.getFullYear(), 0, 1, 0, 0, 0, 0);
TDate jul = new TDate(now.getYear(), 6, 1); JSDate jul = createJSDate(now.getFullYear(), 6, 1, 0, 0, 0, 0);
int maxOffset = Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset()); int maxOffset = Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset());
return new Date(millis).getTimezoneOffset()<maxOffset; return createJSDate(millis).getTimezoneOffset()<maxOffset;
} }
} }
static { static {
PlatformTimezone.addTimezone("GMT", new GMT());
PlatformTimezone.addTimezone("Local", new Local()); PlatformTimezone.addTimezone("Local", new Local());
PlatformTimezone.setPlatformTimezoneId("Local"); PlatformTimezone.setPlatformTimezoneId("Local");
} }
/** /**
* The short display name style, such as {@code PDT}. Requests for this * The short display name style, such as {@code PDT}. Requests for this
* style may yield GMT offsets like {@code GMT-08:00}. * style may yield GMT offsets like {@code GMT-08:00}.
@ -118,9 +159,11 @@ public abstract class TTimeZone {
private static TTimeZone defaultTimeZone; private static TTimeZone defaultTimeZone;
private static TTimeZone systemTimeZone;
private String ID; private String ID;
public TTimeZone(){ public TTimeZone() {
} }
void setID(String id) { void setID(String id) {
@ -130,81 +173,67 @@ public abstract class TTimeZone {
/** /**
* Gets all the available IDs supported. * Gets all the available IDs supported.
*/ */
public static java.lang.String[] getAvailableIDs(){ public static java.lang.String[] getAvailableIDs() {
return PlatformTimezone.getAvailableIds(); return PlatformTimezone.getAvailableIds();
} }
public static java.lang.String[] getAvailableIDs(int rawOffset){ public static java.lang.String[] getAvailableIDs(int rawOffset) {
List<String> out = new ArrayList<String>(); List<String> out = new ArrayList<String>();
for (String id : getAvailableIDs()){ for (String id : getAvailableIDs()) {
PlatformTimezone tz = PlatformTimezone.getTimezone(id); PlatformTimezone tz = PlatformTimezone.getTimezone(id);
if (tz.getTimezoneRawOffset()==rawOffset){ if (tz.getTimezoneRawOffset()==rawOffset) {
out.add(id); out.add(id);
} }
} }
return out.toArray(new String[out.size()]); return out.toArray(new String[out.size()]);
} }
private static String getTimezoneId(){
private static String getTimezoneId() {
return PlatformTimezone.getPlatformTimezoneId(); return PlatformTimezone.getPlatformTimezoneId();
} }
private static int getTimezoneOffset(String name, int year, int month, int day, int timeOfDayMillis) {
private static int getTimezoneOffset(String name, int year, int month, int day, int timeOfDayMillis){
PlatformTimezone tz = PlatformTimezone.getTimezone(name); PlatformTimezone tz = PlatformTimezone.getTimezone(name);
if (tz==null){ if (tz==null) {
throw new RuntimeException("Timezone not found: "+name); throw new RuntimeException("Timezone not found: "+name);
} }
return tz.getTimezoneOffset(year, month, day, timeOfDayMillis); return tz.getTimezoneOffset(year, month, day, timeOfDayMillis);
} }
private static int getTimezoneRawOffset(String name){ private static int getTimezoneRawOffset(String name) {
PlatformTimezone tz = PlatformTimezone.getTimezone(name); PlatformTimezone tz = PlatformTimezone.getTimezone(name);
if (tz==null){ if (tz==null) {
throw new RuntimeException("Timezone not found: "+name); throw new RuntimeException("Timezone not found: "+name);
} }
return tz.getTimezoneRawOffset(); return tz.getTimezoneRawOffset();
} }
private static boolean isTimezoneDST(String name, long millis){ private static boolean isTimezoneDST(String name, long millis) {
PlatformTimezone tz = PlatformTimezone.getTimezone(name); PlatformTimezone tz = PlatformTimezone.getTimezone(name);
if (tz==null){ if (tz==null) {
throw new RuntimeException("Timezone not found: "+name); throw new RuntimeException("Timezone not found: "+name);
} }
return tz.isTimezoneDST(millis); return tz.isTimezoneDST(millis);
} }
private static TTimeZone getSystemTimeZone() {
if (systemTimeZone == null) {
systemTimeZone = getTimeZone(PlatformTimezone.getPlatformTimezoneId());
}
return systemTimeZone;
}
/** /**
* Gets the default TimeZone for this host. The source of the default TimeZone may vary with implementation. * Gets the default TimeZone for this host. The source of the default TimeZone may vary with implementation.
*/ */
public static TTimeZone getDefault(){ public static TTimeZone getDefault() {
if (defaultTimeZone == null) { if (defaultTimeZone == null) {
final String tzone = getTimezoneId(); defaultTimeZone = getSystemTimeZone();
defaultTimeZone = new TTimeZone() {
@Override
public int getOffset(int era, int year, int month, int day, int dayOfWeek, int timeOfDayMillis) {
return getTimezoneOffset(tzone, year, month + 1, day, timeOfDayMillis);
}
@Override
public int getRawOffset() {
return getTimezoneRawOffset(tzone);
}
boolean inDaylightTime(TDate time) {
return isTimezoneDST(tzone, time.getTime());
}
@Override
public boolean useDaylightTime() {
return true;
}
};
defaultTimeZone.ID = tzone;
} }
return defaultTimeZone; return defaultTimeZone;
} }
public void setDefault(TTimeZone tz){ public static void setDefault(TTimeZone tz) {
defaultTimeZone=tz; defaultTimeZone=tz;
} }
@ -212,7 +241,6 @@ public abstract class TTimeZone {
return useDaylightTime() ? 3600000 : 0; return useDaylightTime() ? 3600000 : 0;
} }
boolean inDaylightTime(TDate time) { boolean inDaylightTime(TDate time) {
return false; return false;
} }
@ -220,17 +248,16 @@ public abstract class TTimeZone {
/** /**
* Gets the ID of this time zone. * Gets the ID of this time zone.
*/ */
public java.lang.String getID(){ public java.lang.String getID() {
return ID; return ID;
} }
public int getOffset(long millis){ public int getOffset(long millis) {
Date d = new Date(millis); Date d = new Date(millis);
d.setHours(0); d.setHours(0);
d.setMinutes(0); d.setMinutes(0);
d.setSeconds(0); d.setSeconds(0);
return getOffset(d.getYear()>=-1900?AD:BC, d.getYear()+1900, d.getMonth(), d.getDate(), d.getDay(), (int)(millis-d.getTime()));
return getOffset(0, d.getYear(), d.getMonth(), d.getDate(), d.getDay(), (int)(millis-d.getTime()));
} }
/** /**
@ -243,19 +270,186 @@ public abstract class TTimeZone {
*/ */
public abstract int getRawOffset(); public abstract int getRawOffset();
private static String normalizeGMTOffset(String offset){
int pos;
int len = offset.length();
if (len == 1){
// Should be simple integer of hours 0-9
char c = offset.charAt(0);
if (c < '0' || c > '9') {
return "";
}
return "0"+offset+":00";
} else if (len == 2){
// Should be a 2-digit representation of hours 00-23
char c1 = offset.charAt(0);
if (c1 < '0' || c1 > '2') {
return "";
}
char c2 = offset.charAt(1);
if (c2 < '0' || (c1 == '2' && c2 > '3') || c2 > '9') {
return "";
}
return offset+":00";
} else if (len == 3) {
char c1 = offset.charAt(0);
if (c1 < '0' || c1 > '9') {
return "";
}
char c2 = offset.charAt(1);
if (c2 < '0' || c2 > '5') {
return "";
}
char c3 = offset.charAt(2);
if (c3 < '0' || c3 > '9') {
return "";
}
return "0"+c1+":"+c2+c3;
} else if (len == 4 && offset.charAt(1) == ':'){
char c1 = offset.charAt(0);
if (c1 < '0' || c1 > '9') {
return "";
}
char c2 = offset.charAt(2);
if (c2 < '0' || c2 > '5') {
return "";
}
char c3 = offset.charAt(3);
if (c3 < '0' || c3 > '9') {
return "";
}
return "0"+c1+":"+c2+c3;
} else if (len==4) {
char c1 = offset.charAt(0);
if (c1 < '0' || c1 > '2') {
return "";
}
char c2 = offset.charAt(1);
if (c2 < '0' || (c1 == '2' && c2 > '3') || c2 > '9') {
return "";
}
char c3 = offset.charAt(2);
if (c3 < '0' || c3 > '5') {
return "";
}
char c4 = offset.charAt(3);
if (c4 < '0' || c3 > '9') {
return "";
}
return ""+c1+c2+":"+c3+c4;
} else if (len == 5 && offset.charAt(2) == ':'){
char c1 = offset.charAt(0);
if (c1 < '0' || c1 > '2') {
return "";
}
char c2 = offset.charAt(1);
if (c2 < '0' || (c1 == '2' && c2 > '3') || c2 > '9') {
return "";
}
char c3 = offset.charAt(3);
if (c3 < '0' || c3 > '5') {
return "";
}
char c4 = offset.charAt(4);
if (c4 < '0' || c3 > '9') {
return "";
}
return ""+c1+c2+":"+c3+c4;
} else {
return "";
}
}
/** /**
* Gets the TimeZone for the given ID. * Gets the TimeZone for the given ID.
*/ */
public static TTimeZone getTimeZone(java.lang.String ID){ public static TTimeZone getTimeZone(java.lang.String ID) {
// TODO if (PlatformTimezone.getTimezone(ID)!=null) {
return getDefault(); final TTimeZone tz = new TTimeZone() {
private int dstSavings=-1;
@Override
public int getOffset(int era, int year, int month, int day, int dayOfWeek, int timeOfDayMillis) {
if (era==BC) {
year = -year;
}
return getTimezoneOffset(this.getID(), year, month, day, timeOfDayMillis);
}
@Override
public int getRawOffset() {
return getTimezoneRawOffset(this.getID());
}
@Override
boolean inDaylightTime(TDate time) {
return isTimezoneDST(this.getID(), time.getTime());
}
@Override
public boolean useDaylightTime() {
TDate now = new TDate();
TDate jan = new TDate(now.getYear(), 0, 1);
TDate jul = new TDate(now.getYear(), 6, 1);
return inDaylightTime(jan) || inDaylightTime(jul);
}
@Override
int getDSTSavings() {
if (useDaylightTime()) {
if (dstSavings==-1) {
TDate now = new TDate();
TDate jan = new TDate(now.getYear(), 0, 1);
TDate jul = new TDate(now.getYear(), 6, 1);
dstSavings = Math.abs(this.getOffset(jan.getTime())-this.getOffset(jul.getTime()));
}
return dstSavings;
}
return 0;
}
};
tz.ID = ID;
return tz;
}
if (ID.startsWith("GMT")) {
if (ID.length()==3) {
return GMT;
} else if (ID.charAt(3) == '+' || ID.charAt(3) == '-') {
String strOffset = ID.substring(4);
String normalizedOffset = normalizeGMTOffset(strOffset);
if (normalizedOffset == null || "".equals(normalizedOffset)) {
return GMT;
}
int hours = Integer.parseInt(normalizedOffset.substring(0,2));
int minutes = Integer.parseInt(normalizedOffset.substring(3));
int offset = hours * 60 * 60 * 1000 + minutes * 60 * 1000;
if (ID.charAt(3) == '-') {
offset = -offset;
}
return new TSimpleTimeZone(offset, "GMT"+ID.charAt(3)+normalizedOffset);
}
}
return GMT;
} }
/** /**
* Queries if this time zone uses Daylight Savings Time. * Queries if this time zone uses Daylight Savings Time.
*/ */
public abstract boolean useDaylightTime(); public abstract boolean useDaylightTime();
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 Alexey Andreev. * Copyright 2015 Steve Hannah.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -24,41 +24,101 @@ import java.util.Set;
* @author shannah * @author shannah
*/ */
public abstract class PlatformTimezone { public abstract class PlatformTimezone {
/**
* The default timezone ID.
*/
private static String platformTimezoneId; private static String platformTimezoneId;
/**
* Map of registered timezones. Maps IDs to TimeZones.
*/
private static Map<String, PlatformTimezone> timezones; private static Map<String, PlatformTimezone> timezones;
/**
* Returns timezone map, lazily initialized.
* @return
*/
private static Map<String, PlatformTimezone> timezones(){ private static Map<String, PlatformTimezone> timezones(){
if (timezones==null){ if (timezones==null){
timezones = new HashMap<String, PlatformTimezone>(); timezones = new HashMap<String, PlatformTimezone>();
} }
return timezones; return timezones;
} }
public static PlatformTimezone getTimezone(String id){
/**
* Gets a timezone with the specified ID.
* @param id The ID of the timezone to retrieve.
* @return The TimeZone or null if none exists with that name.
*/
public static PlatformTimezone getTimezone(String id) {
return timezones().get(id); return timezones().get(id);
} }
public static void addTimezone(String id, PlatformTimezone tz){ /**
* Adds a TimeZone.
* @param id The ID of the TimeZone.
* @param tz The TimeZone to add.
*/
public static void addTimezone(String id, PlatformTimezone tz) {
timezones().put(id, tz); timezones().put(id, tz);
} }
public static String[] getAvailableIds(){ /**
* Gets a list of the available platform TimeZone IDs.
* @return
*/
public static String[] getAvailableIds() {
Set<String> keys = timezones().keySet(); Set<String> keys = timezones().keySet();
return keys.toArray(new String[keys.size()]); return keys.toArray(new String[keys.size()]);
} }
public static void setPlatformTimezoneId(String id){ /**
* Sets the local TimeZone ID of the platform. This will be used as the
* "default" TimeZone.
* @param id The ID of the platform timezone.
*/
public static void setPlatformTimezoneId(String id) {
platformTimezoneId=id; platformTimezoneId=id;
} }
public static String getPlatformTimezoneId(){ /**
* Gets the local TimeZone ID of the platform. This will be used as the
* "default" TimeZone.
* @return The default TimeZone ID.
*/
public static String getPlatformTimezoneId() {
return platformTimezoneId; return platformTimezoneId;
} }
/**
* Gets the ID of the TimeZone. E.g. "EST", or "America/Toronto"
* @return The TimeZone ID
*/
public abstract String getTimezoneId(); public abstract String getTimezoneId();
/**
* Gets the timezone offset at the given date. This will include any DST
* offset.
* @param year The year at which the calculation is made. For BC dates, use negatives.
* @param month The month. (0-11)
* @param day The day of the month (1-31).
* @param timeOfDayMillis The time of the day in milliseconds.
* @return The offset in milliseconds from GMT time.
*/
public abstract int getTimezoneOffset(int year, int month, int day, int timeOfDayMillis); public abstract int getTimezoneOffset(int year, int month, int day, int timeOfDayMillis);
/**
* Gets the raw offset of the TimeZone. This does not include any DST offsets.
* @return The raw offset of the timezone.
*/
public abstract int getTimezoneRawOffset(); public abstract int getTimezoneRawOffset();
public abstract boolean isTimezoneDST(long millis);
/**
* Checks if the timezone is observing daylight savings time at the provided
* date.
* @param millis The unix timestamp in milliseconds.
* @return True if the timezone is observing DST at the given date.
*/
public abstract boolean isTimezoneDST(long millis);
} }

View File

@ -30,7 +30,7 @@ import org.teavm.platform.PlatformTimezone;
public class CalendarTest extends junit.framework.TestCase { public class CalendarTest extends junit.framework.TestCase {
static { static {
if (PlatformTimezone.getTimezone("EST")==null){ if (PlatformTimezone.getTimezone("EST")==null) {
PlatformTimezone.addTimezone("EST", new TimeZoneTest.EST()); PlatformTimezone.addTimezone("EST", new TimeZoneTest.EST());
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 shannah. * Copyright 2015 Steve Hannah.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -21,10 +21,10 @@ import java.util.Date;
import java.util.GregorianCalendar; import java.util.GregorianCalendar;
import java.util.List; import java.util.List;
import static org.junit.Assert.*; import static org.junit.Assert.*;
import java.util.Locale;
import java.util.SimpleTimeZone; import java.util.SimpleTimeZone;
import java.util.TimeZone; import java.util.TimeZone;
import org.junit.Test; import org.junit.Test;
import org.teavm.classlib.java.util.TTimeZone.JSDate;
import org.teavm.platform.PlatformTimezone; import org.teavm.platform.PlatformTimezone;
/** /**
@ -59,12 +59,120 @@ public class TimeZoneTest {
} }
static class AsiaShanghai extends PlatformTimezone {
@Override
public String getTimezoneId() {
return "Asia/Shanghai";
}
@Override
public int getTimezoneOffset(int year, int month, int day, int timeOfDayMillis) {
return ONE_HOUR*8;
}
@Override
public int getTimezoneRawOffset() {
return ONE_HOUR*8;
}
@Override
public boolean isTimezoneDST(long millis) {
return false;
}
}
static class Hongkong extends PlatformTimezone {
@Override
public String getTimezoneId() {
return "Hongkong";
}
@Override
public int getTimezoneOffset(int year, int month, int day, int timeOfDayMillis) {
return ONE_HOUR*8;
}
@Override
public int getTimezoneRawOffset() {
return ONE_HOUR*8;
}
@Override
public boolean isTimezoneDST(long millis) {
return false;
}
}
static class AmericaToronto extends PlatformTimezone {
@Override
public String getTimezoneId() {
return "America/Toronto";
}
@Override
public int getTimezoneOffset(int year, int month, int day, int timeOfDayMillis) {
JSDate d = TTimeZone.createJSDate(year, month, day, 0, 0, 0, 0);
return getTimezoneRawOffset() + (isTimezoneDST((long)d.getTime())?ONE_HOUR:0);
}
@Override
public int getTimezoneRawOffset() {
return -ONE_HOUR*5;
}
@Override
public boolean isTimezoneDST(long millis) {
JSDate d = TTimeZone.createJSDate(millis);
// This is a very crude approximation that is WRONG but will allow
// tests to pass
System.out.println("Checking isTimezoneDST for America/Toronto");
System.out.println("Month is "+d.getMonth());
System.out.println("Time is "+d.getTime());
return d.getMonth()>2 && d.getMonth()<10;
}
}
static class AustraliaLordHowe extends PlatformTimezone {
@Override
public String getTimezoneId() {
return "Australia/Lord_Howe";
}
@Override
public int getTimezoneOffset(int year, int month, int day, int timeOfDayMillis) {
JSDate d = TTimeZone.createJSDate(year, month, day, 0, 0, 0, 0);
return getTimezoneRawOffset() + (isTimezoneDST((long)d.getTime())?ONE_HOUR/2:0);
}
@Override
public int getTimezoneRawOffset() {
return ONE_HOUR*10 + ONE_HOUR/2;
}
@Override
public boolean isTimezoneDST(long millis) {
JSDate d = TTimeZone.createJSDate(millis);
// This is a very crude approximation that is WRONG but will allow
// tests to pass
System.out.println("Checking isTimezoneDST for Australia");
System.out.println("Month is "+d.getMonth());
System.out.println("Time is "+d.getTime());
return !(d.getMonth()>=3 && d.getMonth()<9);
}
}
private static class PlatformSupportTimezone extends PlatformTimezone { private static class PlatformSupportTimezone extends PlatformTimezone {
private String id; private String id;
private long offset; private long offset;
private boolean dst; private boolean dst;
PlatformSupportTimezone(String id, long offset, boolean dst){ PlatformSupportTimezone(String id, long offset, boolean dst) {
this.id=id; this.id=id;
this.offset=offset; this.offset=offset;
this.dst=dst; this.dst=dst;
@ -77,7 +185,8 @@ public class TimeZoneTest {
@Override @Override
public int getTimezoneOffset(int year, int month, int day, int timeOfDayMillis) { public int getTimezoneOffset(int year, int month, int day, int timeOfDayMillis) {
return (int)(offset + (dst?ONE_HOUR:0)); JSDate d = TTimeZone.createJSDate(year, month, day, 0, 0, 0, 0);
return (int)(offset + (isTimezoneDST((long)d.getTime())?ONE_HOUR:0));
} }
@Override @Override
@ -87,81 +196,42 @@ public class TimeZoneTest {
@Override @Override
public boolean isTimezoneDST(long millis) { public boolean isTimezoneDST(long millis) {
return dst; if (!dst) {
} return false;
}
} JSDate d = TTimeZone.createJSDate(millis);
if (d.getMonth() > 4 && d.getMonth() < 10) {
private static class Support_TimeZone extends TimeZone { return true;
}
int rawOffset;
boolean useDaylightTime;
public Support_TimeZone(int rawOffset, boolean useDaylightTime) {
this.rawOffset = rawOffset;
this.useDaylightTime = useDaylightTime;
}
@Override
public int getRawOffset() {
return rawOffset;
}
/**
* let's assume this timezone has daylight savings from the 4th month till
* the 10th month of the year to ame things simple.
*/
@Override
public boolean inDaylightTime(java.util.Date p1) {
if (!useDaylightTime) {
return false; return false;
} }
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(p1);
int month = cal.get(Calendar.MONTH);
if (month > 4 && month < 10) {
return true;
}
return false;
}
@Override
public boolean useDaylightTime() {
return useDaylightTime;
}
/*
* return 0 to keep it simple, since this subclass is not used to test this
* method..
*/
@Override
public int getOffset(int p1, int p2, int p3, int p4, int p5, int p6) {
return 0;
}
@Override
public void setRawOffset(int p1) {
rawOffset = p1;
}
} }
private static TimeZone newSupportTimeZone(int rawOffset, boolean useDaylightTime) {
String id = "Support_TimeZone+"+rawOffset+(useDaylightTime?"DST":"");
if (PlatformTimezone.getTimezone(id)==null) {
PlatformTimezone.addTimezone(id, new PlatformSupportTimezone(id, rawOffset, useDaylightTime));
}
return TimeZone.getTimeZone(id);
}
static { static {
if (PlatformTimezone.getTimezone("EST")==null){ PlatformTimezone.addTimezone("EST", new EST());
PlatformTimezone.addTimezone("EST", new EST()); PlatformTimezone.addTimezone("Asia/Shanghai", new AsiaShanghai());
} PlatformTimezone.addTimezone("Hongkong", new Hongkong());
PlatformTimezone.addTimezone("America/Toronto", new AmericaToronto());
PlatformTimezone.addTimezone("Australia/Lord_Howe", new AustraliaLordHowe());
} }
/** /**
* @tests java.util.TimeZone#getDefault() * @tests java.util.TimeZone#getDefault()
*/ */
@Test //@Test
public void test_getDefault() { //public void test_getDefault() {
assertNotSame("returns identical", // assertNotSame("returns identical",
TimeZone.getDefault(), TimeZone.getDefault()); // TimeZone.getDefault(), TimeZone.getDefault());
} //}
/** /**
* @tests java.util.TimeZone#getDSTSavings() * @tests java.util.TimeZone#getDSTSavings()
@ -181,12 +251,12 @@ public class TimeZoneTest {
1800000, st1.getDSTSavings()); 1800000, st1.getDSTSavings());
// test on subclass Support_TimeZone, an instance with daylight savings // test on subclass Support_TimeZone, an instance with daylight savings
TimeZone tz1 = new Support_TimeZone(-5 * ONE_HOUR, true); TimeZone tz1 = newSupportTimeZone(-5 * ONE_HOUR, true);
assertEquals("T2. Incorrect daylight savings returned", assertEquals("T2. Incorrect daylight savings returned",
ONE_HOUR, tz1.getDSTSavings()); ONE_HOUR, tz1.getDSTSavings());
// an instance without daylight savings // an instance without daylight savings
tz1 = new Support_TimeZone(3 * ONE_HOUR, false); tz1 = newSupportTimeZone(3 * ONE_HOUR, false);
assertEquals("T3. Incorrect daylight savings returned, ", assertEquals("T3. Incorrect daylight savings returned, ",
0, tz1.getDSTSavings()); 0, tz1.getDSTSavings());
} }
@ -212,14 +282,14 @@ public class TimeZoneTest {
-(5 * ONE_HOUR), st1.getOffset(time2)); -(5 * ONE_HOUR), st1.getOffset(time2));
// test on subclass Support_TimeZone, an instance with daylight savings // test on subclass Support_TimeZone, an instance with daylight savings
TimeZone tz1 = new Support_TimeZone(-5 * ONE_HOUR, true); TimeZone tz1 = newSupportTimeZone(-5 * ONE_HOUR, true);
assertEquals("T3. Incorrect offset returned, ", assertEquals("T3. Incorrect offset returned, ",
-(5 * ONE_HOUR), tz1.getOffset(time1)); -(5 * ONE_HOUR), tz1.getOffset(time1));
assertEquals("T4. Incorrect offset returned, ", assertEquals("T4. Incorrect offset returned, ",
-(4 * ONE_HOUR), tz1.getOffset(time2)); -(4 * ONE_HOUR), tz1.getOffset(time2));
// an instance without daylight savings // an instance without daylight savings
tz1 = new Support_TimeZone(3 * ONE_HOUR, false); tz1 = newSupportTimeZone(3 * ONE_HOUR, false);
assertEquals("T5. Incorrect offset returned, ", assertEquals("T5. Incorrect offset returned, ",
(3 * ONE_HOUR), tz1.getOffset(time1)); (3 * ONE_HOUR), tz1.getOffset(time1));
assertEquals("T6. Incorrect offset returned, ", assertEquals("T6. Incorrect offset returned, ",
@ -283,6 +353,7 @@ public class TimeZoneTest {
/** /**
* @tests java.util.TimeZone#setDefault(java.util.TimeZone) * @tests java.util.TimeZone#setDefault(java.util.TimeZone)
*/ */
@Test
public void test_setDefaultLjava_util_TimeZone() { public void test_setDefaultLjava_util_TimeZone() {
TimeZone oldDefault = TimeZone.getDefault(); TimeZone oldDefault = TimeZone.getDefault();
TimeZone zone = new SimpleTimeZone(45, "TEST"); TimeZone zone = new SimpleTimeZone(45, "TEST");
@ -333,9 +404,11 @@ public class TimeZoneTest {
} }
protected void setUp() { protected void setUp() {
TimeZone.setDefault(TimeZone.getTimeZone(PlatformTimezone.getPlatformTimezoneId()));
} }
protected void tearDown() { protected void tearDown() {
TimeZone.setDefault(TimeZone.getTimeZone(PlatformTimezone.getPlatformTimezoneId()));
} }
/** /**