From c9819f3a86b28f0046dfe06ddfebcbe5812d9430 Mon Sep 17 00:00:00 2001 From: Steve Hannah Date: Thu, 9 Apr 2015 13:05:24 -0700 Subject: [PATCH] Added timezone support. Only LOCAL and GMT are currently supported, but you can extend the native functions in runtime to add support for other timezones. --- .../teavm/classlib/java/util/TTimeZone.java | 14 +++++- .../resources/org/teavm/javascript/runtime.js | 44 ++++++++++++++++++- .../classlib/java/text/DateFormatTest.java | 4 +- .../java/text/SimpleDateFormatTest.java | 3 +- .../classlib/java/util/TimeZoneTest.java | 24 ++++++++++ 5 files changed, 84 insertions(+), 5 deletions(-) create mode 100644 teavm-tests/src/test/java/org/teavm/classlib/java/util/TimeZoneTest.java diff --git a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TTimeZone.java b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TTimeZone.java index c1b5051a2..d67dc73d7 100644 --- a/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TTimeZone.java +++ b/teavm-classlib/src/main/java/org/teavm/classlib/java/util/TTimeZone.java @@ -15,6 +15,8 @@ */ package org.teavm.classlib.java.util; +import org.teavm.jso.JSBody; + /** * 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. @@ -62,10 +64,20 @@ public abstract class TTimeZone { return new String[] {"GMT", i}; } } - + @JSBody(params={}, + script="return $rt_getTimezoneId(name,year,month,day,timeOfDayMillis)" + ) private static native String getTimezoneId(); + + @JSBody(params={"name","year","month","day","timeOfDayMillis"}, + script="return $rt_getTimezoneOffset(name,year,month,day,timeOfDayMillis)") private static native int getTimezoneOffset(String name, int year, int month, int day, int timeOfDayMillis); + + @JSBody(params="name", + script="return $rt_getTimezoneRawOffset(name)") private static native int getTimezoneRawOffset(String name); + + @JSBody(params={"name","millis"}, script="return $rt_isTimezoneDST(name,millis)") private static native boolean isTimezoneDST(String name, long millis); /** diff --git a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js index 142d1cc95..dff1691cc 100644 --- a/teavm-core/src/main/resources/org/teavm/javascript/runtime.js +++ b/teavm-core/src/main/resources/org/teavm/javascript/runtime.js @@ -529,7 +529,49 @@ function $rt_nativeThread() { function $rt_invalidPointer() { throw new Error("Invalid recorded state"); } - +function $rt_getTimezoneId(){ + return "LOCAL"; +} +function $rt_getTimezoneOffset(name, year, month, day, timeOfDayMillis){ + if ($rt_getTimezoneId()===name){ + var hours = Math.floor(timeOfDayMillis/1000/60/60); + var minutes = Math.floor(timeOfDayMillis/1000/60)%60; + var seconds = Math.floor(timeOfDayMillis/1000)%60; + var millis = timeOfDayMillis % 1000; + return -(new Date(year, month, day, hours, minutes, seconds, millis).getTimezoneOffset()*1000*60); + } else if ("UTC"===name || "GMT"===name){ + return 0; + } else { + throw new Error("Unsupported Timezone: "+name); + } +} +function $rt_getTimezoneRawOffset(name){ + if ($rt_getTimezoneId()===name){ + var millis = new Date().getTime(); + var i=0; + var addDays = 1000 * 60 *60 * 24 * 200; // Check 200 days later + while ($rt_isTimezoneDST(name, millis) && i++<4){ + millis += addDays; + } + return -(new Date(millis).getTimezoneOffset()*1000*60); + } else if (name==='GMT' || name==='UTC'){ + return 0; + } else { + throw new Error("Unsupported Timezone: "+name); + } +} +function $rt_isTimezoneDST(name, millis){ + if ($rt_getTimezoneId()===name){ + var jan = new Date(this.getFullYear(), 0, 1); + var jul = new Date(this.getFullYear(), 6, 1); + var maxOff = Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset()); + return new Date(millis).getTimezoneOffset()