Reimplement java.util.Date in Java, using the new JsDate.
http://gwt-code-reviews.appspot.com/181801
Review by: rice, jat
git-svn-id: https://google-web-toolkit.googlecode.com/svn/trunk@7713 8db76d5a-ed1c-0410-87a9-c151d255dfc7
diff --git a/user/super/com/google/gwt/emul/java/util/Date.java b/user/super/com/google/gwt/emul/java/util/Date.java
index 7701124..f54ed3c 100644
--- a/user/super/com/google/gwt/emul/java/util/Date.java
+++ b/user/super/com/google/gwt/emul/java/util/Date.java
@@ -1,12 +1,12 @@
/*
* Copyright 2007 Google Inc.
- *
+ *
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
@@ -15,7 +15,7 @@
*/
package java.util;
-import com.google.gwt.core.client.JavaScriptObject;
+import com.google.gwt.core.client.JsDate;
import java.io.Serializable;
@@ -25,34 +25,31 @@
public class Date implements Cloneable, Comparable<Date>, Serializable {
/**
- * Used only by toString().
+ * Encapsulates static data to avoid Date itself having a static initializer.
*/
- private static final String[] DAYS = {
- "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
- };
+ private static class StringData {
+ public static final String[] DAYS = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
- /**
- * Used only by toString().
- */
- private static final String[] MONTHS = {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
- };
+ public static final String[] MONTHS = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
+ "Nov", "Dec"};
+ }
public static long parse(String s) {
- long d = (long) parse0(s);
- if (d != -1) {
- return d;
- } else {
+ double parsed = JsDate.parse(s);
+ if (Double.isNaN(parsed)) {
throw new IllegalArgumentException();
}
+ return (long) parsed;
}
// CHECKSTYLE_OFF: Matching the spec.
- public static long UTC(int year, int month, int date, int hrs,
- int min, int sec) {
- return (long) utc0(year, month, date, hrs, min, sec);
+ public static long UTC(int year, int month, int date, int hrs, int min,
+ int sec) {
+ return (long) JsDate.UTC(year + 1900, month, date, hrs, min, sec, 0);
}
+
// CHECKSTYLE_ON
/**
@@ -69,71 +66,35 @@
}
/**
- * Return the names for the days of the week as specified by the Date
- * specification.
- */
- @SuppressWarnings("unused") // called by JSNI
- private static String dayToString(int day) {
- return DAYS[day];
- }
-
- /**
- * Return the names for the months of the year as specified by the Date
- * specification.
- */
- @SuppressWarnings("unused") // called by JSNI
- private static String monthToString(int month) {
- return MONTHS[month];
- }
-
- private static native double parse0(String s) /*-{
- var d = Date.parse(s);
- return isNaN(d) ? -1 : d;
- }-*/;
-
- /**
- * Throw an exception if jsdate is not an object.
- *
- * @param val
- */
- @SuppressWarnings("unused") // called by JSNI
- private static void throwJsDateException(String val) {
- throw new IllegalStateException("jsdate is " + val);
- }
-
- private static native double utc0(int year, int month, int date, int hrs,
- int min, int sec) /*-{
- return Date.UTC(year + 1900, month, date, hrs, min, sec);
- }-*/;
-
- /**
* JavaScript Date instance.
*/
- @SuppressWarnings("unused") // used from JSNI
- private JavaScriptObject jsdate;
-
+ private final JsDate jsdate;
+
public Date() {
- init();
+ jsdate = JsDate.create();
}
public Date(int year, int month, int date) {
- init(year, month, date, 0, 0, 0);
+ this(year, month, date, 0, 0, 0);
}
public Date(int year, int month, int date, int hrs, int min) {
- init(year, month, date, hrs, min, 0);
+ this(year, month, date, hrs, min, 0);
}
public Date(int year, int month, int date, int hrs, int min, int sec) {
- init(year, month, date, hrs, min, sec);
+ jsdate = JsDate.create();
+ jsdate.setFullYear(year + 1900, month, date);
+ jsdate.setHours(hrs, min, sec, 0);
+ fixDaylightSavings(hrs);
}
public Date(long date) {
- init(date);
+ jsdate = JsDate.create(date);
}
public Date(String date) {
- init(Date.parse(date));
+ this(Date.parse(date));
}
public boolean after(Date when) {
@@ -165,161 +126,113 @@
return ((obj instanceof Date) && (getTime() == ((Date) obj).getTime()));
}
- public native int getDate() /*-{
- this.@java.util.Date::checkJsDate()();
- return this.@java.util.Date::jsdate.getDate();
- }-*/;
-
- public native int getDay() /*-{
- this.@java.util.Date::checkJsDate()();
- return this.@java.util.Date::jsdate.getDay();
- }-*/;
-
- public native int getHours() /*-{
- this.@java.util.Date::checkJsDate()();
- return this.@java.util.Date::jsdate.getHours();
- }-*/;
-
- public native int getMinutes() /*-{
- this.@java.util.Date::checkJsDate()();
- return this.@java.util.Date::jsdate.getMinutes();
- }-*/;
-
- public native int getMonth() /*-{
- this.@java.util.Date::checkJsDate()();
- return this.@java.util.Date::jsdate.getMonth();
- }-*/;
-
- public native int getSeconds() /*-{
- this.@java.util.Date::checkJsDate()();
- return this.@java.util.Date::jsdate.getSeconds();
- }-*/;
-
- public long getTime() {
- return (long) getTime0();
+ public int getDate() {
+ return jsdate.getDate();
}
- public native int getTimezoneOffset() /*-{
- this.@java.util.Date::checkJsDate()();
- return this.@java.util.Date::jsdate.getTimezoneOffset();
- }-*/;
+ public int getDay() {
+ return jsdate.getDay();
+ }
- public native int getYear() /*-{
- this.@java.util.Date::checkJsDate()();
- return this.@java.util.Date::jsdate.getFullYear() - 1900;
- }-*/;
+ public int getHours() {
+ return jsdate.getHours();
+ }
+
+ public int getMinutes() {
+ return jsdate.getMinutes();
+ }
+
+ public int getMonth() {
+ return jsdate.getMonth();
+ }
+
+ public int getSeconds() {
+ return jsdate.getSeconds();
+ }
+
+ public long getTime() {
+ return (long) jsdate.getTime();
+ }
+
+ public int getTimezoneOffset() {
+ return jsdate.getTimezoneOffset();
+ }
+
+ public int getYear() {
+ return jsdate.getFullYear() - 1900;
+ }
@Override
public int hashCode() {
- return (int) (this.getTime() ^ (this.getTime() >>> 32));
+ long time = getTime();
+ return (int) (time ^ (time >>> 32));
}
- public native void setDate(int date) /*-{
- this.@java.util.Date::checkJsDate()();
- var hours = this.@java.util.Date::jsdate.getHours()
- this.@java.util.Date::jsdate.setDate(date);
- this.@java.util.Date::fixDaylightSavings(I)(hours);
- }-*/;
+ public void setDate(int date) {
+ int hours = jsdate.getHours();
+ jsdate.setDate(date);
+ fixDaylightSavings(hours);
+ }
- public native void setHours(int hours) /*-{
- this.@java.util.Date::checkJsDate()();
- this.@java.util.Date::jsdate.setHours(hours);
- this.@java.util.Date::fixDaylightSavings(I)(hours);
- }-*/;
+ public void setHours(int hours) {
+ jsdate.setHours(hours);
+ fixDaylightSavings(hours);
+ }
- public native void setMinutes(int minutes) /*-{
- this.@java.util.Date::checkJsDate()();
- // Truncate (minutes / 60) to int.
- var hours = this.@java.util.Date::jsdate.getHours() + ~~(minutes / 60);
- this.@java.util.Date::jsdate.setMinutes(minutes);
- this.@java.util.Date::fixDaylightSavings(I)(hours);
- }-*/;
+ public void setMinutes(int minutes) {
+ int hours = getHours() + minutes / 60;
+ jsdate.setMinutes(minutes);
+ fixDaylightSavings(hours);
+ }
- public native void setMonth(int month) /*-{
- this.@java.util.Date::checkJsDate()();
- var hours = this.@java.util.Date::jsdate.getHours();
- this.@java.util.Date::jsdate.setMonth(month);
- this.@java.util.Date::fixDaylightSavings(I)(hours);
- }-*/;
+ public void setMonth(int month) {
+ int hours = jsdate.getHours();
+ jsdate.setMonth(month);
+ fixDaylightSavings(hours);
+ }
- public native void setSeconds(int seconds) /*-{
- this.@java.util.Date::checkJsDate()();
- // Truncate (seconds / (60 * 60)) to int.
- var hours = this.@java.util.Date::jsdate.getHours() + ~~(seconds / (60 * 60));
- this.@java.util.Date::jsdate.setSeconds(seconds);
- this.@java.util.Date::fixDaylightSavings(I)(hours);
- }-*/;
+ public void setSeconds(int seconds) {
+ int hours = getHours() + seconds / (60 * 60);
+ jsdate.setSeconds(seconds);
+ fixDaylightSavings(hours);
+ }
public void setTime(long time) {
- setTime0(time);
+ jsdate.setTime(time);
}
- public native void setYear(int year) /*-{
- this.@java.util.Date::checkJsDate()();
- var hours = this.@java.util.Date::jsdate.getHours()
- this.@java.util.Date::jsdate.setFullYear(year + 1900);
- this.@java.util.Date::fixDaylightSavings(I)(hours);
- }-*/;
+ public void setYear(int year) {
+ int hours = jsdate.getHours();
+ jsdate.setFullYear(year + 1900);
+ fixDaylightSavings(hours);
+ }
- public native String toGMTString() /*-{
- this.@java.util.Date::checkJsDate()();
- var d = this.@java.util.Date::jsdate;
- var padTwo = @java.util.Date::padTwo(I);
- var month =
- @java.util.Date::monthToString(I)(this.@java.util.Date::jsdate.getUTCMonth());
-
- return d.getUTCDate() + " " +
- month + " " +
- d.getUTCFullYear() + " " +
- padTwo(d.getUTCHours()) + ":" +
- padTwo(d.getUTCMinutes()) + ":" +
- padTwo(d.getUTCSeconds()) +
- " GMT";
- }-*/;
+ public String toGMTString() {
+ return jsdate.getUTCDate() + " " + StringData.MONTHS[jsdate.getUTCMonth()]
+ + " " + jsdate.getUTCFullYear() + " " + padTwo(jsdate.getUTCHours())
+ + ":" + padTwo(jsdate.getUTCMinutes()) + ":"
+ + padTwo(jsdate.getUTCSeconds()) + " GMT";
+ }
- public native String toLocaleString() /*-{
- this.@java.util.Date::checkJsDate()();
- return this.@java.util.Date::jsdate.toLocaleString();
- }-*/;
+ public String toLocaleString() {
+ return jsdate.toLocaleString();
+ }
@Override
- public native String toString() /*-{
- this.@java.util.Date::checkJsDate()();
- var d = this.@java.util.Date::jsdate;
- var padTwo = @java.util.Date::padTwo(I);
- var day =
- @java.util.Date::dayToString(I)(d.getDay());
- var month =
- @java.util.Date::monthToString(I)(d.getMonth());
-
+ public String toString() {
// Compute timezone offset. The value that getTimezoneOffset returns is
// backwards for the transformation that we want.
- var offset = -d.getTimezoneOffset();
- var hourOffset = String((offset >= 0) ?
- "+" + Math.floor(offset / 60) : Math.ceil(offset / 60));
- var minuteOffset = padTwo(Math.abs(offset) % 60);
+ int offset = -jsdate.getTimezoneOffset();
+ String hourOffset = ((offset >= 0) ? "+" : "") + (offset / 60);
+ String minuteOffset = padTwo(Math.abs(offset) % 60);
- return day + " " + month + " " +
- padTwo(d.getDate()) + " " +
- padTwo(d.getHours()) + ":" +
- padTwo(d.getMinutes()) + ":" +
- padTwo(d.getSeconds()) +
- " GMT" + hourOffset + minuteOffset +
- + " " + d.getFullYear();
- }-*/;
+ return StringData.DAYS[jsdate.getDay()] + " "
+ + StringData.MONTHS[jsdate.getMonth()] + " " + padTwo(jsdate.getDate())
+ + " " + padTwo(jsdate.getHours()) + ":" + padTwo(jsdate.getMinutes())
+ + ":" + padTwo(jsdate.getSeconds()) + " GMT" + hourOffset
+ + minuteOffset + " " + jsdate.getFullYear();
+ }
- /**
- * Check that jsdate is valid and throw an exception if not.
- */
- @SuppressWarnings("unused") // called by JSNI
- private native void checkJsDate() /*-{
- if (!this.@java.util.Date::jsdate
- || typeof this.@java.util.Date::jsdate != "object") {
- @java.util.Date::throwJsDateException(Ljava/lang/String;)(""
- + this.@java.util.Date::jsdate);
- }
- }-*/;
-
/*
* Some browsers have the following behavior:
*
@@ -339,66 +252,27 @@
* local time advancing into daylight savings time. If so, push the requested
* time forward out of the non-existent range.
*/
- @SuppressWarnings("unused") // called by JSNI
- private native void fixDaylightSavings(int hours) /*-{
- if ((this.@java.util.Date::jsdate.getHours() % 24) != (hours % 24)) {
- // Find the change in time zone offset between the current
- // time and the same time the following day
- var d = new Date();
- d.setTime(this.@java.util.Date::jsdate.getTime());
- var noff = d.getTimezoneOffset();
- d.setDate(d.getDate() + 1);
- var loff = d.getTimezoneOffset();
- var timeDiff = noff - loff;
- var timeDiffHours = ~~(timeDiff / 60);
- var timeDiffMinutes = timeDiff % 60;
+ private void fixDaylightSavings(int hours) {
+ if ((jsdate.getHours() % 24) != (hours % 24)) {
+ JsDate copy = JsDate.create(jsdate.getTime());
+ copy.setDate(copy.getDate() + 1);
+ int timeDiff = jsdate.getTimezoneOffset() - copy.getTimezoneOffset();
// If the time zone offset is changing, advance the hours and
// minutes from the initially requested time by the change amount
if (timeDiff > 0) {
- var year = this.@java.util.Date::jsdate.getYear() + 1900;
- var month = this.@java.util.Date::jsdate.getMonth();
- var day = this.@java.util.Date::jsdate.getDate();
- var badHours = this.@java.util.Date::jsdate.getHours();
- var minute = this.@java.util.Date::jsdate.getMinutes();
- var second = this.@java.util.Date::jsdate.getSeconds();
+ int timeDiffHours = timeDiff / 60;
+ int timeDiffMinutes = timeDiff % 60;
+ int day = jsdate.getDate();
+ int badHours = jsdate.getHours();
if (badHours + timeDiffHours >= 24) {
day++;
}
- var newTime = new Date(year, month, day,
- hours + timeDiffHours,
- minute + timeDiffMinutes, second);
- this.@java.util.Date::jsdate.setTime(newTime.getTime());
+ JsDate newTime = JsDate.create(jsdate.getFullYear(), jsdate.getMonth(),
+ day, hours + timeDiffHours, jsdate.getMinutes() + timeDiffMinutes,
+ jsdate.getSeconds(), jsdate.getMilliseconds());
+ jsdate.setTime(newTime.getTime());
}
}
- }-*/;
-
- private native double getTime0() /*-{
- this.@java.util.Date::checkJsDate()();
- return this.@java.util.Date::jsdate.getTime();
- }-*/;
-
- private native void init() /*-{
- this.@java.util.Date::jsdate = new Date();
- }-*/;
-
- private native void init(double date) /*-{
- this.@java.util.Date::jsdate = new Date(date);
- }-*/;
-
- private native void init(int year, int month, int date, int hrs, int min,
- int sec) /*-{
- this.@java.util.Date::jsdate = new Date();
- this.@java.util.Date::checkJsDate()();
- this.@java.util.Date::jsdate.setFullYear(year + 1900, month, date);
- this.@java.util.Date::jsdate.setHours(hrs, min, sec, 0);
-
- // Set the expected hour.
- this.@java.util.Date::fixDaylightSavings(I)(hrs);
- }-*/;
-
- private native void setTime0(double time) /*-{
- this.@java.util.Date::checkJsDate()();
- this.@java.util.Date::jsdate.setTime(time);
- }-*/;
+ }
}
diff --git a/user/test/com/google/gwt/emultest/java/util/DateTest.java b/user/test/com/google/gwt/emultest/java/util/DateTest.java
index 54bdda3..bb7e596 100644
--- a/user/test/com/google/gwt/emultest/java/util/DateTest.java
+++ b/user/test/com/google/gwt/emultest/java/util/DateTest.java
@@ -33,19 +33,6 @@
public static final String PAST = "PAST";
public static final long SECOND_MILLISECONDS_SHIFT = 10;
- private static native void mungeDateNull(Date d) /*-{
- d.@java.util.Date::jsdate = null;
- }-*/;
-
- private static native void mungeDatePrimitive(Date d) /*-{
- d.@java.util.Date::jsdate = 42;
- }-*/;
-
- private static native void mungeDateUndef(Date d) /*-{
- // use (void 0) to get an undefined value
- d.@java.util.Date::jsdate = (void 0);
- }-*/;
-
Date theDate = new Date();
/**
@@ -111,39 +98,6 @@
}
/**
- * Test that Date correctly catches when its internal jsdate
- * instance is mangled.
- */
- public void testCheck() {
- if (GWT.isScript()) {
- Date d = new Date();
- mungeDateNull(d);
- try {
- d.getHours();
- fail("Expected IllegalStateException");
- } catch (IllegalStateException expected) {
- // do nothing
- }
- d = new Date();
- mungeDateUndef(d);
- try {
- d.getHours();
- fail("Expected IllegalStateException");
- } catch (IllegalStateException expected) {
- // do nothing
- }
- d = new Date();
- mungeDatePrimitive(d);
- try {
- d.getHours();
- fail("Expected IllegalStateException");
- } catch (IllegalStateException expected) {
- // do nothing
- }
- }
- }
-
- /**
* Tests that if daylight savings time occurs tomorrow, the current date isn't
* affected.
*/