0001: /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
0002: *
0003: * ***** BEGIN LICENSE BLOCK *****
0004: * Version: MPL 1.1/GPL 2.0
0005: *
0006: * The contents of this file are subject to the Mozilla Public License Version
0007: * 1.1 (the "License"); you may not use this file except in compliance with
0008: * the License. You may obtain a copy of the License at
0009: * http://www.mozilla.org/MPL/
0010: *
0011: * Software distributed under the License is distributed on an "AS IS" basis,
0012: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0013: * for the specific language governing rights and limitations under the
0014: * License.
0015: *
0016: * The Original Code is Rhino code, released
0017: * May 6, 1999.
0018: *
0019: * The Initial Developer of the Original Code is
0020: * Netscape Communications Corporation.
0021: * Portions created by the Initial Developer are Copyright (C) 1997-1999
0022: * the Initial Developer. All Rights Reserved.
0023: *
0024: * Contributor(s):
0025: * Peter Annema
0026: * Norris Boyd
0027: * Mike McCabe
0028: * Ilya Frank
0029: *
0030: *
0031: * Alternatively, the contents of this file may be used under the terms of
0032: * the GNU General Public License Version 2 or later (the "GPL"), in which
0033: * case the provisions of the GPL are applicable instead of those above. If
0034: * you wish to allow use of your version of this file only under the terms of
0035: * the GPL and not to allow others to use your version of this file under the
0036: * MPL, indicate your decision by deleting the provisions above and replacing
0037: * them with the notice and other provisions required by the GPL. If you do
0038: * not delete the provisions above, a recipient may use your version of this
0039: * file under either the MPL or the GPL.
0040: *
0041: * ***** END LICENSE BLOCK ***** */
0042:
0043: package org.mozilla.javascript;
0044:
0045: import java.util.Date;
0046: import java.text.DateFormat;
0047:
0048: /**
0049: * This class implements the Date native object.
0050: * See ECMA 15.9.
0051: * @author Mike McCabe
0052: */
0053: final class NativeDate extends IdScriptableObject {
0054: static final long serialVersionUID = -8307438915861678966L;
0055:
0056: private static final Object DATE_TAG = new Object();
0057:
0058: private static final String js_NaN_date_str = "Invalid Date";
0059:
0060: static void init(Scriptable scope, boolean sealed) {
0061: NativeDate obj = new NativeDate();
0062: // Set the value of the prototype Date to NaN ('invalid date');
0063: obj.date = ScriptRuntime.NaN;
0064: obj.exportAsJSClass(MAX_PROTOTYPE_ID, scope, sealed);
0065: }
0066:
0067: private NativeDate() {
0068: if (this TimeZone == null) {
0069: // j.u.TimeZone is synchronized, so setting class statics from it
0070: // should be OK.
0071: this TimeZone = java.util.TimeZone.getDefault();
0072: LocalTZA = this TimeZone.getRawOffset();
0073: }
0074: }
0075:
0076: public String getClassName() {
0077: return "Date";
0078: }
0079:
0080: public Object getDefaultValue(Class typeHint) {
0081: if (typeHint == null)
0082: typeHint = ScriptRuntime.StringClass;
0083: return super .getDefaultValue(typeHint);
0084: }
0085:
0086: double getJSTimeValue() {
0087: return date;
0088: }
0089:
0090: protected void fillConstructorProperties(IdFunctionObject ctor) {
0091: addIdFunctionProperty(ctor, DATE_TAG, ConstructorId_now, "now",
0092: 0);
0093: addIdFunctionProperty(ctor, DATE_TAG, ConstructorId_parse,
0094: "parse", 1);
0095: addIdFunctionProperty(ctor, DATE_TAG, ConstructorId_UTC, "UTC",
0096: 1);
0097: super .fillConstructorProperties(ctor);
0098: }
0099:
0100: protected void initPrototypeId(int id) {
0101: String s;
0102: int arity;
0103: switch (id) {
0104: case Id_constructor:
0105: arity = 1;
0106: s = "constructor";
0107: break;
0108: case Id_toString:
0109: arity = 0;
0110: s = "toString";
0111: break;
0112: case Id_toTimeString:
0113: arity = 0;
0114: s = "toTimeString";
0115: break;
0116: case Id_toDateString:
0117: arity = 0;
0118: s = "toDateString";
0119: break;
0120: case Id_toLocaleString:
0121: arity = 0;
0122: s = "toLocaleString";
0123: break;
0124: case Id_toLocaleTimeString:
0125: arity = 0;
0126: s = "toLocaleTimeString";
0127: break;
0128: case Id_toLocaleDateString:
0129: arity = 0;
0130: s = "toLocaleDateString";
0131: break;
0132: case Id_toUTCString:
0133: arity = 0;
0134: s = "toUTCString";
0135: break;
0136: case Id_toSource:
0137: arity = 0;
0138: s = "toSource";
0139: break;
0140: case Id_valueOf:
0141: arity = 0;
0142: s = "valueOf";
0143: break;
0144: case Id_getTime:
0145: arity = 0;
0146: s = "getTime";
0147: break;
0148: case Id_getYear:
0149: arity = 0;
0150: s = "getYear";
0151: break;
0152: case Id_getFullYear:
0153: arity = 0;
0154: s = "getFullYear";
0155: break;
0156: case Id_getUTCFullYear:
0157: arity = 0;
0158: s = "getUTCFullYear";
0159: break;
0160: case Id_getMonth:
0161: arity = 0;
0162: s = "getMonth";
0163: break;
0164: case Id_getUTCMonth:
0165: arity = 0;
0166: s = "getUTCMonth";
0167: break;
0168: case Id_getDate:
0169: arity = 0;
0170: s = "getDate";
0171: break;
0172: case Id_getUTCDate:
0173: arity = 0;
0174: s = "getUTCDate";
0175: break;
0176: case Id_getDay:
0177: arity = 0;
0178: s = "getDay";
0179: break;
0180: case Id_getUTCDay:
0181: arity = 0;
0182: s = "getUTCDay";
0183: break;
0184: case Id_getHours:
0185: arity = 0;
0186: s = "getHours";
0187: break;
0188: case Id_getUTCHours:
0189: arity = 0;
0190: s = "getUTCHours";
0191: break;
0192: case Id_getMinutes:
0193: arity = 0;
0194: s = "getMinutes";
0195: break;
0196: case Id_getUTCMinutes:
0197: arity = 0;
0198: s = "getUTCMinutes";
0199: break;
0200: case Id_getSeconds:
0201: arity = 0;
0202: s = "getSeconds";
0203: break;
0204: case Id_getUTCSeconds:
0205: arity = 0;
0206: s = "getUTCSeconds";
0207: break;
0208: case Id_getMilliseconds:
0209: arity = 0;
0210: s = "getMilliseconds";
0211: break;
0212: case Id_getUTCMilliseconds:
0213: arity = 0;
0214: s = "getUTCMilliseconds";
0215: break;
0216: case Id_getTimezoneOffset:
0217: arity = 0;
0218: s = "getTimezoneOffset";
0219: break;
0220: case Id_setTime:
0221: arity = 1;
0222: s = "setTime";
0223: break;
0224: case Id_setMilliseconds:
0225: arity = 1;
0226: s = "setMilliseconds";
0227: break;
0228: case Id_setUTCMilliseconds:
0229: arity = 1;
0230: s = "setUTCMilliseconds";
0231: break;
0232: case Id_setSeconds:
0233: arity = 2;
0234: s = "setSeconds";
0235: break;
0236: case Id_setUTCSeconds:
0237: arity = 2;
0238: s = "setUTCSeconds";
0239: break;
0240: case Id_setMinutes:
0241: arity = 3;
0242: s = "setMinutes";
0243: break;
0244: case Id_setUTCMinutes:
0245: arity = 3;
0246: s = "setUTCMinutes";
0247: break;
0248: case Id_setHours:
0249: arity = 4;
0250: s = "setHours";
0251: break;
0252: case Id_setUTCHours:
0253: arity = 4;
0254: s = "setUTCHours";
0255: break;
0256: case Id_setDate:
0257: arity = 1;
0258: s = "setDate";
0259: break;
0260: case Id_setUTCDate:
0261: arity = 1;
0262: s = "setUTCDate";
0263: break;
0264: case Id_setMonth:
0265: arity = 2;
0266: s = "setMonth";
0267: break;
0268: case Id_setUTCMonth:
0269: arity = 2;
0270: s = "setUTCMonth";
0271: break;
0272: case Id_setFullYear:
0273: arity = 3;
0274: s = "setFullYear";
0275: break;
0276: case Id_setUTCFullYear:
0277: arity = 3;
0278: s = "setUTCFullYear";
0279: break;
0280: case Id_setYear:
0281: arity = 1;
0282: s = "setYear";
0283: break;
0284: default:
0285: throw new IllegalArgumentException(String.valueOf(id));
0286: }
0287: initPrototypeMethod(DATE_TAG, id, s, arity);
0288: }
0289:
0290: public Object execIdCall(IdFunctionObject f, Context cx,
0291: Scriptable scope, Scriptable this Obj, Object[] args) {
0292: if (!f.hasTag(DATE_TAG)) {
0293: return super .execIdCall(f, cx, scope, this Obj, args);
0294: }
0295: int id = f.methodId();
0296: switch (id) {
0297: case ConstructorId_now:
0298: return ScriptRuntime.wrapNumber(now());
0299:
0300: case ConstructorId_parse: {
0301: String dataStr = ScriptRuntime.toString(args, 0);
0302: return ScriptRuntime.wrapNumber(date_parseString(dataStr));
0303: }
0304:
0305: case ConstructorId_UTC:
0306: return ScriptRuntime.wrapNumber(jsStaticFunction_UTC(args));
0307:
0308: case Id_constructor: {
0309: // if called as a function, just return a string
0310: // representing the current time.
0311: if (this Obj != null)
0312: return date_format(now(), Id_toString);
0313: return jsConstructor(args);
0314: }
0315: }
0316:
0317: // The rest of Date.prototype methods require thisObj to be Date
0318:
0319: if (!(this Obj instanceof NativeDate))
0320: throw incompatibleCallError(f);
0321: NativeDate realThis = (NativeDate) this Obj;
0322: double t = realThis.date;
0323:
0324: switch (id) {
0325:
0326: case Id_toString:
0327: case Id_toTimeString:
0328: case Id_toDateString:
0329: if (t == t) {
0330: return date_format(t, id);
0331: }
0332: return js_NaN_date_str;
0333:
0334: case Id_toLocaleString:
0335: case Id_toLocaleTimeString:
0336: case Id_toLocaleDateString:
0337: if (t == t) {
0338: return toLocale_helper(t, id);
0339: }
0340: return js_NaN_date_str;
0341:
0342: case Id_toUTCString:
0343: if (t == t) {
0344: return js_toUTCString(t);
0345: }
0346: return js_NaN_date_str;
0347:
0348: case Id_toSource:
0349: return "(new Date(" + ScriptRuntime.toString(t) + "))";
0350:
0351: case Id_valueOf:
0352: case Id_getTime:
0353: return ScriptRuntime.wrapNumber(t);
0354:
0355: case Id_getYear:
0356: case Id_getFullYear:
0357: case Id_getUTCFullYear:
0358: if (t == t) {
0359: if (id != Id_getUTCFullYear)
0360: t = LocalTime(t);
0361: t = YearFromTime(t);
0362: if (id == Id_getYear) {
0363: if (cx
0364: .hasFeature(Context.FEATURE_NON_ECMA_GET_YEAR)) {
0365: if (1900 <= t && t < 2000) {
0366: t -= 1900;
0367: }
0368: } else {
0369: t -= 1900;
0370: }
0371: }
0372: }
0373: return ScriptRuntime.wrapNumber(t);
0374:
0375: case Id_getMonth:
0376: case Id_getUTCMonth:
0377: if (t == t) {
0378: if (id == Id_getMonth)
0379: t = LocalTime(t);
0380: t = MonthFromTime(t);
0381: }
0382: return ScriptRuntime.wrapNumber(t);
0383:
0384: case Id_getDate:
0385: case Id_getUTCDate:
0386: if (t == t) {
0387: if (id == Id_getDate)
0388: t = LocalTime(t);
0389: t = DateFromTime(t);
0390: }
0391: return ScriptRuntime.wrapNumber(t);
0392:
0393: case Id_getDay:
0394: case Id_getUTCDay:
0395: if (t == t) {
0396: if (id == Id_getDay)
0397: t = LocalTime(t);
0398: t = WeekDay(t);
0399: }
0400: return ScriptRuntime.wrapNumber(t);
0401:
0402: case Id_getHours:
0403: case Id_getUTCHours:
0404: if (t == t) {
0405: if (id == Id_getHours)
0406: t = LocalTime(t);
0407: t = HourFromTime(t);
0408: }
0409: return ScriptRuntime.wrapNumber(t);
0410:
0411: case Id_getMinutes:
0412: case Id_getUTCMinutes:
0413: if (t == t) {
0414: if (id == Id_getMinutes)
0415: t = LocalTime(t);
0416: t = MinFromTime(t);
0417: }
0418: return ScriptRuntime.wrapNumber(t);
0419:
0420: case Id_getSeconds:
0421: case Id_getUTCSeconds:
0422: if (t == t) {
0423: if (id == Id_getSeconds)
0424: t = LocalTime(t);
0425: t = SecFromTime(t);
0426: }
0427: return ScriptRuntime.wrapNumber(t);
0428:
0429: case Id_getMilliseconds:
0430: case Id_getUTCMilliseconds:
0431: if (t == t) {
0432: if (id == Id_getMilliseconds)
0433: t = LocalTime(t);
0434: t = msFromTime(t);
0435: }
0436: return ScriptRuntime.wrapNumber(t);
0437:
0438: case Id_getTimezoneOffset:
0439: if (t == t) {
0440: t = (t - LocalTime(t)) / msPerMinute;
0441: }
0442: return ScriptRuntime.wrapNumber(t);
0443:
0444: case Id_setTime:
0445: t = TimeClip(ScriptRuntime.toNumber(args, 0));
0446: realThis.date = t;
0447: return ScriptRuntime.wrapNumber(t);
0448:
0449: case Id_setMilliseconds:
0450: case Id_setUTCMilliseconds:
0451: case Id_setSeconds:
0452: case Id_setUTCSeconds:
0453: case Id_setMinutes:
0454: case Id_setUTCMinutes:
0455: case Id_setHours:
0456: case Id_setUTCHours:
0457: t = makeTime(t, args, id);
0458: realThis.date = t;
0459: return ScriptRuntime.wrapNumber(t);
0460:
0461: case Id_setDate:
0462: case Id_setUTCDate:
0463: case Id_setMonth:
0464: case Id_setUTCMonth:
0465: case Id_setFullYear:
0466: case Id_setUTCFullYear:
0467: t = makeDate(t, args, id);
0468: realThis.date = t;
0469: return ScriptRuntime.wrapNumber(t);
0470:
0471: case Id_setYear: {
0472: double year = ScriptRuntime.toNumber(args, 0);
0473:
0474: if (year != year || Double.isInfinite(year)) {
0475: t = ScriptRuntime.NaN;
0476: } else {
0477: if (t != t) {
0478: t = 0;
0479: } else {
0480: t = LocalTime(t);
0481: }
0482:
0483: if (year >= 0 && year <= 99)
0484: year += 1900;
0485:
0486: double day = MakeDay(year, MonthFromTime(t),
0487: DateFromTime(t));
0488: t = MakeDate(day, TimeWithinDay(t));
0489: t = internalUTC(t);
0490: t = TimeClip(t);
0491: }
0492: }
0493: realThis.date = t;
0494: return ScriptRuntime.wrapNumber(t);
0495:
0496: default:
0497: throw new IllegalArgumentException(String.valueOf(id));
0498: }
0499:
0500: }
0501:
0502: /* ECMA helper functions */
0503:
0504: private static final double HalfTimeDomain = 8.64e15;
0505: private static final double HoursPerDay = 24.0;
0506: private static final double MinutesPerHour = 60.0;
0507: private static final double SecondsPerMinute = 60.0;
0508: private static final double msPerSecond = 1000.0;
0509: private static final double MinutesPerDay = (HoursPerDay * MinutesPerHour);
0510: private static final double SecondsPerDay = (MinutesPerDay * SecondsPerMinute);
0511: private static final double SecondsPerHour = (MinutesPerHour * SecondsPerMinute);
0512: private static final double msPerDay = (SecondsPerDay * msPerSecond);
0513: private static final double msPerHour = (SecondsPerHour * msPerSecond);
0514: private static final double msPerMinute = (SecondsPerMinute * msPerSecond);
0515:
0516: private static double Day(double t) {
0517: return Math.floor(t / msPerDay);
0518: }
0519:
0520: private static double TimeWithinDay(double t) {
0521: double result;
0522: result = t % msPerDay;
0523: if (result < 0)
0524: result += msPerDay;
0525: return result;
0526: }
0527:
0528: private static boolean IsLeapYear(int year) {
0529: return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
0530: }
0531:
0532: /* math here has to be f.p, because we need
0533: * floor((1968 - 1969) / 4) == -1
0534: */
0535: private static double DayFromYear(double y) {
0536: return ((365 * ((y) - 1970) + Math.floor(((y) - 1969) / 4.0)
0537: - Math.floor(((y) - 1901) / 100.0) + Math
0538: .floor(((y) - 1601) / 400.0)));
0539: }
0540:
0541: private static double TimeFromYear(double y) {
0542: return DayFromYear(y) * msPerDay;
0543: }
0544:
0545: private static int YearFromTime(double t) {
0546: int lo = (int) Math.floor((t / msPerDay) / 366) + 1970;
0547: int hi = (int) Math.floor((t / msPerDay) / 365) + 1970;
0548: int mid;
0549:
0550: /* above doesn't work for negative dates... */
0551: if (hi < lo) {
0552: int temp = lo;
0553: lo = hi;
0554: hi = temp;
0555: }
0556:
0557: /* Use a simple binary search algorithm to find the right
0558: year. This seems like brute force... but the computation
0559: of hi and lo years above lands within one year of the
0560: correct answer for years within a thousand years of
0561: 1970; the loop below only requires six iterations
0562: for year 270000. */
0563: while (hi > lo) {
0564: mid = (hi + lo) / 2;
0565: if (TimeFromYear(mid) > t) {
0566: hi = mid - 1;
0567: } else {
0568: lo = mid + 1;
0569: if (TimeFromYear(lo) > t) {
0570: return mid;
0571: }
0572: }
0573: }
0574: return lo;
0575: }
0576:
0577: private static double DayFromMonth(int m, int year) {
0578: int day = m * 30;
0579:
0580: if (m >= 7) {
0581: day += m / 2 - 1;
0582: } else if (m >= 2) {
0583: day += (m - 1) / 2 - 1;
0584: } else {
0585: day += m;
0586: }
0587:
0588: if (m >= 2 && IsLeapYear(year)) {
0589: ++day;
0590: }
0591:
0592: return day;
0593: }
0594:
0595: private static int MonthFromTime(double t) {
0596: int year = YearFromTime(t);
0597: int d = (int) (Day(t) - DayFromYear(year));
0598:
0599: d -= 31 + 28;
0600: if (d < 0) {
0601: return (d < -28) ? 0 : 1;
0602: }
0603:
0604: if (IsLeapYear(year)) {
0605: if (d == 0)
0606: return 1; // 29 February
0607: --d;
0608: }
0609:
0610: // d: date count from 1 March
0611: int estimate = d / 30; // approx number of month since March
0612: int mstart;
0613: switch (estimate) {
0614: case 0:
0615: return 2;
0616: case 1:
0617: mstart = 31;
0618: break;
0619: case 2:
0620: mstart = 31 + 30;
0621: break;
0622: case 3:
0623: mstart = 31 + 30 + 31;
0624: break;
0625: case 4:
0626: mstart = 31 + 30 + 31 + 30;
0627: break;
0628: case 5:
0629: mstart = 31 + 30 + 31 + 30 + 31;
0630: break;
0631: case 6:
0632: mstart = 31 + 30 + 31 + 30 + 31 + 31;
0633: break;
0634: case 7:
0635: mstart = 31 + 30 + 31 + 30 + 31 + 31 + 30;
0636: break;
0637: case 8:
0638: mstart = 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31;
0639: break;
0640: case 9:
0641: mstart = 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30;
0642: break;
0643: case 10:
0644: return 11; //Late december
0645: default:
0646: throw Kit.codeBug();
0647: }
0648: // if d < mstart then real month since March == estimate - 1
0649: return (d >= mstart) ? estimate + 2 : estimate + 1;
0650: }
0651:
0652: private static int DateFromTime(double t) {
0653: int year = YearFromTime(t);
0654: int d = (int) (Day(t) - DayFromYear(year));
0655:
0656: d -= 31 + 28;
0657: if (d < 0) {
0658: return (d < -28) ? d + 31 + 28 + 1 : d + 28 + 1;
0659: }
0660:
0661: if (IsLeapYear(year)) {
0662: if (d == 0)
0663: return 29; // 29 February
0664: --d;
0665: }
0666:
0667: // d: date count from 1 March
0668: int mdays, mstart;
0669: switch (d / 30) { // approx number of month since March
0670: case 0:
0671: return d + 1;
0672: case 1:
0673: mdays = 31;
0674: mstart = 31;
0675: break;
0676: case 2:
0677: mdays = 30;
0678: mstart = 31 + 30;
0679: break;
0680: case 3:
0681: mdays = 31;
0682: mstart = 31 + 30 + 31;
0683: break;
0684: case 4:
0685: mdays = 30;
0686: mstart = 31 + 30 + 31 + 30;
0687: break;
0688: case 5:
0689: mdays = 31;
0690: mstart = 31 + 30 + 31 + 30 + 31;
0691: break;
0692: case 6:
0693: mdays = 31;
0694: mstart = 31 + 30 + 31 + 30 + 31 + 31;
0695: break;
0696: case 7:
0697: mdays = 30;
0698: mstart = 31 + 30 + 31 + 30 + 31 + 31 + 30;
0699: break;
0700: case 8:
0701: mdays = 31;
0702: mstart = 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31;
0703: break;
0704: case 9:
0705: mdays = 30;
0706: mstart = 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30;
0707: break;
0708: case 10:
0709: return d - (31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30) + 1; //Late december
0710: default:
0711: throw Kit.codeBug();
0712: }
0713: d -= mstart;
0714: if (d < 0) {
0715: // wrong estimate: sfhift to previous month
0716: d += mdays;
0717: }
0718: return d + 1;
0719: }
0720:
0721: private static int WeekDay(double t) {
0722: double result;
0723: result = Day(t) + 4;
0724: result = result % 7;
0725: if (result < 0)
0726: result += 7;
0727: return (int) result;
0728: }
0729:
0730: private static double now() {
0731: return System.currentTimeMillis();
0732: }
0733:
0734: /* Should be possible to determine the need for this dynamically
0735: * if we go with the workaround... I'm not using it now, because I
0736: * can't think of any clean way to make toLocaleString() and the
0737: * time zone (comment) in toString match the generated string
0738: * values. Currently it's wrong-but-consistent in all but the
0739: * most recent betas of the JRE - seems to work in 1.1.7.
0740: */
0741: private final static boolean TZO_WORKAROUND = false;
0742:
0743: private static double DaylightSavingTA(double t) {
0744: // Another workaround! The JRE doesn't seem to know about DST
0745: // before year 1 AD, so we map to equivalent dates for the
0746: // purposes of finding dst. To be safe, we do this for years
0747: // outside 1970-2038.
0748: if (t < 0.0 || t > 2145916800000.0) {
0749: int year = EquivalentYear(YearFromTime(t));
0750: double day = MakeDay(year, MonthFromTime(t),
0751: DateFromTime(t));
0752: t = MakeDate(day, TimeWithinDay(t));
0753: }
0754: if (!TZO_WORKAROUND) {
0755: Date date = new Date((long) t);
0756: if (this TimeZone.inDaylightTime(date))
0757: return msPerHour;
0758: else
0759: return 0;
0760: } else {
0761: /* Use getOffset if inDaylightTime() is broken, because it
0762: * seems to work acceptably. We don't switch over to it
0763: * entirely, because it requires (expensive) exploded date arguments,
0764: * and the api makes it impossible to handle dst
0765: * changeovers cleanly.
0766: */
0767:
0768: // Hardcode the assumption that the changeover always
0769: // happens at 2:00 AM:
0770: t += LocalTZA + (HourFromTime(t) <= 2 ? msPerHour : 0);
0771:
0772: int year = YearFromTime(t);
0773: double offset = this TimeZone.getOffset(year > 0 ? 1 : 0,
0774: year, MonthFromTime(t), DateFromTime(t),
0775: WeekDay(t), (int) TimeWithinDay(t));
0776:
0777: if ((offset - LocalTZA) != 0)
0778: return msPerHour;
0779: else
0780: return 0;
0781: // return offset - LocalTZA;
0782: }
0783: }
0784:
0785: /*
0786: * Find a year for which any given date will fall on the same weekday.
0787: *
0788: * This function should be used with caution when used other than
0789: * for determining DST; it hasn't been proven not to produce an
0790: * incorrect year for times near year boundaries.
0791: */
0792: private static int EquivalentYear(int year) {
0793: int day = (int) DayFromYear(year) + 4;
0794: day = day % 7;
0795: if (day < 0)
0796: day += 7;
0797: // Years and leap years on which Jan 1 is a Sunday, Monday, etc.
0798: if (IsLeapYear(year)) {
0799: switch (day) {
0800: case 0:
0801: return 1984;
0802: case 1:
0803: return 1996;
0804: case 2:
0805: return 1980;
0806: case 3:
0807: return 1992;
0808: case 4:
0809: return 1976;
0810: case 5:
0811: return 1988;
0812: case 6:
0813: return 1972;
0814: }
0815: } else {
0816: switch (day) {
0817: case 0:
0818: return 1978;
0819: case 1:
0820: return 1973;
0821: case 2:
0822: return 1974;
0823: case 3:
0824: return 1975;
0825: case 4:
0826: return 1981;
0827: case 5:
0828: return 1971;
0829: case 6:
0830: return 1977;
0831: }
0832: }
0833: // Unreachable
0834: throw Kit.codeBug();
0835: }
0836:
0837: private static double LocalTime(double t) {
0838: return t + LocalTZA + DaylightSavingTA(t);
0839: }
0840:
0841: private static double internalUTC(double t) {
0842: return t - LocalTZA - DaylightSavingTA(t - LocalTZA);
0843: }
0844:
0845: private static int HourFromTime(double t) {
0846: double result;
0847: result = Math.floor(t / msPerHour) % HoursPerDay;
0848: if (result < 0)
0849: result += HoursPerDay;
0850: return (int) result;
0851: }
0852:
0853: private static int MinFromTime(double t) {
0854: double result;
0855: result = Math.floor(t / msPerMinute) % MinutesPerHour;
0856: if (result < 0)
0857: result += MinutesPerHour;
0858: return (int) result;
0859: }
0860:
0861: private static int SecFromTime(double t) {
0862: double result;
0863: result = Math.floor(t / msPerSecond) % SecondsPerMinute;
0864: if (result < 0)
0865: result += SecondsPerMinute;
0866: return (int) result;
0867: }
0868:
0869: private static int msFromTime(double t) {
0870: double result;
0871: result = t % msPerSecond;
0872: if (result < 0)
0873: result += msPerSecond;
0874: return (int) result;
0875: }
0876:
0877: private static double MakeTime(double hour, double min, double sec,
0878: double ms) {
0879: return ((hour * MinutesPerHour + min) * SecondsPerMinute + sec)
0880: * msPerSecond + ms;
0881: }
0882:
0883: private static double MakeDay(double year, double month, double date) {
0884: year += Math.floor(month / 12);
0885:
0886: month = month % 12;
0887: if (month < 0)
0888: month += 12;
0889:
0890: double yearday = Math.floor(TimeFromYear(year) / msPerDay);
0891: double monthday = DayFromMonth((int) month, (int) year);
0892:
0893: return yearday + monthday + date - 1;
0894: }
0895:
0896: private static double MakeDate(double day, double time) {
0897: return day * msPerDay + time;
0898: }
0899:
0900: private static double TimeClip(double d) {
0901: if (d != d || d == Double.POSITIVE_INFINITY
0902: || d == Double.NEGATIVE_INFINITY
0903: || Math.abs(d) > HalfTimeDomain) {
0904: return ScriptRuntime.NaN;
0905: }
0906: if (d > 0.0)
0907: return Math.floor(d + 0.);
0908: else
0909: return Math.ceil(d + 0.);
0910: }
0911:
0912: /* end of ECMA helper functions */
0913:
0914: /* find UTC time from given date... no 1900 correction! */
0915: private static double date_msecFromDate(double year, double mon,
0916: double mday, double hour, double min, double sec,
0917: double msec) {
0918: double day;
0919: double time;
0920: double result;
0921:
0922: day = MakeDay(year, mon, mday);
0923: time = MakeTime(hour, min, sec, msec);
0924: result = MakeDate(day, time);
0925: return result;
0926: }
0927:
0928: /* compute the time in msec (unclipped) from the given args */
0929: private static final int MAXARGS = 7;
0930:
0931: private static double date_msecFromArgs(Object[] args) {
0932: double array[] = new double[MAXARGS];
0933: int loop;
0934: double d;
0935:
0936: for (loop = 0; loop < MAXARGS; loop++) {
0937: if (loop < args.length) {
0938: d = ScriptRuntime.toNumber(args[loop]);
0939: if (d != d || Double.isInfinite(d)) {
0940: return ScriptRuntime.NaN;
0941: }
0942: array[loop] = ScriptRuntime.toInteger(args[loop]);
0943: } else {
0944: if (loop == 2) {
0945: array[loop] = 1; /* Default the date argument to 1. */
0946: } else {
0947: array[loop] = 0;
0948: }
0949: }
0950: }
0951:
0952: /* adjust 2-digit years into the 20th century */
0953: if (array[0] >= 0 && array[0] <= 99)
0954: array[0] += 1900;
0955:
0956: return date_msecFromDate(array[0], array[1], array[2],
0957: array[3], array[4], array[5], array[6]);
0958: }
0959:
0960: private static double jsStaticFunction_UTC(Object[] args) {
0961: return TimeClip(date_msecFromArgs(args));
0962: }
0963:
0964: private static double date_parseString(String s) {
0965: int year = -1;
0966: int mon = -1;
0967: int mday = -1;
0968: int hour = -1;
0969: int min = -1;
0970: int sec = -1;
0971: char c = 0;
0972: char si = 0;
0973: int i = 0;
0974: int n = -1;
0975: double tzoffset = -1;
0976: char prevc = 0;
0977: int limit = 0;
0978: boolean seenplusminus = false;
0979:
0980: limit = s.length();
0981: while (i < limit) {
0982: c = s.charAt(i);
0983: i++;
0984: if (c <= ' ' || c == ',' || c == '-') {
0985: if (i < limit) {
0986: si = s.charAt(i);
0987: if (c == '-' && '0' <= si && si <= '9') {
0988: prevc = c;
0989: }
0990: }
0991: continue;
0992: }
0993: if (c == '(') { /* comments) */
0994: int depth = 1;
0995: while (i < limit) {
0996: c = s.charAt(i);
0997: i++;
0998: if (c == '(')
0999: depth++;
1000: else if (c == ')')
1001: if (--depth <= 0)
1002: break;
1003: }
1004: continue;
1005: }
1006: if ('0' <= c && c <= '9') {
1007: n = c - '0';
1008: while (i < limit && '0' <= (c = s.charAt(i))
1009: && c <= '9') {
1010: n = n * 10 + c - '0';
1011: i++;
1012: }
1013:
1014: /* allow TZA before the year, so
1015: * 'Wed Nov 05 21:49:11 GMT-0800 1997'
1016: * works */
1017:
1018: /* uses of seenplusminus allow : in TZA, so Java
1019: * no-timezone style of GMT+4:30 works
1020: */
1021: if ((prevc == '+' || prevc == '-')/* && year>=0 */) {
1022: /* make ':' case below change tzoffset */
1023: seenplusminus = true;
1024:
1025: /* offset */
1026: if (n < 24)
1027: n = n * 60; /* EG. "GMT-3" */
1028: else
1029: n = n % 100 + n / 100 * 60; /* eg "GMT-0430" */
1030: if (prevc == '+') /* plus means east of GMT */
1031: n = -n;
1032: if (tzoffset != 0 && tzoffset != -1)
1033: return ScriptRuntime.NaN;
1034: tzoffset = n;
1035: } else if (n >= 70
1036: || (prevc == '/' && mon >= 0 && mday >= 0 && year < 0)) {
1037: if (year >= 0)
1038: return ScriptRuntime.NaN;
1039: else if (c <= ' ' || c == ',' || c == '/'
1040: || i >= limit)
1041: year = n < 100 ? n + 1900 : n;
1042: else
1043: return ScriptRuntime.NaN;
1044: } else if (c == ':') {
1045: if (hour < 0)
1046: hour = /*byte*/n;
1047: else if (min < 0)
1048: min = /*byte*/n;
1049: else
1050: return ScriptRuntime.NaN;
1051: } else if (c == '/') {
1052: if (mon < 0)
1053: mon = /*byte*/n - 1;
1054: else if (mday < 0)
1055: mday = /*byte*/n;
1056: else
1057: return ScriptRuntime.NaN;
1058: } else if (i < limit && c != ',' && c > ' ' && c != '-') {
1059: return ScriptRuntime.NaN;
1060: } else if (seenplusminus && n < 60) { /* handle GMT-3:30 */
1061: if (tzoffset < 0)
1062: tzoffset -= n;
1063: else
1064: tzoffset += n;
1065: } else if (hour >= 0 && min < 0) {
1066: min = /*byte*/n;
1067: } else if (min >= 0 && sec < 0) {
1068: sec = /*byte*/n;
1069: } else if (mday < 0) {
1070: mday = /*byte*/n;
1071: } else {
1072: return ScriptRuntime.NaN;
1073: }
1074: prevc = 0;
1075: } else if (c == '/' || c == ':' || c == '+' || c == '-') {
1076: prevc = c;
1077: } else {
1078: int st = i - 1;
1079: while (i < limit) {
1080: c = s.charAt(i);
1081: if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')))
1082: break;
1083: i++;
1084: }
1085: int letterCount = i - st;
1086: if (letterCount < 2)
1087: return ScriptRuntime.NaN;
1088: /*
1089: * Use ported code from jsdate.c rather than the locale-specific
1090: * date-parsing code from Java, to keep js and rhino consistent.
1091: * Is this the right strategy?
1092: */
1093: String wtb = "am;pm;"
1094: + "monday;tuesday;wednesday;thursday;friday;"
1095: + "saturday;sunday;"
1096: + "january;february;march;april;may;june;"
1097: + "july;august;september;october;november;december;"
1098: + "gmt;ut;utc;est;edt;cst;cdt;mst;mdt;pst;pdt;";
1099: int index = 0;
1100: for (int wtbOffset = 0;;) {
1101: int wtbNext = wtb.indexOf(';', wtbOffset);
1102: if (wtbNext < 0)
1103: return ScriptRuntime.NaN;
1104: if (wtb.regionMatches(true, wtbOffset, s, st,
1105: letterCount))
1106: break;
1107: wtbOffset = wtbNext + 1;
1108: ++index;
1109: }
1110: if (index < 2) {
1111: /*
1112: * AM/PM. Count 12:30 AM as 00:30, 12:30 PM as
1113: * 12:30, instead of blindly adding 12 if PM.
1114: */
1115: if (hour > 12 || hour < 0) {
1116: return ScriptRuntime.NaN;
1117: } else if (index == 0) {
1118: // AM
1119: if (hour == 12)
1120: hour = 0;
1121: } else {
1122: // PM
1123: if (hour != 12)
1124: hour += 12;
1125: }
1126: } else if ((index -= 2) < 7) {
1127: // ignore week days
1128: } else if ((index -= 7) < 12) {
1129: // month
1130: if (mon < 0) {
1131: mon = index;
1132: } else {
1133: return ScriptRuntime.NaN;
1134: }
1135: } else {
1136: index -= 12;
1137: // timezones
1138: switch (index) {
1139: case 0 /* gmt */:
1140: tzoffset = 0;
1141: break;
1142: case 1 /* ut */:
1143: tzoffset = 0;
1144: break;
1145: case 2 /* utc */:
1146: tzoffset = 0;
1147: break;
1148: case 3 /* est */:
1149: tzoffset = 5 * 60;
1150: break;
1151: case 4 /* edt */:
1152: tzoffset = 4 * 60;
1153: break;
1154: case 5 /* cst */:
1155: tzoffset = 6 * 60;
1156: break;
1157: case 6 /* cdt */:
1158: tzoffset = 5 * 60;
1159: break;
1160: case 7 /* mst */:
1161: tzoffset = 7 * 60;
1162: break;
1163: case 8 /* mdt */:
1164: tzoffset = 6 * 60;
1165: break;
1166: case 9 /* pst */:
1167: tzoffset = 8 * 60;
1168: break;
1169: case 10 /* pdt */:
1170: tzoffset = 7 * 60;
1171: break;
1172: default:
1173: Kit.codeBug();
1174: }
1175: }
1176: }
1177: }
1178: if (year < 0 || mon < 0 || mday < 0)
1179: return ScriptRuntime.NaN;
1180: if (sec < 0)
1181: sec = 0;
1182: if (min < 0)
1183: min = 0;
1184: if (hour < 0)
1185: hour = 0;
1186:
1187: double msec = date_msecFromDate(year, mon, mday, hour, min,
1188: sec, 0);
1189: if (tzoffset == -1) { /* no time zone specified, have to use local */
1190: return internalUTC(msec);
1191: } else {
1192: return msec + tzoffset * msPerMinute;
1193: }
1194: }
1195:
1196: private static String date_format(double t, int methodId) {
1197: StringBuffer result = new StringBuffer(60);
1198: double local = LocalTime(t);
1199:
1200: /* Tue Oct 31 09:41:40 GMT-0800 (PST) 2000 */
1201: /* Tue Oct 31 2000 */
1202: /* 09:41:40 GMT-0800 (PST) */
1203:
1204: if (methodId != Id_toTimeString) {
1205: appendWeekDayName(result, WeekDay(local));
1206: result.append(' ');
1207: appendMonthName(result, MonthFromTime(local));
1208: result.append(' ');
1209: append0PaddedUint(result, DateFromTime(local), 2);
1210: result.append(' ');
1211: int year = YearFromTime(local);
1212: if (year < 0) {
1213: result.append('-');
1214: year = -year;
1215: }
1216: append0PaddedUint(result, year, 4);
1217: if (methodId != Id_toDateString)
1218: result.append(' ');
1219: }
1220:
1221: if (methodId != Id_toDateString) {
1222: append0PaddedUint(result, HourFromTime(local), 2);
1223: result.append(':');
1224: append0PaddedUint(result, MinFromTime(local), 2);
1225: result.append(':');
1226: append0PaddedUint(result, SecFromTime(local), 2);
1227:
1228: // offset from GMT in minutes. The offset includes daylight
1229: // savings, if it applies.
1230: int minutes = (int) Math
1231: .floor((LocalTZA + DaylightSavingTA(t))
1232: / msPerMinute);
1233: // map 510 minutes to 0830 hours
1234: int offset = (minutes / 60) * 100 + minutes % 60;
1235: if (offset > 0) {
1236: result.append(" GMT+");
1237: } else {
1238: result.append(" GMT-");
1239: offset = -offset;
1240: }
1241: append0PaddedUint(result, offset, 4);
1242:
1243: if (timeZoneFormatter == null)
1244: timeZoneFormatter = new java.text.SimpleDateFormat(
1245: "zzz");
1246:
1247: // Find an equivalent year before getting the timezone
1248: // comment. See DaylightSavingTA.
1249: if (t < 0.0 || t > 2145916800000.0) {
1250: int equiv = EquivalentYear(YearFromTime(local));
1251: double day = MakeDay(equiv, MonthFromTime(t),
1252: DateFromTime(t));
1253: t = MakeDate(day, TimeWithinDay(t));
1254: }
1255: result.append(" (");
1256: java.util.Date date = new Date((long) t);
1257: synchronized (timeZoneFormatter) {
1258: result.append(timeZoneFormatter.format(date));
1259: }
1260: result.append(')');
1261: }
1262: return result.toString();
1263: }
1264:
1265: /* the javascript constructor */
1266: private static Object jsConstructor(Object[] args) {
1267: NativeDate obj = new NativeDate();
1268:
1269: // if called as a constructor with no args,
1270: // return a new Date with the current time.
1271: if (args.length == 0) {
1272: obj.date = now();
1273: return obj;
1274: }
1275:
1276: // if called with just one arg -
1277: if (args.length == 1) {
1278: Object arg0 = args[0];
1279: if (arg0 instanceof Scriptable)
1280: arg0 = ((Scriptable) arg0).getDefaultValue(null);
1281: double date;
1282: if (arg0 instanceof String) {
1283: // it's a string; parse it.
1284: date = date_parseString((String) arg0);
1285: } else {
1286: // if it's not a string, use it as a millisecond date
1287: date = ScriptRuntime.toNumber(arg0);
1288: }
1289: obj.date = TimeClip(date);
1290: return obj;
1291: }
1292:
1293: double time = date_msecFromArgs(args);
1294:
1295: if (!Double.isNaN(time) && !Double.isInfinite(time))
1296: time = TimeClip(internalUTC(time));
1297:
1298: obj.date = time;
1299:
1300: return obj;
1301: }
1302:
1303: private static String toLocale_helper(double t, int methodId) {
1304: java.text.DateFormat formatter;
1305: switch (methodId) {
1306: case Id_toLocaleString:
1307: if (localeDateTimeFormatter == null) {
1308: localeDateTimeFormatter = DateFormat
1309: .getDateTimeInstance(DateFormat.LONG,
1310: DateFormat.LONG);
1311: }
1312: formatter = localeDateTimeFormatter;
1313: break;
1314: case Id_toLocaleTimeString:
1315: if (localeTimeFormatter == null) {
1316: localeTimeFormatter = DateFormat
1317: .getTimeInstance(DateFormat.LONG);
1318: }
1319: formatter = localeTimeFormatter;
1320: break;
1321: case Id_toLocaleDateString:
1322: if (localeDateFormatter == null) {
1323: localeDateFormatter = DateFormat
1324: .getDateInstance(DateFormat.LONG);
1325: }
1326: formatter = localeDateFormatter;
1327: break;
1328: default:
1329: formatter = null; // unreachable
1330: }
1331:
1332: synchronized (formatter) {
1333: return formatter.format(new Date((long) t));
1334: }
1335: }
1336:
1337: private static String js_toUTCString(double date) {
1338: StringBuffer result = new StringBuffer(60);
1339:
1340: appendWeekDayName(result, WeekDay(date));
1341: result.append(", ");
1342: append0PaddedUint(result, DateFromTime(date), 2);
1343: result.append(' ');
1344: appendMonthName(result, MonthFromTime(date));
1345: result.append(' ');
1346: int year = YearFromTime(date);
1347: if (year < 0) {
1348: result.append('-');
1349: year = -year;
1350: }
1351: append0PaddedUint(result, year, 4);
1352: result.append(' ');
1353: append0PaddedUint(result, HourFromTime(date), 2);
1354: result.append(':');
1355: append0PaddedUint(result, MinFromTime(date), 2);
1356: result.append(':');
1357: append0PaddedUint(result, SecFromTime(date), 2);
1358: result.append(" GMT");
1359: return result.toString();
1360: }
1361:
1362: private static void append0PaddedUint(StringBuffer sb, int i,
1363: int minWidth) {
1364: if (i < 0)
1365: Kit.codeBug();
1366: int scale = 1;
1367: --minWidth;
1368: if (i >= 10) {
1369: if (i < 1000 * 1000 * 1000) {
1370: for (;;) {
1371: int newScale = scale * 10;
1372: if (i < newScale) {
1373: break;
1374: }
1375: --minWidth;
1376: scale = newScale;
1377: }
1378: } else {
1379: // Separated case not to check against 10 * 10^9 overflow
1380: minWidth -= 9;
1381: scale = 1000 * 1000 * 1000;
1382: }
1383: }
1384: while (minWidth > 0) {
1385: sb.append('0');
1386: --minWidth;
1387: }
1388: while (scale != 1) {
1389: sb.append((char) ('0' + (i / scale)));
1390: i %= scale;
1391: scale /= 10;
1392: }
1393: sb.append((char) ('0' + i));
1394: }
1395:
1396: private static void appendMonthName(StringBuffer sb, int index) {
1397: // Take advantage of the fact that all month abbreviations
1398: // have the same length to minimize amount of strings runtime has
1399: // to keep in memory
1400: String months = "Jan" + "Feb" + "Mar" + "Apr" + "May" + "Jun"
1401: + "Jul" + "Aug" + "Sep" + "Oct" + "Nov" + "Dec";
1402: index *= 3;
1403: for (int i = 0; i != 3; ++i) {
1404: sb.append(months.charAt(index + i));
1405: }
1406: }
1407:
1408: private static void appendWeekDayName(StringBuffer sb, int index) {
1409: String days = "Sun" + "Mon" + "Tue" + "Wed" + "Thu" + "Fri"
1410: + "Sat";
1411: index *= 3;
1412: for (int i = 0; i != 3; ++i) {
1413: sb.append(days.charAt(index + i));
1414: }
1415: }
1416:
1417: private static double makeTime(double date, Object[] args,
1418: int methodId) {
1419: int maxargs;
1420: boolean local = true;
1421: switch (methodId) {
1422: case Id_setUTCMilliseconds:
1423: local = false;
1424: // fallthrough
1425: case Id_setMilliseconds:
1426: maxargs = 1;
1427: break;
1428:
1429: case Id_setUTCSeconds:
1430: local = false;
1431: // fallthrough
1432: case Id_setSeconds:
1433: maxargs = 2;
1434: break;
1435:
1436: case Id_setUTCMinutes:
1437: local = false;
1438: // fallthrough
1439: case Id_setMinutes:
1440: maxargs = 3;
1441: break;
1442:
1443: case Id_setUTCHours:
1444: local = false;
1445: // fallthrough
1446: case Id_setHours:
1447: maxargs = 4;
1448: break;
1449:
1450: default:
1451: Kit.codeBug();
1452: maxargs = 0;
1453: }
1454:
1455: int i;
1456: double conv[] = new double[4];
1457: double hour, min, sec, msec;
1458: double lorutime; /* Local or UTC version of date */
1459:
1460: double time;
1461: double result;
1462:
1463: /* just return NaN if the date is already NaN */
1464: if (date != date)
1465: return date;
1466:
1467: /* Satisfy the ECMA rule that if a function is called with
1468: * fewer arguments than the specified formal arguments, the
1469: * remaining arguments are set to undefined. Seems like all
1470: * the Date.setWhatever functions in ECMA are only varargs
1471: * beyond the first argument; this should be set to undefined
1472: * if it's not given. This means that "d = new Date();
1473: * d.setMilliseconds()" returns NaN. Blech.
1474: */
1475: if (args.length == 0)
1476: args = ScriptRuntime.padArguments(args, 1);
1477:
1478: for (i = 0; i < args.length && i < maxargs; i++) {
1479: conv[i] = ScriptRuntime.toNumber(args[i]);
1480:
1481: // limit checks that happen in MakeTime in ECMA.
1482: if (conv[i] != conv[i] || Double.isInfinite(conv[i])) {
1483: return ScriptRuntime.NaN;
1484: }
1485: conv[i] = ScriptRuntime.toInteger(conv[i]);
1486: }
1487:
1488: if (local)
1489: lorutime = LocalTime(date);
1490: else
1491: lorutime = date;
1492:
1493: i = 0;
1494: int stop = args.length;
1495:
1496: if (maxargs >= 4 && i < stop)
1497: hour = conv[i++];
1498: else
1499: hour = HourFromTime(lorutime);
1500:
1501: if (maxargs >= 3 && i < stop)
1502: min = conv[i++];
1503: else
1504: min = MinFromTime(lorutime);
1505:
1506: if (maxargs >= 2 && i < stop)
1507: sec = conv[i++];
1508: else
1509: sec = SecFromTime(lorutime);
1510:
1511: if (maxargs >= 1 && i < stop)
1512: msec = conv[i++];
1513: else
1514: msec = msFromTime(lorutime);
1515:
1516: time = MakeTime(hour, min, sec, msec);
1517: result = MakeDate(Day(lorutime), time);
1518:
1519: if (local)
1520: result = internalUTC(result);
1521: date = TimeClip(result);
1522:
1523: return date;
1524: }
1525:
1526: private static double makeDate(double date, Object[] args,
1527: int methodId) {
1528: int maxargs;
1529: boolean local = true;
1530: switch (methodId) {
1531: case Id_setUTCDate:
1532: local = false;
1533: // fallthrough
1534: case Id_setDate:
1535: maxargs = 1;
1536: break;
1537:
1538: case Id_setUTCMonth:
1539: local = false;
1540: // fallthrough
1541: case Id_setMonth:
1542: maxargs = 2;
1543: break;
1544:
1545: case Id_setUTCFullYear:
1546: local = false;
1547: // fallthrough
1548: case Id_setFullYear:
1549: maxargs = 3;
1550: break;
1551:
1552: default:
1553: Kit.codeBug();
1554: maxargs = 0;
1555: }
1556:
1557: int i;
1558: double conv[] = new double[3];
1559: double year, month, day;
1560: double lorutime; /* local or UTC version of date */
1561: double result;
1562:
1563: /* See arg padding comment in makeTime.*/
1564: if (args.length == 0)
1565: args = ScriptRuntime.padArguments(args, 1);
1566:
1567: for (i = 0; i < args.length && i < maxargs; i++) {
1568: conv[i] = ScriptRuntime.toNumber(args[i]);
1569:
1570: // limit checks that happen in MakeDate in ECMA.
1571: if (conv[i] != conv[i] || Double.isInfinite(conv[i])) {
1572: return ScriptRuntime.NaN;
1573: }
1574: conv[i] = ScriptRuntime.toInteger(conv[i]);
1575: }
1576:
1577: /* return NaN if date is NaN and we're not setting the year,
1578: * If we are, use 0 as the time. */
1579: if (date != date) {
1580: if (args.length < 3) {
1581: return ScriptRuntime.NaN;
1582: } else {
1583: lorutime = 0;
1584: }
1585: } else {
1586: if (local)
1587: lorutime = LocalTime(date);
1588: else
1589: lorutime = date;
1590: }
1591:
1592: i = 0;
1593: int stop = args.length;
1594:
1595: if (maxargs >= 3 && i < stop)
1596: year = conv[i++];
1597: else
1598: year = YearFromTime(lorutime);
1599:
1600: if (maxargs >= 2 && i < stop)
1601: month = conv[i++];
1602: else
1603: month = MonthFromTime(lorutime);
1604:
1605: if (maxargs >= 1 && i < stop)
1606: day = conv[i++];
1607: else
1608: day = DateFromTime(lorutime);
1609:
1610: day = MakeDay(year, month, day); /* day within year */
1611: result = MakeDate(day, TimeWithinDay(lorutime));
1612:
1613: if (local)
1614: result = internalUTC(result);
1615:
1616: date = TimeClip(result);
1617:
1618: return date;
1619: }
1620:
1621: // #string_id_map#
1622:
1623: protected int findPrototypeId(String s) {
1624: int id;
1625: // #generated# Last update: 2007-05-09 08:15:38 EDT
1626: L0: {
1627: id = 0;
1628: String X = null;
1629: int c;
1630: L: switch (s.length()) {
1631: case 6:
1632: X = "getDay";
1633: id = Id_getDay;
1634: break L;
1635: case 7:
1636: switch (s.charAt(3)) {
1637: case 'D':
1638: c = s.charAt(0);
1639: if (c == 'g') {
1640: X = "getDate";
1641: id = Id_getDate;
1642: } else if (c == 's') {
1643: X = "setDate";
1644: id = Id_setDate;
1645: }
1646: break L;
1647: case 'T':
1648: c = s.charAt(0);
1649: if (c == 'g') {
1650: X = "getTime";
1651: id = Id_getTime;
1652: } else if (c == 's') {
1653: X = "setTime";
1654: id = Id_setTime;
1655: }
1656: break L;
1657: case 'Y':
1658: c = s.charAt(0);
1659: if (c == 'g') {
1660: X = "getYear";
1661: id = Id_getYear;
1662: } else if (c == 's') {
1663: X = "setYear";
1664: id = Id_setYear;
1665: }
1666: break L;
1667: case 'u':
1668: X = "valueOf";
1669: id = Id_valueOf;
1670: break L;
1671: }
1672: break L;
1673: case 8:
1674: switch (s.charAt(3)) {
1675: case 'H':
1676: c = s.charAt(0);
1677: if (c == 'g') {
1678: X = "getHours";
1679: id = Id_getHours;
1680: } else if (c == 's') {
1681: X = "setHours";
1682: id = Id_setHours;
1683: }
1684: break L;
1685: case 'M':
1686: c = s.charAt(0);
1687: if (c == 'g') {
1688: X = "getMonth";
1689: id = Id_getMonth;
1690: } else if (c == 's') {
1691: X = "setMonth";
1692: id = Id_setMonth;
1693: }
1694: break L;
1695: case 'o':
1696: X = "toSource";
1697: id = Id_toSource;
1698: break L;
1699: case 't':
1700: X = "toString";
1701: id = Id_toString;
1702: break L;
1703: }
1704: break L;
1705: case 9:
1706: X = "getUTCDay";
1707: id = Id_getUTCDay;
1708: break L;
1709: case 10:
1710: c = s.charAt(3);
1711: if (c == 'M') {
1712: c = s.charAt(0);
1713: if (c == 'g') {
1714: X = "getMinutes";
1715: id = Id_getMinutes;
1716: } else if (c == 's') {
1717: X = "setMinutes";
1718: id = Id_setMinutes;
1719: }
1720: } else if (c == 'S') {
1721: c = s.charAt(0);
1722: if (c == 'g') {
1723: X = "getSeconds";
1724: id = Id_getSeconds;
1725: } else if (c == 's') {
1726: X = "setSeconds";
1727: id = Id_setSeconds;
1728: }
1729: } else if (c == 'U') {
1730: c = s.charAt(0);
1731: if (c == 'g') {
1732: X = "getUTCDate";
1733: id = Id_getUTCDate;
1734: } else if (c == 's') {
1735: X = "setUTCDate";
1736: id = Id_setUTCDate;
1737: }
1738: }
1739: break L;
1740: case 11:
1741: switch (s.charAt(3)) {
1742: case 'F':
1743: c = s.charAt(0);
1744: if (c == 'g') {
1745: X = "getFullYear";
1746: id = Id_getFullYear;
1747: } else if (c == 's') {
1748: X = "setFullYear";
1749: id = Id_setFullYear;
1750: }
1751: break L;
1752: case 'M':
1753: X = "toGMTString";
1754: id = Id_toGMTString;
1755: break L;
1756: case 'T':
1757: X = "toUTCString";
1758: id = Id_toUTCString;
1759: break L;
1760: case 'U':
1761: c = s.charAt(0);
1762: if (c == 'g') {
1763: c = s.charAt(9);
1764: if (c == 'r') {
1765: X = "getUTCHours";
1766: id = Id_getUTCHours;
1767: } else if (c == 't') {
1768: X = "getUTCMonth";
1769: id = Id_getUTCMonth;
1770: }
1771: } else if (c == 's') {
1772: c = s.charAt(9);
1773: if (c == 'r') {
1774: X = "setUTCHours";
1775: id = Id_setUTCHours;
1776: } else if (c == 't') {
1777: X = "setUTCMonth";
1778: id = Id_setUTCMonth;
1779: }
1780: }
1781: break L;
1782: case 's':
1783: X = "constructor";
1784: id = Id_constructor;
1785: break L;
1786: }
1787: break L;
1788: case 12:
1789: c = s.charAt(2);
1790: if (c == 'D') {
1791: X = "toDateString";
1792: id = Id_toDateString;
1793: } else if (c == 'T') {
1794: X = "toTimeString";
1795: id = Id_toTimeString;
1796: }
1797: break L;
1798: case 13:
1799: c = s.charAt(0);
1800: if (c == 'g') {
1801: c = s.charAt(6);
1802: if (c == 'M') {
1803: X = "getUTCMinutes";
1804: id = Id_getUTCMinutes;
1805: } else if (c == 'S') {
1806: X = "getUTCSeconds";
1807: id = Id_getUTCSeconds;
1808: }
1809: } else if (c == 's') {
1810: c = s.charAt(6);
1811: if (c == 'M') {
1812: X = "setUTCMinutes";
1813: id = Id_setUTCMinutes;
1814: } else if (c == 'S') {
1815: X = "setUTCSeconds";
1816: id = Id_setUTCSeconds;
1817: }
1818: }
1819: break L;
1820: case 14:
1821: c = s.charAt(0);
1822: if (c == 'g') {
1823: X = "getUTCFullYear";
1824: id = Id_getUTCFullYear;
1825: } else if (c == 's') {
1826: X = "setUTCFullYear";
1827: id = Id_setUTCFullYear;
1828: } else if (c == 't') {
1829: X = "toLocaleString";
1830: id = Id_toLocaleString;
1831: }
1832: break L;
1833: case 15:
1834: c = s.charAt(0);
1835: if (c == 'g') {
1836: X = "getMilliseconds";
1837: id = Id_getMilliseconds;
1838: } else if (c == 's') {
1839: X = "setMilliseconds";
1840: id = Id_setMilliseconds;
1841: }
1842: break L;
1843: case 17:
1844: X = "getTimezoneOffset";
1845: id = Id_getTimezoneOffset;
1846: break L;
1847: case 18:
1848: c = s.charAt(0);
1849: if (c == 'g') {
1850: X = "getUTCMilliseconds";
1851: id = Id_getUTCMilliseconds;
1852: } else if (c == 's') {
1853: X = "setUTCMilliseconds";
1854: id = Id_setUTCMilliseconds;
1855: } else if (c == 't') {
1856: c = s.charAt(8);
1857: if (c == 'D') {
1858: X = "toLocaleDateString";
1859: id = Id_toLocaleDateString;
1860: } else if (c == 'T') {
1861: X = "toLocaleTimeString";
1862: id = Id_toLocaleTimeString;
1863: }
1864: }
1865: break L;
1866: }
1867: if (X != null && X != s && !X.equals(s))
1868: id = 0;
1869: break L0;
1870: }
1871: // #/generated#
1872: return id;
1873: }
1874:
1875: private static final int ConstructorId_now = -3,
1876: ConstructorId_parse = -2, ConstructorId_UTC = -1,
1877:
1878: Id_constructor = 1, Id_toString = 2, Id_toTimeString = 3,
1879: Id_toDateString = 4, Id_toLocaleString = 5,
1880: Id_toLocaleTimeString = 6, Id_toLocaleDateString = 7,
1881: Id_toUTCString = 8, Id_toSource = 9, Id_valueOf = 10,
1882: Id_getTime = 11, Id_getYear = 12, Id_getFullYear = 13,
1883: Id_getUTCFullYear = 14, Id_getMonth = 15,
1884: Id_getUTCMonth = 16, Id_getDate = 17, Id_getUTCDate = 18,
1885: Id_getDay = 19, Id_getUTCDay = 20, Id_getHours = 21,
1886: Id_getUTCHours = 22, Id_getMinutes = 23,
1887: Id_getUTCMinutes = 24, Id_getSeconds = 25,
1888: Id_getUTCSeconds = 26, Id_getMilliseconds = 27,
1889: Id_getUTCMilliseconds = 28, Id_getTimezoneOffset = 29,
1890: Id_setTime = 30, Id_setMilliseconds = 31,
1891: Id_setUTCMilliseconds = 32, Id_setSeconds = 33,
1892: Id_setUTCSeconds = 34, Id_setMinutes = 35,
1893: Id_setUTCMinutes = 36, Id_setHours = 37,
1894: Id_setUTCHours = 38, Id_setDate = 39, Id_setUTCDate = 40,
1895: Id_setMonth = 41, Id_setUTCMonth = 42, Id_setFullYear = 43,
1896: Id_setUTCFullYear = 44, Id_setYear = 45,
1897:
1898: MAX_PROTOTYPE_ID = 45;
1899:
1900: private static final int Id_toGMTString = Id_toUTCString; // Alias, see Ecma B.2.6
1901: // #/string_id_map#
1902:
1903: /* cached values */
1904: private static java.util.TimeZone this TimeZone;
1905: private static double LocalTZA;
1906: private static java.text.DateFormat timeZoneFormatter;
1907: private static java.text.DateFormat localeDateTimeFormatter;
1908: private static java.text.DateFormat localeDateFormatter;
1909: private static java.text.DateFormat localeTimeFormatter;
1910:
1911: private double date;
1912: }
|