Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
    *
    * This Source Code Form is subject to the terms of the Mozilla Public
    * License, v. 2.0. If a copy of the MPL was not distributed with this
    * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
   
   package org.mozilla.javascript;
   
   import java.util.Date;
  
This class implements the Date native object. See ECMA 15.9.

Author(s):
Mike McCabe
  
  final class NativeDate extends IdScriptableObject
  {
      static final long serialVersionUID = -8307438915861678966L;
  
      private static final Object DATE_TAG = "Date";
  
      private static final String js_NaN_date_str = "Invalid Date";
  
      private static final DateFormat isoFormat;
      static {
         = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
        .setTimeZone(new SimpleTimeZone(0, "UTC"));
        .setLenient(false);
      }
  
      static void init(Scriptable scopeboolean sealed)
      {
          NativeDate obj = new NativeDate();
          // Set the value of the prototype Date to NaN ('invalid date');
          obj.date = .;
          obj.exportAsJSClass(scopesealed);
      }
  
      private NativeDate()
      {
          if ( == null) {
              // j.u.TimeZone is synchronized, so setting class statics from it
              // should be OK.
               = TimeZone.getDefault();
               = .getRawOffset();
          }
      }
  
      @Override
      public String getClassName()
      {
          return "Date";
      }
  
      @Override
      public Object getDefaultValue(Class<?> typeHint)
      {
          if (typeHint == null)
              typeHint = .;
          return super.getDefaultValue(typeHint);
      }
  
      double getJSTimeValue()
      {
          return ;
      }
  
      @Override
      protected void fillConstructorProperties(IdFunctionObject ctor)
      {
          addIdFunctionProperty(ctor,
                                "now", 0);
                                "parse", 1);
          addIdFunctionProperty(ctor,
                                "UTC", 1);
          super.fillConstructorProperties(ctor);
      }
  
      @Override
      protected void initPrototypeId(int id)
      {
          String s;
          int arity;
          switch (id) {
            case :        arity=1; s="constructor";        break;
            case :           arity=0; s="toString";           break;
            case :       arity=0; s="toTimeString";       break;
            case :       arity=0; s="toDateString";       break;
            case :     arity=0; s="toLocaleString";     break;
            case arity=0; s="toLocaleTimeString"break;
            case arity=0; s="toLocaleDateString"break;
            case :        arity=0; s="toUTCString";        break;
            case :           arity=0; s="toSource";           break;
           case :            arity=0; s="valueOf";            break;
           case :            arity=0; s="getTime";            break;
           case :            arity=0; s="getYear";            break;
           case :        arity=0; s="getFullYear";        break;
           case :     arity=0; s="getUTCFullYear";     break;
           case :           arity=0; s="getMonth";           break;
           case :        arity=0; s="getUTCMonth";        break;
           case :            arity=0; s="getDate";            break;
           case :         arity=0; s="getUTCDate";         break;
           case :             arity=0; s="getDay";             break;
           case :          arity=0; s="getUTCDay";          break;
           case :           arity=0; s="getHours";           break;
           case :        arity=0; s="getUTCHours";        break;
           case :         arity=0; s="getMinutes";         break;
           case :      arity=0; s="getUTCMinutes";      break;
           case :         arity=0; s="getSeconds";         break;
           case :      arity=0; s="getUTCSeconds";      break;
           case :    arity=0; s="getMilliseconds";    break;
           case arity=0; s="getUTCMilliseconds"break;
           case :  arity=0; s="getTimezoneOffset";  break;
           case :            arity=1; s="setTime";            break;
           case :    arity=1; s="setMilliseconds";    break;
           case arity=1; s="setUTCMilliseconds"break;
           case :         arity=2; s="setSeconds";         break;
           case :      arity=2; s="setUTCSeconds";      break;
           case :         arity=3; s="setMinutes";         break;
           case :      arity=3; s="setUTCMinutes";      break;
           case :           arity=4; s="setHours";           break;
           case :        arity=4; s="setUTCHours";        break;
           case :            arity=1; s="setDate";            break;
           case :         arity=1; s="setUTCDate";         break;
           case :           arity=2; s="setMonth";           break;
           case :        arity=2; s="setUTCMonth";        break;
           case :        arity=3; s="setFullYear";        break;
           case :     arity=3; s="setUTCFullYear";     break;
           case :            arity=1; s="setYear";            break;
           case :        arity=0; s="toISOString";        break;
           case :             arity=1; s="toJSON";             break;
           defaultthrow new IllegalArgumentException(String.valueOf(id));
         }
         initPrototypeMethod(idsarity);
     }
 
     @Override
     public Object execIdCall(IdFunctionObject fContext cxScriptable scope,
                              Scriptable thisObjObject[] args)
     {
         if (!f.hasTag()) {
             return super.execIdCall(fcxscopethisObjargs);
         }
         int id = f.methodId();
         switch (id) {
           case :
             return ScriptRuntime.wrapNumber(now());
 
           case :
             {
                 String dataStr = ScriptRuntime.toString(args, 0);
                 return ScriptRuntime.wrapNumber(date_parseString(dataStr));
             }
 
           case :
             return ScriptRuntime.wrapNumber(jsStaticFunction_UTC(args));
 
           case :
             {
                 // if called as a function, just return a string
                 // representing the current time.
                 if (thisObj != null)
                     return date_format(now(), );
                 return jsConstructor(args);
             }
 
           case :
             {
                 if (thisObj instanceof NativeDate) {
                     return ((NativeDatethisObj).toISOString();
                 }
 
                 final String toISOString = "toISOString";
 
                 Scriptable o = ScriptRuntime.toObject(cxscopethisObj);
                 Object tv = ScriptRuntime.toPrimitive(o.);
                 if (tv instanceof Number) {
                     double d = ((Numbertv).doubleValue();
                     if (d != d || Double.isInfinite(d)) {
                         return null;
                     }
                 }
                 Object toISO = o.get(toISOStringo);
                 if (toISO == ) {
                     throw ScriptRuntime.typeError2("msg.function.not.found.in",
                             toISOString,
                             ScriptRuntime.toString(o));
                 }
                 if ( !(toISO instanceof Callable) ) {
                     throw ScriptRuntime.typeError3("msg.isnt.function.in",
                             toISOString,
                             ScriptRuntime.toString(o),
                             ScriptRuntime.toString(toISO));
                 }
                 Object result = ((CallabletoISO).call(cxscopeo,
                             .);
                 if ( !ScriptRuntime.isPrimitive(result) ) {
                     throw ScriptRuntime.typeError1("msg.toisostring.must.return.primitive",
                             ScriptRuntime.toString(result));
                 }
                 return result;
             }
 
         }
 
         // The rest of Date.prototype methods require thisObj to be Date
 
         if (!(thisObj instanceof NativeDate))
             throw incompatibleCallError(f);
         NativeDate realThis = (NativeDate)thisObj;
         double t = realThis.date;
 
         switch (id) {
 
           case :
           case :
           case :
             if (t == t) {
                 return date_format(tid);
             }
             return ;
 
           case :
           case :
           case :
             if (t == t) {
                 return toLocale_helper(tid);
             }
             return ;
 
           case :
             if (t == t) {
                 return js_toUTCString(t);
             }
             return ;
 
           case :
             return "(new Date("+ScriptRuntime.toString(t)+"))";
 
           case :
           case :
             return ScriptRuntime.wrapNumber(t);
 
           case :
           case :
           case :
             if (t == t) {
                 if (id != t = LocalTime(t);
                 t = YearFromTime(t);
                 if (id == ) {
                     if (cx.hasFeature(.)) {
                         if (1900 <= t && t < 2000) {
                             t -= 1900;
                         }
                     } else {
                         t -= 1900;
                     }
                 }
             }
             return ScriptRuntime.wrapNumber(t);
 
           case :
           case :
             if (t == t) {
                 if (id == t = LocalTime(t);
                 t = MonthFromTime(t);
             }
             return ScriptRuntime.wrapNumber(t);
 
           case :
           case :
             if (t == t) {
                 if (id == t = LocalTime(t);
                 t = DateFromTime(t);
             }
             return ScriptRuntime.wrapNumber(t);
 
           case :
           case :
             if (t == t) {
                 if (id == t = LocalTime(t);
                 t = WeekDay(t);
             }
             return ScriptRuntime.wrapNumber(t);
 
           case :
           case :
             if (t == t) {
                 if (id == t = LocalTime(t);
                 t = HourFromTime(t);
             }
             return ScriptRuntime.wrapNumber(t);
 
           case :
           case :
             if (t == t) {
                 if (id == t = LocalTime(t);
                 t = MinFromTime(t);
             }
             return ScriptRuntime.wrapNumber(t);
 
           case :
           case :
             if (t == t) {
                 if (id == t = LocalTime(t);
                 t = SecFromTime(t);
             }
             return ScriptRuntime.wrapNumber(t);
 
           case :
           case :
             if (t == t) {
                 if (id == t = LocalTime(t);
                 t = msFromTime(t);
             }
             return ScriptRuntime.wrapNumber(t);
 
           case :
             if (t == t) {
                 t = (t - LocalTime(t)) / ;
             }
             return ScriptRuntime.wrapNumber(t);
 
           case :
             t = TimeClip(ScriptRuntime.toNumber(args, 0));
             realThis.date = t;
             return ScriptRuntime.wrapNumber(t);
 
           case :
           case :
           case :
           case :
           case :
           case :
           case :
           case :
             t = makeTime(targsid);
             realThis.date = t;
             return ScriptRuntime.wrapNumber(t);
 
           case :
           case :
           case :
           case :
           case :
           case :
             t = makeDate(targsid);
             realThis.date = t;
             return ScriptRuntime.wrapNumber(t);
 
           case :
             {
                 double year = ScriptRuntime.toNumber(args, 0);
 
                 if (year != year || Double.isInfinite(year)) {
                     t = .;
                 } else {
                     if (t != t) {
                         t = 0;
                     } else {
                         t = LocalTime(t);
                     }
 
                     if (year >= 0 && year <= 99)
                         year += 1900;
 
                     double day = MakeDay(yearMonthFromTime(t),
                                          DateFromTime(t));
                     t = MakeDate(dayTimeWithinDay(t));
                     t = internalUTC(t);
                     t = TimeClip(t);
                 }
             }
             realThis.date = t;
             return ScriptRuntime.wrapNumber(t);
 
           case :
             return realThis.toISOString();
 
           defaultthrow new IllegalArgumentException(String.valueOf(id));
         }
 
     }
 
     private String toISOString() {
         if ( == ) {
             synchronized () {
                 return .format(new Date((long));
             }
         }
         String msg = ScriptRuntime.getMessage0("msg.invalid.date");
         throw ScriptRuntime.constructError("RangeError"msg);
     }
 
     /* ECMA helper functions */
 
     private static final double HalfTimeDomain = 8.64e15;
     private static final double HoursPerDay    = 24.0;
     private static final double MinutesPerHour = 60.0;
     private static final double SecondsPerMinute = 60.0;
     private static final double msPerSecond    = 1000.0;
     private static final double MinutesPerDay  = ( * );
     private static final double SecondsPerDay  = ( * );
     private static final double SecondsPerHour = ( * );
     private static final double msPerDay       = ( * );
     private static final double msPerHour      = ( * );
     private static final double msPerMinute    = ( * );
 
     private static double Day(double t)
     {
         return Math.floor(t / );
     }
 
     private static double TimeWithinDay(double t)
     {
         double result;
         result = t % ;
         if (result < 0)
             result += ;
         return result;
     }
 
     private static boolean IsLeapYear(int year)
     {
         return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
     }
 
     /* math here has to be f.p, because we need
      *  floor((1968 - 1969) / 4) == -1
      */
     private static double DayFromYear(double y)
     {
         return ((365 * ((y)-1970) + Math.floor(((y)-1969)/4.0)
                  - Math.floor(((y)-1901)/100.0) + Math.floor(((y)-1601)/400.0)));
     }
 
     private static double TimeFromYear(double y)
     {
         return DayFromYear(y) * ;
     }
 
     private static int YearFromTime(double t)
     {
         int lo = (int) Math.floor((t / ) / 366) + 1970;
         int hi = (int) Math.floor((t / ) / 365) + 1970;
         int mid;
 
         /* above doesn't work for negative dates... */
         if (hi < lo) {
             int temp = lo;
             lo = hi;
             hi = temp;
         }
 
         /* Use a simple binary search algorithm to find the right
            year.  This seems like brute force... but the computation
            of hi and lo years above lands within one year of the
            correct answer for years within a thousand years of
            1970; the loop below only requires six iterations
            for year 270000. */
         while (hi > lo) {
             mid = (hi + lo) / 2;
             if (TimeFromYear(mid) > t) {
                 hi = mid - 1;
             } else {
                 lo = mid + 1;
                 if (TimeFromYear(lo) > t) {
                     return mid;
                 }
             }
         }
         return lo;
     }
 
     private static double DayFromMonth(int mint year)
     {
         int day = m * 30;
 
         if (m >= 7) { day += m / 2 - 1; }
         else if (m >= 2) { day += (m - 1) / 2 - 1; }
         else { day += m; }
 
         if (m >= 2 && IsLeapYear(year)) { ++day; }
 
         return day;
     }
 
     private static int MonthFromTime(double t)
     {
         int year = YearFromTime(t);
         int d = (int)(Day(t) - DayFromYear(year));
 
         d -= 31 + 28;
         if (d < 0) {
             return (d < -28) ? 0 : 1;
         }
 
         if (IsLeapYear(year)) {
             if (d == 0)
                 return 1; // 29 February
             --d;
         }
 
         // d: date count from 1 March
         int estimate = d / 30; // approx number of month since March
         int mstart;
         switch (estimate) {
             case 0: return 2;
             case 1: mstart = 31; break;
             case 2: mstart = 31+30; break;
             case 3: mstart = 31+30+31; break;
             case 4: mstart = 31+30+31+30; break;
             case 5: mstart = 31+30+31+30+31; break;
             case 6: mstart = 31+30+31+30+31+31; break;
             case 7: mstart = 31+30+31+30+31+31+30; break;
             case 8: mstart = 31+30+31+30+31+31+30+31; break;
             case 9: mstart = 31+30+31+30+31+31+30+31+30; break;
             case 10: return 11; //Late december
             defaultthrow Kit.codeBug();
         }
         // if d < mstart then real month since March == estimate - 1
         return (d >= mstart) ? estimate + 2 : estimate + 1;
     }
 
     private static int DateFromTime(double t)
     {
         int year = YearFromTime(t);
         int d = (int)(Day(t) - DayFromYear(year));
 
         d -= 31 + 28;
         if (d < 0) {
             return (d < -28) ? d + 31 + 28 + 1 : d + 28 + 1;
         }
 
         if (IsLeapYear(year)) {
             if (d == 0)
                 return 29; // 29 February
             --d;
         }
 
         // d: date count from 1 March
         int mdaysmstart;
         switch (d / 30) { // approx number of month since March
             case 0: return d + 1;
             case 1: mdays = 31; mstart = 31; break;
             case 2: mdays = 30; mstart = 31+30; break;
             case 3: mdays = 31; mstart = 31+30+31; break;
             case 4: mdays = 30; mstart = 31+30+31+30; break;
             case 5: mdays = 31; mstart = 31+30+31+30+31; break;
             case 6: mdays = 31; mstart = 31+30+31+30+31+31; break;
             case 7: mdays = 30; mstart = 31+30+31+30+31+31+30; break;
             case 8: mdays = 31; mstart = 31+30+31+30+31+31+30+31; break;
             case 9: mdays = 30; mstart = 31+30+31+30+31+31+30+31+30; break;
             case 10:
                 return d - (31+30+31+30+31+31+30+31+30) + 1; //Late december
             defaultthrow Kit.codeBug();
         }
         d -= mstart;
         if (d < 0) {
             // wrong estimate: sfhift to previous month
             d += mdays;
         }
         return d + 1;
      }
 
     private static int WeekDay(double t)
     {
         double result;
         result = Day(t) + 4;
         result = result % 7;
         if (result < 0)
             result += 7;
         return (intresult;
     }
 
     private static double now()
     {
         return System.currentTimeMillis();
     }
 
     private static double DaylightSavingTA(double t)
     {
         // Another workaround!  The JRE doesn't seem to know about DST
         // before year 1 AD, so we map to equivalent dates for the
         // purposes of finding DST. To be safe, we do this for years
         // before 1970.
         if (t < 0.0) {
             int year = EquivalentYear(YearFromTime(t));
             double day = MakeDay(yearMonthFromTime(t), DateFromTime(t));
             t = MakeDate(dayTimeWithinDay(t));
         }
         Date date = new Date((longt);
         if (.inDaylightTime(date))
             return ;
         else
             return 0;
     }
 
     /*
      * Find a year for which any given date will fall on the same weekday.
      *
      * This function should be used with caution when used other than
      * for determining DST; it hasn't been proven not to produce an
      * incorrect year for times near year boundaries.
      */
     private static int EquivalentYear(int year)
     {
         int day = (intDayFromYear(year) + 4;
         day = day % 7;
         if (day < 0)
             day += 7;
         // Years and leap years on which Jan 1 is a Sunday, Monday, etc.
         if (IsLeapYear(year)) {
             switch (day) {
                 case 0: return 1984;
                 case 1: return 1996;
                 case 2: return 1980;
                 case 3: return 1992;
                 case 4: return 1976;
                 case 5: return 1988;
                 case 6: return 1972;
             }
         } else {
             switch (day) {
                 case 0: return 1978;
                 case 1: return 1973;
                 case 2: return 1985;
                 case 3: return 1986;
                 case 4: return 1981;
                 case 5: return 1971;
                 case 6: return 1977;
             }
         }
         // Unreachable
         throw Kit.codeBug();
     }
 
     private static double LocalTime(double t)
     {
         return t +  + DaylightSavingTA(t);
     }
 
     private static double internalUTC(double t)
     {
         return t -  - DaylightSavingTA(t - );
     }
 
     private static int HourFromTime(double t)
     {
         double result;
         result = Math.floor(t / ) % ;
         if (result < 0)
             result += ;
         return (intresult;
     }
 
     private static int MinFromTime(double t)
     {
         double result;
         result = Math.floor(t / ) % ;
         if (result < 0)
             result += ;
         return (intresult;
     }
 
     private static int SecFromTime(double t)
     {
         double result;
         result = Math.floor(t / ) % ;
         if (result < 0)
             result += ;
         return (intresult;
     }
 
     private static int msFromTime(double t)
     {
         double result;
         result =  t % ;
         if (result < 0)
             result += ;
         return (intresult;
     }
 
     private static double MakeTime(double hourdouble min,
                                    double secdouble ms)
     {
         return ((hour *  + min) *  + sec)
             *  + ms;
     }
 
     private static double MakeDay(double yeardouble monthdouble date)
     {
         year += Math.floor(month / 12);
 
         month = month % 12;
         if (month < 0)
             month += 12;
 
         double yearday = Math.floor(TimeFromYear(year) / );
         double monthday = DayFromMonth((int)month, (int)year);
 
         return yearday + monthday + date - 1;
     }
 
     private static double MakeDate(double daydouble time)
     {
         return day *  + time;
     }
 
     private static double TimeClip(double d)
     {
         if (d != d ||
             d == . ||
             d == . ||
             Math.abs(d) > )
         {
             return .;
         }
         if (d > 0.0)
             return Math.floor(d + 0.);
         else
             return Math.ceil(d + 0.);
     }
 
     /* end of ECMA helper functions */
 
     /* find UTC time from given date... no 1900 correction! */
     private static double date_msecFromDate(double yeardouble mon,
                                             double mdaydouble hour,
                                             double mindouble sec,
                                             double msec)
     {
         double day;
         double time;
         double result;
 
         day = MakeDay(yearmonmday);
         time = MakeTime(hourminsecmsec);
         result = MakeDate(daytime);
         return result;
     }
 
     /* compute the time in msec (unclipped) from the given args */
     private static final int MAXARGS = 7;
     private static double date_msecFromArgs(Object[] args)
     {
         double array[] = new double[];
         int loop;
         double d;
 
         for (loop = 0; loop < loop++) {
             if (loop < args.length) {
                 d = ScriptRuntime.toNumber(args[loop]);
                 if (d != d || Double.isInfinite(d)) {
                     return .;
                 }
                 array[loop] = ScriptRuntime.toInteger(args[loop]);
             } else {
                 if (loop == 2) {
                     array[loop] = 1; /* Default the date argument to 1. */
                 } else {
                     array[loop] = 0;
                 }
             }
         }
 
         /* adjust 2-digit years into the 20th century */
         if (array[0] >= 0 && array[0] <= 99)
             array[0] += 1900;
 
         return date_msecFromDate(array[0], array[1], array[2],
                                  array[3], array[4], array[5], array[6]);
     }
 
     private static double jsStaticFunction_UTC(Object[] args)
     {
         return TimeClip(date_msecFromArgs(args));
     }
 
     private static double date_parseString(String s)
     {
         try {
           if (s.length() == 24) {
               final Date d;
               synchronized() {
                   d = .parse(s);
               }
               return d.getTime();
           }
         } catch (java.text.ParseException ex) {}
 
         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;
 
         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 .;
                     tzoffset = n;
                 } else if (n >= 70  ||
                            (prevc == '/' && mon >= 0 && mday >= 0
                             && year < 0))
                 {
                     if (year >= 0)
                         return .;
                     else if (c <= ' ' || c == ',' || c == '/' || i >= limit)
                         year = n < 100 ? n + 1900 : n;
                     else
                         return .;
                 } else if (c == ':') {
                     if (hour < 0)
                         hour = /*byte*/ n;
                     else if (min < 0)
                         min = /*byte*/ n;
                     else
                         return .;
                 } else if (c == '/') {
                     if (mon < 0)
                         mon = /*byte*/ n-1;
                     else if (mday < 0)
                         mday = /*byte*/ n;
                     else
                         return .;
                 } else if (i < limit && c != ',' && c > ' ' && c != '-') {
                     return .;
                 } 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 .;
                 }
                 prevc = 0;
             } else if (c == '/' || c == ':' || c == '+' || c == '-') {
                 prevc = c;
             } else {
                 int st = i - 1;
                 while (i < limit) {
                     c = s.charAt(i);
                     if (!(('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z')))
                         break;
                     i++;
                 }
                 int letterCount = i - st;
                 if (letterCount < 2)
                     return .;
                /*
                 * 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?
                 */
                 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;";
                 int index = 0;
                 for (int wtbOffset = 0; ;) {
                     int wtbNext = wtb.indexOf(';'wtbOffset);
                     if (wtbNext < 0)
                         return .;
                     if (wtb.regionMatches(truewtbOffsetsstletterCount))
                         break;
                     wtbOffset = wtbNext + 1;
                     ++index;
                 }
                 if (index < 2) {
                     /*
                      * 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 .;
                     } else if (index == 0) {
                         // AM
                         if (hour == 12)
                             hour = 0;
                     } else {
                         // PM
                         if (hour != 12)
                             hour += 12;
                     }
                 } else if ((index -= 2) < 7) {
                     // ignore week days
                 } else if ((index -= 7) < 12) {
                     // month
                     if (mon < 0) {
                         mon = index;
                     } else {
                         return .;
                     }
                 } else {
                     index -= 12;
                     // timezones
                     switch (index) {
                       case 0 /* gmt */tzoffset = 0; break;
                       case 1 /* ut */:  tzoffset = 0; break;
                       case 2 /* utc */tzoffset = 0; break;
                       case 3 /* est */tzoffset = 5 * 60; break;
                       case 4 /* edt */tzoffset = 4 * 60; break;
                       case 5 /* cst */tzoffset = 6 * 60; break;
                       case 6 /* cdt */tzoffset = 5 * 60; break;
                       case 7 /* mst */tzoffset = 7 * 60; break;
                       case 8 /* mdt */tzoffset = 6 * 60; break;
                       case 9 /* pst */tzoffset = 8 * 60; break;
                       case 10 /* pdt */:tzoffset = 7 * 60; break;
                       default: Kit.codeBug();
                     }
                 }
             }
         }
         if (year < 0 || mon < 0 || mday < 0)
             return .;
         if (sec < 0)
             sec = 0;
         if (min < 0)
             min = 0;
         if (hour < 0)
             hour = 0;
 
         double msec = date_msecFromDate(yearmonmdayhourminsec, 0);
         if (tzoffset == -1) { /* no time zone specified, have to use local */
             return internalUTC(msec);
         } else {
            return msec + tzoffset * ;
        }
    }
    private static String date_format(double tint methodId)
    {
        StringBuffer result = new StringBuffer(60);
        double local = LocalTime(t);
        /* Tue Oct 31 09:41:40 GMT-0800 (PST) 2000 */
        /* Tue Oct 31 2000 */
        /* 09:41:40 GMT-0800 (PST) */
        if (methodId != ) {
            appendWeekDayName(resultWeekDay(local));
            result.append(' ');
            appendMonthName(resultMonthFromTime(local));
            result.append(' ');
            append0PaddedUint(resultDateFromTime(local), 2);
            result.append(' ');
            int year = YearFromTime(local);
            if (year < 0) {
                result.append('-');
                year = -year;
            }
            append0PaddedUint(resultyear, 4);
            if (methodId != )
                result.append(' ');
        }
        if (methodId != ) {
            append0PaddedUint(resultHourFromTime(local), 2);
            result.append(':');
            append0PaddedUint(resultMinFromTime(local), 2);
            result.append(':');
            append0PaddedUint(resultSecFromTime(local), 2);
            // offset from GMT in minutes.  The offset includes daylight
            // savings, if it applies.
            int minutes = (int) Math.floor(( + DaylightSavingTA(t))
                                           / );
            // map 510 minutes to 0830 hours
            int offset = (minutes / 60) * 100 + minutes % 60;
            if (offset > 0) {
                result.append(" GMT+");
            } else {
                result.append(" GMT-");
                offset = -offset;
            }
            append0PaddedUint(resultoffset, 4);
            if ( == null)
                 = new SimpleDateFormat("zzz");
            // Find an equivalent year before getting the timezone
            // comment.  See DaylightSavingTA.
            if (t < 0.0) {
                int equiv = EquivalentYear(YearFromTime(local));
                double day = MakeDay(equivMonthFromTime(t), DateFromTime(t));
                t = MakeDate(dayTimeWithinDay(t));
            }
            result.append(" (");
            Date date = new Date((longt);
            synchronized () {
                result.append(.format(date));
            }
            result.append(')');
        }
        return result.toString();
    }
    /* the javascript constructor */
    private static Object jsConstructor(Object[] args)
    {
        NativeDate obj = new NativeDate();
        // if called as a constructor with no args,
        // return a new Date with the current time.
        if (args.length == 0) {
            obj.date = now();