From 75feb179b4d734f941962d1cda2110e779df42d5 Mon Sep 17 00:00:00 2001 From: megacz Date: Fri, 30 Jan 2004 07:37:27 +0000 Subject: [PATCH] 2003/09/26 07:09:55 darcs-hash:20040130073727-2ba56-5db85e97adf73381cc713b7e78a0fc98b67e3e48.gz --- src/org/xwt/XMLRPC.java | 56 +- src/org/xwt/js/Date.java | 1623 ++++++++++++++++++++++++++++++++++++++++++++- src/org/xwt/util/Log.java | 2 +- 3 files changed, 1642 insertions(+), 39 deletions(-) diff --git a/src/org/xwt/XMLRPC.java b/src/org/xwt/XMLRPC.java index 12c6466..7325476 100644 --- a/src/org/xwt/XMLRPC.java +++ b/src/org/xwt/XMLRPC.java @@ -113,33 +113,30 @@ class XMLRPC extends JS.Callable { objects.setElementAt(new String(content.getBuf(), 0, content.size()), objects.size() - 1); else if (c.localName.equals("dateTime.iso8601")) { - throw new Error("not implemented"); - /* - String s = new String(content.getBuf(), 0, content.size()); - - // strip whitespace - int i=0; - while(Character.isWhitespace(s.charAt(i))) i++; - if (i > 0) s = s.substring(i); - - try { - NativeDate nd = (NativeDate)JS.Thread.enter().newObject(org.xwt.util.JS.Obj.defaultObjects, "Date"); - double date = NativeDate.date_msecFromDate(Double.valueOf(s.substring(0, 4)).doubleValue(), - Double.valueOf(s.substring(4, 6)).doubleValue() - 1, - Double.valueOf(s.substring(6, 8)).doubleValue(), - Double.valueOf(s.substring(9, 11)).doubleValue(), - Double.valueOf(s.substring(12, 14)).doubleValue(), - Double.valueOf(s.substring(15, 17)).doubleValue(), - (double)0 - ); - nd.jsFunction_setTime(NativeDate.internalUTC(date)); - objects.setElementAt(nd, objects.size() - 1); - - } catch (Exception e) { - if (Log.on) Log.log(this, "error parsing date : " + s); - if (Log.on) Log.log(this, e); - } - */ + String s = new String(content.getBuf(), 0, content.size()); + + // strip whitespace + int i=0; + while(Character.isWhitespace(s.charAt(i))) i++; + if (i > 0) s = s.substring(i); + + try { + org.xwt.js.Date nd = new org.xwt.js.Date(); + double date = org.xwt.js.Date.date_msecFromDate(Double.valueOf(s.substring(0, 4)).doubleValue(), + Double.valueOf(s.substring(4, 6)).doubleValue() - 1, + Double.valueOf(s.substring(6, 8)).doubleValue(), + Double.valueOf(s.substring(9, 11)).doubleValue(), + Double.valueOf(s.substring(12, 14)).doubleValue(), + Double.valueOf(s.substring(15, 17)).doubleValue(), + (double)0 + ); + nd.jsFunction_setTime(org.xwt.js.Date.internalUTC(date)); + objects.setElementAt(nd, objects.size() - 1); + + } catch (Exception e) { + if (Log.on) Log.log(this, "error parsing date : " + s); + if (Log.on) Log.log(this, e); + } } else if (c.localName.equals("member")) { Object memberValue = objects.elementAt(objects.size() - 1); @@ -240,11 +237,9 @@ class XMLRPC extends JS.Callable { } sb.append("\n"); - /* } else if (o instanceof org.xwt.js.Date) { sb.append(" "); - org.xwt.js.Date d = (org.xwt.js.Date)o; - Date d = new Date(nd.getRawTime()); + java.util.Date d = new java.util.Date(((org.xwt.js.Date)o).getRawTime()); sb.append(d.getYear() + 1900); if (d.getMonth() + 1 < 10) sb.append('0'); sb.append(d.getMonth() + 1); @@ -260,7 +255,6 @@ class XMLRPC extends JS.Callable { if (d.getSeconds() < 10) sb.append('0'); sb.append(d.getSeconds()); sb.append("\n"); - */ } else if (o instanceof JS.Array) { if (tracker.get(o) != null) throw new JS.Exn("attempted to send multi-ref data structure via XML-RPC"); diff --git a/src/org/xwt/js/Date.java b/src/org/xwt/js/Date.java index 8fbd02d..150d738 100644 --- a/src/org/xwt/js/Date.java +++ b/src/org/xwt/js/Date.java @@ -1,10 +1,1619 @@ -// Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] +/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (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.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is Rhino code, released + * May 6, 1999. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1997-1999 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * Norris Boyd + * Mike McCabe + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License (the "GPL"), in which case the + * provisions of the GPL are applicable instead of those above. + * If you wish to allow use of your version of this file only + * under the terms of the GPL and not to allow others to use your + * version of this file under the NPL, indicate your decision by + * deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the NPL or the GPL. + */ -package org.xwt.js; -import org.xwt.util.*; -import java.io.*; -import java.util.*; +package org.xwt.js; -/** a JavaScript Date object */ -class Date extends JS.Obj { +import java.util.TimeZone; +import java.util.Locale; +import java.text.NumberFormat; +import java.text.DateFormat; +import java.text.SimpleDateFormat; + +/** + * This class implements the Date native object. + * See ECMA 15.9. + * @author Mike McCabe + */ +public class Date extends JS.Obj { + + public Date() { + if (thisTimeZone == null) { + // j.u.TimeZone is synchronized, so setting class statics from it + // should be OK. + thisTimeZone = java.util.TimeZone.getDefault(); + LocalTZA = thisTimeZone.getRawOffset(); + } + } + + public String coerceToString() { return date_format(date, FORMATSPEC_FULL); } + + public Object callMethod(Object name, JS.Array args_, boolean checkOnly) { + Object[] args = new Object[args_.length()]; + for(int i=0; i lo) { + mid = (hi + lo) / 2; + if (TimeFromYear(mid) > t) { + hi = mid - 1; + } else { + if (TimeFromYear(mid) <= t) { + int temp = mid + 1; + if (TimeFromYear(temp) > t) { + return mid; + } + lo = mid + 1; + } + } + } + return lo; + } + + private static boolean InLeapYear(double t) { + return DaysInYear(YearFromTime(t)) == 366; + } + + private static int DayWithinYear(double t) { + int year = YearFromTime(t); + return (int) (Day(t) - DayFromYear(year)); + } + /* + * The following array contains the day of year for the first day of + * each month, where index 0 is January, and day 0 is January 1. + */ + + private static double DayFromMonth(int m, boolean leap) { + int day = m * 30; + + if (m >= 7) { day += m / 2 - 1; } + else if (m >= 2) { day += (m - 1) / 2 - 1; } + else { day += m; } + + if (leap && m >= 2) { ++day; } + + return day; + } + + private static int MonthFromTime(double t) { + int d, step; + + d = DayWithinYear(t); + + if (d < (step = 31)) + return 0; + + // Originally coded as step += (InLeapYear(t) ? 29 : 28); + // but some jits always returned 28! + if (InLeapYear(t)) + step += 29; + else + step += 28; + + if (d < step) + return 1; + if (d < (step += 31)) + return 2; + if (d < (step += 30)) + return 3; + if (d < (step += 31)) + return 4; + if (d < (step += 30)) + return 5; + if (d < (step += 31)) + return 6; + if (d < (step += 31)) + return 7; + if (d < (step += 30)) + return 8; + if (d < (step += 31)) + return 9; + if (d < (step += 30)) + return 10; + return 11; + } + + private static int DateFromTime(double t) { + int d, step, next; + + d = DayWithinYear(t); + if (d <= (next = 30)) + return d + 1; + step = next; + + // Originally coded as next += (InLeapYear(t) ? 29 : 28); + // but some jits always returned 28! + if (InLeapYear(t)) + next += 29; + else + next += 28; + + if (d <= next) + return d - step; + step = next; + if (d <= (next += 31)) + return d - step; + step = next; + if (d <= (next += 30)) + return d - step; + step = next; + if (d <= (next += 31)) + return d - step; + step = next; + if (d <= (next += 30)) + return d - step; + step = next; + if (d <= (next += 31)) + return d - step; + step = next; + if (d <= (next += 31)) + return d - step; + step = next; + if (d <= (next += 30)) + return d - step; + step = next; + if (d <= (next += 31)) + return d - step; + step = next; + if (d <= (next += 30)) + return d - step; + step = next; + + return d - step; + } + + private static int WeekDay(double t) { + double result; + result = Day(t) + 4; + result = result % 7; + if (result < 0) + result += 7; + return (int) result; + } + + private static double Now() { + return (double) System.currentTimeMillis(); + } + + /* Should be possible to determine the need for this dynamically + * if we go with the workaround... I'm not using it now, because I + * can't think of any clean way to make toLocaleString() and the + * time zone (comment) in toString match the generated string + * values. Currently it's wrong-but-consistent in all but the + * most recent betas of the JRE - seems to work in 1.1.7. + */ + private final static boolean TZO_WORKAROUND = false; + private static double DaylightSavingTA(double t) { + if (!TZO_WORKAROUND) { + java.util.Date date = new java.util.Date((long) t); + if (thisTimeZone.inDaylightTime(date)) + return msPerHour; + else + return 0; + } else { + /* Use getOffset if inDaylightTime() is broken, because it + * seems to work acceptably. We don't switch over to it + * entirely, because it requires (expensive) exploded date arguments, + * and the api makes it impossible to handle dst + * changeovers cleanly. + */ + + // Hardcode the assumption that the changeover always + // happens at 2:00 AM: + t += LocalTZA + (HourFromTime(t) <= 2 ? msPerHour : 0); + + int year = YearFromTime(t); + double offset = thisTimeZone.getOffset(year > 0 ? 1 : 0, + year, + MonthFromTime(t), + DateFromTime(t), + WeekDay(t), + (int)TimeWithinDay(t)); + + if ((offset - LocalTZA) != 0) + return msPerHour; + else + return 0; + // return offset - LocalTZA; + } + } + + private static double LocalTime(double t) { + return t + LocalTZA + DaylightSavingTA(t); + } + + public static double internalUTC(double t) { + return t - LocalTZA - DaylightSavingTA(t - LocalTZA); + } + + private static int HourFromTime(double t) { + double result; + result = java.lang.Math.floor(t / msPerHour) % HoursPerDay; + if (result < 0) + result += HoursPerDay; + return (int) result; + } + + private static int MinFromTime(double t) { + double result; + result = java.lang.Math.floor(t / msPerMinute) % MinutesPerHour; + if (result < 0) + result += MinutesPerHour; + return (int) result; + } + + private static int SecFromTime(double t) { + double result; + result = java.lang.Math.floor(t / msPerSecond) % SecondsPerMinute; + if (result < 0) + result += SecondsPerMinute; + return (int) result; + } + + private static int msFromTime(double t) { + double result; + result = t % msPerSecond; + if (result < 0) + result += msPerSecond; + return (int) result; + } + + private static double MakeTime(double hour, double min, + double sec, double ms) + { + return ((hour * MinutesPerHour + min) * SecondsPerMinute + sec) + * msPerSecond + ms; + } + + private static double MakeDay(double year, double month, double date) { + double result; + boolean leap; + double yearday; + double monthday; + + year += java.lang.Math.floor(month / 12); + + month = month % 12; + if (month < 0) + month += 12; + + leap = (DaysInYear((int) year) == 366); + + yearday = java.lang.Math.floor(TimeFromYear(year) / msPerDay); + monthday = DayFromMonth((int) month, leap); + + result = yearday + + monthday + + date - 1; + return result; + } + + private static double MakeDate(double day, double time) { + return day * msPerDay + time; + } + + private static double TimeClip(double d) { + if (d != d || + d == Double.POSITIVE_INFINITY || + d == Double.NEGATIVE_INFINITY || + java.lang.Math.abs(d) > HalfTimeDomain) + { + return Double.NaN; + } + if (d > 0.0) + return java.lang.Math.floor(d + 0.); + else + return java.lang.Math.ceil(d + 0.); + } + + /* end of ECMA helper functions */ + + /* find UTC time from given date... no 1900 correction! */ + public static double date_msecFromDate(double year, double mon, + double mday, double hour, + double min, double sec, + double msec) + { + double day; + double time; + double result; + + day = MakeDay(year, mon, mday); + time = MakeTime(hour, min, sec, msec); + result = MakeDate(day, time); + return result; + } + + + private static final int MAXARGS = 7; + private static double jsStaticFunction_UTC(Object[] args) { + double array[] = new double[MAXARGS]; + int loop; + double d; + + for (loop = 0; loop < MAXARGS; loop++) { + if (loop < args.length) { + d = _toNumber(args[loop]); + if (d != d || Double.isInfinite(d)) { + return Double.NaN; + } + array[loop] = toDouble(args[loop]); + } else { + array[loop] = 0; + } + } + + /* adjust 2-digit years into the 20th century */ + if (array[0] >= 0 && array[0] <= 99) + array[0] += 1900; + + /* if we got a 0 for 'date' (which is out of range) + * pretend it's a 1. (So Date.UTC(1972, 5) works) */ + if (array[2] < 1) + array[2] = 1; + + d = date_msecFromDate(array[0], array[1], array[2], + array[3], array[4], array[5], array[6]); + d = TimeClip(d); + return d; + // return new Double(d); + } + + /* + * Use ported code from jsdate.c rather than the locale-specific + * date-parsing code from Java, to keep js and rhino consistent. + * Is this the right strategy? + */ + + /* for use by date_parse */ + + /* replace this with byte arrays? Cheaper? */ + private static String wtb[] = { + "am", "pm", + "monday", "tuesday", "wednesday", "thursday", "friday", + "saturday", "sunday", + "january", "february", "march", "april", "may", "june", + "july", "august", "september", "october", "november", "december", + "gmt", "ut", "utc", "est", "edt", "cst", "cdt", + "mst", "mdt", "pst", "pdt" + /* time zone table needs to be expanded */ + }; + + private static int ttb[] = { + -1, -2, 0, 0, 0, 0, 0, 0, 0, /* AM/PM */ + 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, + 10000 + 0, 10000 + 0, 10000 + 0, /* UT/UTC */ + 10000 + 5 * 60, 10000 + 4 * 60, /* EDT */ + 10000 + 6 * 60, 10000 + 5 * 60, + 10000 + 7 * 60, 10000 + 6 * 60, + 10000 + 8 * 60, 10000 + 7 * 60 + }; + + /* helper for date_parse */ + private static boolean date_regionMatches(String s1, int s1off, + String s2, int s2off, + int count) + { + boolean result = false; + /* return true if matches, otherwise, false */ + int s1len = s1.length(); + int s2len = s2.length(); + + while (count > 0 && s1off < s1len && s2off < s2len) { + if (Character.toLowerCase(s1.charAt(s1off)) != + Character.toLowerCase(s2.charAt(s2off))) + break; + s1off++; + s2off++; + count--; + } + + if (count == 0) { + result = true; + } + return result; + } + + private static double date_parseString(String s) { + double msec; + + int year = -1; + int mon = -1; + int mday = -1; + int hour = -1; + int min = -1; + int sec = -1; + char c = 0; + char si = 0; + int i = 0; + int n = -1; + double tzoffset = -1; + char prevc = 0; + int limit = 0; + boolean seenplusminus = false; + + if (s == null) // ??? Will s be null? + return Double.NaN; + limit = s.length(); + while (i < limit) { + c = s.charAt(i); + i++; + if (c <= ' ' || c == ',' || c == '-') { + if (i < limit) { + si = s.charAt(i); + if (c == '-' && '0' <= si && si <= '9') { + prevc = c; + } + } + continue; + } + if (c == '(') { /* comments) */ + int depth = 1; + while (i < limit) { + c = s.charAt(i); + i++; + if (c == '(') + depth++; + else if (c == ')') + if (--depth <= 0) + break; + } + continue; + } + if ('0' <= c && c <= '9') { + n = c - '0'; + while (i < limit && '0' <= (c = s.charAt(i)) && c <= '9') { + n = n * 10 + c - '0'; + i++; + } + + /* allow TZA before the year, so + * 'Wed Nov 05 21:49:11 GMT-0800 1997' + * works */ + + /* uses of seenplusminus allow : in TZA, so Java + * no-timezone style of GMT+4:30 works + */ + if ((prevc == '+' || prevc == '-')/* && year>=0 */) { + /* make ':' case below change tzoffset */ + seenplusminus = true; + + /* offset */ + if (n < 24) + n = n * 60; /* EG. "GMT-3" */ + else + n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */ + if (prevc == '+') /* plus means east of GMT */ + n = -n; + if (tzoffset != 0 && tzoffset != -1) + return Double.NaN; + tzoffset = n; + } else if (n >= 70 || + (prevc == '/' && mon >= 0 && mday >= 0 && year < 0)) { + if (year >= 0) + return Double.NaN; + else if (c <= ' ' || c == ',' || c == '/' || i >= limit) + year = n < 100 ? n + 1900 : n; + else + return Double.NaN; + } else if (c == ':') { + if (hour < 0) + hour = /*byte*/ n; + else if (min < 0) + min = /*byte*/ n; + else + return Double.NaN; + } else if (c == '/') { + if (mon < 0) + mon = /*byte*/ n-1; + else if (mday < 0) + mday = /*byte*/ n; + else + return Double.NaN; + } else if (i < limit && c != ',' && c > ' ' && c != '-') { + return Double.NaN; + } else if (seenplusminus && n < 60) { /* handle GMT-3:30 */ + if (tzoffset < 0) + tzoffset -= n; + else + tzoffset += n; + } else if (hour >= 0 && min < 0) { + min = /*byte*/ n; + } else if (min >= 0 && sec < 0) { + sec = /*byte*/ n; + } else if (mday < 0) { + mday = /*byte*/ n; + } else { + return Double.NaN; + } + prevc = 0; + } else if (c == '/' || c == ':' || c == '+' || c == '-') { + prevc = c; + } else { + int st = i - 1; + int k; + while (i < limit) { + c = s.charAt(i); + if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'))) + break; + i++; + } + if (i <= st + 1) + return Double.NaN; + for (k = wtb.length; --k >= 0;) + if (date_regionMatches(wtb[k], 0, s, st, i-st)) { + int action = ttb[k]; + if (action != 0) { + if (action < 0) { + /* + * AM/PM. Count 12:30 AM as 00:30, 12:30 PM as + * 12:30, instead of blindly adding 12 if PM. + */ + if (hour > 12 || hour < 0) { + return Double.NaN; + } else { + if (action == -1 && hour == 12) { // am + hour = 0; + } else if (action == -2 && hour != 12) {// pm + hour += 12; + } + } + } else if (action <= 13) { /* month! */ + if (mon < 0) { + mon = /*byte*/ (action - 2); + } else { + return Double.NaN; + } + } else { + tzoffset = action - 10000; + } + } + break; + } + if (k < 0) + return Double.NaN; + prevc = 0; + } + } + if (year < 0 || mon < 0 || mday < 0) + return Double.NaN; + if (sec < 0) + sec = 0; + if (min < 0) + min = 0; + if (hour < 0) + hour = 0; + if (tzoffset == -1) { /* no time zone specified, have to use local */ + double time; + time = date_msecFromDate(year, mon, mday, hour, min, sec, 0); + return internalUTC(time); + } + + msec = date_msecFromDate(year, mon, mday, hour, min, sec, 0); + msec += tzoffset * msPerMinute; + return msec; + } + + private static double jsStaticFunction_parse(String s) { + return date_parseString(s); + } + + private static final int FORMATSPEC_FULL = 0; + private static final int FORMATSPEC_DATE = 1; + private static final int FORMATSPEC_TIME = 2; + + private static String date_format(double t, int format) { + if (t != t) + return jsFunction_NaN_date_str; + + StringBuffer result = new StringBuffer(60); + double local = LocalTime(t); + + /* offset from GMT in minutes. The offset includes daylight savings, + if it applies. */ + int minutes = (int) java.lang.Math.floor((LocalTZA + DaylightSavingTA(t)) + / msPerMinute); + /* map 510 minutes to 0830 hours */ + int offset = (minutes / 60) * 100 + minutes % 60; + + String dateStr = Integer.toString(DateFromTime(local)); + String hourStr = Integer.toString(HourFromTime(local)); + String minStr = Integer.toString(MinFromTime(local)); + String secStr = Integer.toString(SecFromTime(local)); + String offsetStr = Integer.toString(offset > 0 ? offset : -offset); + int year = YearFromTime(local); + String yearStr = Integer.toString(year > 0 ? year : -year); + + /* Tue Oct 31 09:41:40 GMT-0800 (PST) 2000 */ + /* Tue Oct 31 2000 */ + /* 09:41:40 GMT-0800 (PST) */ + + if (format != FORMATSPEC_TIME) { + result.append(days[WeekDay(local)]); + result.append(' '); + result.append(months[MonthFromTime(local)]); + if (dateStr.length() == 1) + result.append(" 0"); + else + result.append(' '); + result.append(dateStr); + result.append(' '); + } + + if (format != FORMATSPEC_DATE) { + if (hourStr.length() == 1) + result.append('0'); + result.append(hourStr); + if (minStr.length() == 1) + result.append(":0"); + else + result.append(':'); + result.append(minStr); + if (secStr.length() == 1) + result.append(":0"); + else + result.append(':'); + result.append(secStr); + if (offset > 0) + result.append(" GMT+"); + else + result.append(" GMT-"); + for (int i = offsetStr.length(); i < 4; i++) + result.append('0'); + result.append(offsetStr); + + if (timeZoneFormatter == null) + timeZoneFormatter = new java.text.SimpleDateFormat("zzz"); + + if (timeZoneFormatter != null) { + result.append(" ("); + java.util.Date date = new java.util.Date((long) t); + result.append(timeZoneFormatter.format(date)); + result.append(')'); + } + if (format != FORMATSPEC_TIME) + result.append(' '); + } + + if (format != FORMATSPEC_TIME) { + if (year < 0) + result.append('-'); + for (int i = yearStr.length(); i < 4; i++) + result.append('0'); + result.append(yearStr); + } + + return result.toString(); + } + + private static double _toNumber(Object o) { return JS.toDouble(o); } + private static double _toNumber(Object[] o, int index) { return JS.toDouble(o[index]); } + private static double toDouble(double d) { return d; } + + public Date(JS.Array args_) { + Object[] args = new Object[args_.length()]; + for(int i=0; i= 0 && array[0] <= 99) + array[0] += 1900; + + /* if we got a 0 for 'date' (which is out of range) + * pretend it's a 1 */ + if (array[2] < 1) + array[2] = 1; + + double day = MakeDay(array[0], array[1], array[2]); + double time = MakeTime(array[3], array[4], array[5], array[6]); + time = MakeDate(day, time); + time = internalUTC(time); + obj.date = TimeClip(time); + + return; + } + + /* constants for toString, toUTCString */ + private static String jsFunction_NaN_date_str = "Invalid Date"; + + private static String[] days = { + "Sun","Mon","Tue","Wed","Thu","Fri","Sat" + }; + + private static String[] months = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; + + private static String toLocale_helper(double t, + java.text.DateFormat formatter) + { + if (t != t) + return jsFunction_NaN_date_str; + + java.util.Date tempdate = new java.util.Date((long) t); + return formatter.format(tempdate); + } + + private static String jsFunction_toLocaleString(double date) { + if (localeDateTimeFormatter == null) + localeDateTimeFormatter = + DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG); + + return toLocale_helper(date, localeDateTimeFormatter); + } + + private static String jsFunction_toLocaleTimeString(double date) { + if (localeTimeFormatter == null) + localeTimeFormatter = DateFormat.getTimeInstance(DateFormat.LONG); + + return toLocale_helper(date, localeTimeFormatter); + } + + private static String jsFunction_toLocaleDateString(double date) { + if (localeDateFormatter == null) + localeDateFormatter = DateFormat.getDateInstance(DateFormat.LONG); + + return toLocale_helper(date, localeDateFormatter); + } + + private static String jsFunction_toUTCString(double date) { + StringBuffer result = new StringBuffer(60); + + String dateStr = Integer.toString(DateFromTime(date)); + String hourStr = Integer.toString(HourFromTime(date)); + String minStr = Integer.toString(MinFromTime(date)); + String secStr = Integer.toString(SecFromTime(date)); + int year = YearFromTime(date); + String yearStr = Integer.toString(year > 0 ? year : -year); + + result.append(days[WeekDay(date)]); + result.append(", "); + if (dateStr.length() == 1) + result.append('0'); + result.append(dateStr); + result.append(' '); + result.append(months[MonthFromTime(date)]); + if (year < 0) + result.append(" -"); + else + result.append(' '); + int i; + for (i = yearStr.length(); i < 4; i++) + result.append('0'); + result.append(yearStr); + + if (hourStr.length() == 1) + result.append(" 0"); + else + result.append(' '); + result.append(hourStr); + if (minStr.length() == 1) + result.append(":0"); + else + result.append(':'); + result.append(minStr); + if (secStr.length() == 1) + result.append(":0"); + else + result.append(':'); + result.append(secStr); + + result.append(" GMT"); + return result.toString(); + } + + private static double jsFunction_getYear(double date) { + int result = YearFromTime(LocalTime(date)); + result -= 1900; + return result; + } + + private static double jsFunction_getTimezoneOffset(double date) { + return (date - LocalTime(date)) / msPerMinute; + } + + public double jsFunction_setTime(double time) { + this.date = TimeClip(time); + return this.date; + } + + private double makeTime(Object[] args, int maxargs, boolean local) { + int i; + double conv[] = new double[4]; + double hour, min, sec, msec; + double lorutime; /* Local or UTC version of date */ + + double time; + double result; + + double date = this.date; + + /* just return NaN if the date is already NaN */ + if (date != date) + return date; + + /* Satisfy the ECMA rule that if a function is called with + * fewer arguments than the specified formal arguments, the + * remaining arguments are set to undefined. Seems like all + * the Date.setWhatever functions in ECMA are only varargs + * beyond the first argument; this should be set to undefined + * if it's not given. This means that "d = new Date(); + * d.setMilliseconds()" returns NaN. Blech. + */ + if (args.length == 0) + args = new Object[] { null }; + + for (i = 0; i < args.length && i < maxargs; i++) { + conv[i] = _toNumber(args[i]); + + // limit checks that happen in MakeTime in ECMA. + if (conv[i] != conv[i] || Double.isInfinite(conv[i])) { + this.date = Double.NaN; + return this.date; + } + conv[i] = toDouble(conv[i]); + } + + if (local) + lorutime = LocalTime(date); + else + lorutime = date; + + i = 0; + int stop = args.length; + + if (maxargs >= 4 && i < stop) + hour = conv[i++]; + else + hour = HourFromTime(lorutime); + + if (maxargs >= 3 && i < stop) + min = conv[i++]; + else + min = MinFromTime(lorutime); + + if (maxargs >= 2 && i < stop) + sec = conv[i++]; + else + sec = SecFromTime(lorutime); + + if (maxargs >= 1 && i < stop) + msec = conv[i++]; + else + msec = msFromTime(lorutime); + + time = MakeTime(hour, min, sec, msec); + result = MakeDate(Day(lorutime), time); + + if (local) + result = internalUTC(result); + date = TimeClip(result); + + this.date = date; + return date; + } + + private double jsFunction_setHours(Object[] args) { + return makeTime(args, 4, true); + } + + private double jsFunction_setUTCHours(Object[] args) { + return makeTime(args, 4, false); + } + + private double makeDate(Object[] args, int maxargs, boolean local) { + int i; + double conv[] = new double[3]; + double year, month, day; + double lorutime; /* local or UTC version of date */ + double result; + + double date = this.date; + + /* See arg padding comment in makeTime.*/ + if (args.length == 0) + args = new Object[] { null }; + + for (i = 0; i < args.length && i < maxargs; i++) { + conv[i] = _toNumber(args[i]); + + // limit checks that happen in MakeDate in ECMA. + if (conv[i] != conv[i] || Double.isInfinite(conv[i])) { + this.date = Double.NaN; + return this.date; + } + conv[i] = toDouble(conv[i]); + } + + /* return NaN if date is NaN and we're not setting the year, + * If we are, use 0 as the time. */ + if (date != date) { + if (args.length < 3) { + return Double.NaN; + } else { + lorutime = 0; + } + } else { + if (local) + lorutime = LocalTime(date); + else + lorutime = date; + } + + i = 0; + int stop = args.length; + + if (maxargs >= 3 && i < stop) + year = conv[i++]; + else + year = YearFromTime(lorutime); + + if (maxargs >= 2 && i < stop) + month = conv[i++]; + else + month = MonthFromTime(lorutime); + + if (maxargs >= 1 && i < stop) + day = conv[i++]; + else + day = DateFromTime(lorutime); + + day = MakeDay(year, month, day); /* day within year */ + result = MakeDate(day, TimeWithinDay(lorutime)); + + if (local) + result = internalUTC(result); + + date = TimeClip(result); + + this.date = date; + return date; + } + + private double jsFunction_setYear(double year) { + double day, result; + if (year != year || Double.isInfinite(year)) { + this.date = Double.NaN; + return this.date; + } + + if (this.date != this.date) { + this.date = 0; + } else { + this.date = LocalTime(this.date); + } + + if (year >= 0 && year <= 99) + year += 1900; + + day = MakeDay(year, MonthFromTime(this.date), DateFromTime(this.date)); + result = MakeDate(day, TimeWithinDay(this.date)); + result = internalUTC(result); + + this.date = TimeClip(result); + return this.date; + } + + protected String getIdName(int id) { + switch (id) { + case ConstructorId_UTC: return "UTC"; + case ConstructorId_parse: return "parse"; + case Id_constructor: return "constructor"; + case Id_toString: return "toString"; + case Id_toTimeString: return "toTimeString"; + case Id_toDateString: return "toDateString"; + case Id_toLocaleString: return "toLocaleString"; + case Id_toLocaleTimeString: return "toLocaleTimeString"; + case Id_toLocaleDateString: return "toLocaleDateString"; + case Id_toUTCString: return "toUTCString"; + case Id_valueOf: return "valueOf"; + case Id_getTime: return "getTime"; + case Id_getYear: return "getYear"; + case Id_getFullYear: return "getFullYear"; + case Id_getUTCFullYear: return "getUTCFullYear"; + case Id_getMonth: return "getMonth"; + case Id_getUTCMonth: return "getUTCMonth"; + case Id_getDate: return "getDate"; + case Id_getUTCDate: return "getUTCDate"; + case Id_getDay: return "getDay"; + case Id_getUTCDay: return "getUTCDay"; + case Id_getHours: return "getHours"; + case Id_getUTCHours: return "getUTCHours"; + case Id_getMinutes: return "getMinutes"; + case Id_getUTCMinutes: return "getUTCMinutes"; + case Id_getSeconds: return "getSeconds"; + case Id_getUTCSeconds: return "getUTCSeconds"; + case Id_getMilliseconds: return "getMilliseconds"; + case Id_getUTCMilliseconds: return "getUTCMilliseconds"; + case Id_getTimezoneOffset: return "getTimezoneOffset"; + case Id_setTime: return "setTime"; + case Id_setMilliseconds: return "setMilliseconds"; + case Id_setUTCMilliseconds: return "setUTCMilliseconds"; + case Id_setSeconds: return "setSeconds"; + case Id_setUTCSeconds: return "setUTCSeconds"; + case Id_setMinutes: return "setMinutes"; + case Id_setUTCMinutes: return "setUTCMinutes"; + case Id_setHours: return "setHours"; + case Id_setUTCHours: return "setUTCHours"; + case Id_setDate: return "setDate"; + case Id_setUTCDate: return "setUTCDate"; + case Id_setMonth: return "setMonth"; + case Id_setUTCMonth: return "setUTCMonth"; + case Id_setFullYear: return "setFullYear"; + case Id_setUTCFullYear: return "setUTCFullYear"; + case Id_setYear: return "setYear"; + } + return null; + } + +// #string_id_map# + + protected int mapNameToId(String s) { + int id; +// #generated# Last update: 2001-04-22 23:46:59 CEST + L0: { id = 0; String X = null; int c; + L: switch (s.length()) { + case 6: X="getDay";id=Id_getDay; break L; + case 7: switch (s.charAt(3)) { + case 'D': c=s.charAt(0); + if (c=='g') { X="getDate";id=Id_getDate; } + else if (c=='s') { X="setDate";id=Id_setDate; } + break L; + case 'T': c=s.charAt(0); + if (c=='g') { X="getTime";id=Id_getTime; } + else if (c=='s') { X="setTime";id=Id_setTime; } + break L; + case 'Y': c=s.charAt(0); + if (c=='g') { X="getYear";id=Id_getYear; } + else if (c=='s') { X="setYear";id=Id_setYear; } + break L; + case 'u': X="valueOf";id=Id_valueOf; break L; + } break L; + case 8: c=s.charAt(0); + if (c=='g') { + c=s.charAt(7); + if (c=='h') { X="getMonth";id=Id_getMonth; } + else if (c=='s') { X="getHours";id=Id_getHours; } + } + else if (c=='s') { + c=s.charAt(7); + if (c=='h') { X="setMonth";id=Id_setMonth; } + else if (c=='s') { X="setHours";id=Id_setHours; } + } + else if (c=='t') { X="toString";id=Id_toString; } + break L; + case 9: X="getUTCDay";id=Id_getUTCDay; break L; + case 10: c=s.charAt(3); + if (c=='M') { + c=s.charAt(0); + if (c=='g') { X="getMinutes";id=Id_getMinutes; } + else if (c=='s') { X="setMinutes";id=Id_setMinutes; } + } + else if (c=='S') { + c=s.charAt(0); + if (c=='g') { X="getSeconds";id=Id_getSeconds; } + else if (c=='s') { X="setSeconds";id=Id_setSeconds; } + } + else if (c=='U') { + c=s.charAt(0); + if (c=='g') { X="getUTCDate";id=Id_getUTCDate; } + else if (c=='s') { X="setUTCDate";id=Id_setUTCDate; } + } + break L; + case 11: switch (s.charAt(3)) { + case 'F': c=s.charAt(0); + if (c=='g') { X="getFullYear";id=Id_getFullYear; } + else if (c=='s') { X="setFullYear";id=Id_setFullYear; } + break L; + case 'M': X="toGMTString";id=Id_toGMTString; break L; + case 'T': X="toUTCString";id=Id_toUTCString; break L; + case 'U': c=s.charAt(0); + if (c=='g') { + c=s.charAt(9); + if (c=='r') { X="getUTCHours";id=Id_getUTCHours; } + else if (c=='t') { X="getUTCMonth";id=Id_getUTCMonth; } + } + else if (c=='s') { + c=s.charAt(9); + if (c=='r') { X="setUTCHours";id=Id_setUTCHours; } + else if (c=='t') { X="setUTCMonth";id=Id_setUTCMonth; } + } + break L; + case 's': X="constructor";id=Id_constructor; break L; + } break L; + case 12: c=s.charAt(2); + if (c=='D') { X="toDateString";id=Id_toDateString; } + else if (c=='T') { X="toTimeString";id=Id_toTimeString; } + break L; + case 13: c=s.charAt(0); + if (c=='g') { + c=s.charAt(6); + if (c=='M') { X="getUTCMinutes";id=Id_getUTCMinutes; } + else if (c=='S') { X="getUTCSeconds";id=Id_getUTCSeconds; } + } + else if (c=='s') { + c=s.charAt(6); + if (c=='M') { X="setUTCMinutes";id=Id_setUTCMinutes; } + else if (c=='S') { X="setUTCSeconds";id=Id_setUTCSeconds; } + } + break L; + case 14: c=s.charAt(0); + if (c=='g') { X="getUTCFullYear";id=Id_getUTCFullYear; } + else if (c=='s') { X="setUTCFullYear";id=Id_setUTCFullYear; } + else if (c=='t') { X="toLocaleString";id=Id_toLocaleString; } + break L; + case 15: c=s.charAt(0); + if (c=='g') { X="getMilliseconds";id=Id_getMilliseconds; } + else if (c=='s') { X="setMilliseconds";id=Id_setMilliseconds; } + break L; + case 17: X="getTimezoneOffset";id=Id_getTimezoneOffset; break L; + case 18: c=s.charAt(0); + if (c=='g') { X="getUTCMilliseconds";id=Id_getUTCMilliseconds; } + else if (c=='s') { X="setUTCMilliseconds";id=Id_setUTCMilliseconds; } + else if (c=='t') { + c=s.charAt(8); + if (c=='D') { X="toLocaleDateString";id=Id_toLocaleDateString; } + else if (c=='T') { X="toLocaleTimeString";id=Id_toLocaleTimeString; } + } + break L; + } + if (X!=null && X!=s && !X.equals(s)) id = 0; + } +// #/generated# + return id; + } + + private static final int + ConstructorId_UTC = -2, + ConstructorId_parse = -1, + + Id_constructor = 1, + Id_toString = 2, + Id_toTimeString = 3, + Id_toDateString = 4, + Id_toLocaleString = 5, + Id_toLocaleTimeString = 6, + Id_toLocaleDateString = 7, + Id_toUTCString = 8, + Id_valueOf = 9, + Id_getTime = 10, + Id_getYear = 11, + Id_getFullYear = 12, + Id_getUTCFullYear = 13, + Id_getMonth = 14, + Id_getUTCMonth = 15, + Id_getDate = 16, + Id_getUTCDate = 17, + Id_getDay = 18, + Id_getUTCDay = 19, + Id_getHours = 20, + Id_getUTCHours = 21, + Id_getMinutes = 22, + Id_getUTCMinutes = 23, + Id_getSeconds = 24, + Id_getUTCSeconds = 25, + Id_getMilliseconds = 26, + Id_getUTCMilliseconds = 27, + Id_getTimezoneOffset = 28, + Id_setTime = 29, + Id_setMilliseconds = 30, + Id_setUTCMilliseconds = 31, + Id_setSeconds = 32, + Id_setUTCSeconds = 33, + Id_setMinutes = 34, + Id_setUTCMinutes = 35, + Id_setHours = 36, + Id_setUTCHours = 37, + Id_setDate = 38, + Id_setUTCDate = 39, + Id_setMonth = 40, + Id_setUTCMonth = 41, + Id_setFullYear = 42, + Id_setUTCFullYear = 43, + Id_setYear = 44, + + MAX_PROTOTYPE_ID = 44; + + private static final int + Id_toGMTString = Id_toUTCString; // Alias, see Ecma B.2.6 +// #/string_id_map# + + /* cached values */ + private static java.util.TimeZone thisTimeZone; + private static double LocalTZA; + private static java.text.DateFormat timeZoneFormatter; + private static java.text.DateFormat localeDateTimeFormatter; + private static java.text.DateFormat localeDateFormatter; + private static java.text.DateFormat localeTimeFormatter; + + private double date; + + public long getRawTime() { return (long)this.date; } } + + diff --git a/src/org/xwt/util/Log.java b/src/org/xwt/util/Log.java index 4782b9f..05ee8d3 100644 --- a/src/org/xwt/util/Log.java +++ b/src/org/xwt/util/Log.java @@ -1,6 +1,6 @@ // Copyright 2003 Adam Megacz, see the COPYING file for licensing [LGPL] package org.xwt.util; -import org.xwt.js.*; +import org.xwt.js.JS; import java.io.*; import java.util.*; -- 1.7.10.4