gnash-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Gnash-commit] gnash ChangeLog configure.ac doc/C/asspec/date....


From: Martin Guy
Subject: [Gnash-commit] gnash ChangeLog configure.ac doc/C/asspec/date....
Date: Wed, 18 Apr 2007 13:47:25 +0000

CVSROOT:        /sources/gnash
Module name:    gnash
Changes by:     Martin Guy <martinwguy> 07/04/18 13:47:24

Modified files:
        .              : ChangeLog configure.ac 
        doc/C/asspec   : date.xml 
        server/asobj   : Date.cpp Global.cpp 
        server         : as_value.h as_value.cpp 
        testsuite/actionscript.all: Date.as 

Log message:
                * configure.ac: Introduce HAVE_LONG_TIMEZONE if extern long 
timezone
                  exists
                * doc/C/asspec/date.xml: first draft
                * server/asobj/Date.cpp: Complete its implementation
                * server/asobj/Global.cpp: Use definitions of NAN and INFINITY 
from
                  as_value.h
                * server/as_value.h: add definition for INFINITY, as for NAN
                * server/as_value.cpp: Reject accidental "Infinity" and 
"-Infinity"
                  string-to-number conversions (should give NaN); 
                  Use NAN from as_value.h;
                  Conversion of an AS function to a number gives NaN, not 0.
                * testsuite/actionscript.all/Date.as: Add extensive constructor 
tests

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/ChangeLog?cvsroot=gnash&r1=1.2908&r2=1.2909
http://cvs.savannah.gnu.org/viewcvs/gnash/configure.ac?cvsroot=gnash&r1=1.290&r2=1.291
http://cvs.savannah.gnu.org/viewcvs/gnash/doc/C/asspec/date.xml?cvsroot=gnash&r1=1.1&r2=1.2
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/Date.cpp?cvsroot=gnash&r1=1.41&r2=1.42
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/Global.cpp?cvsroot=gnash&r1=1.59&r2=1.60
http://cvs.savannah.gnu.org/viewcvs/gnash/server/as_value.h?cvsroot=gnash&r1=1.44&r2=1.45
http://cvs.savannah.gnu.org/viewcvs/gnash/server/as_value.cpp?cvsroot=gnash&r1=1.38&r2=1.39
http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/actionscript.all/Date.as?cvsroot=gnash&r1=1.20&r2=1.21

Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/gnash/gnash/ChangeLog,v
retrieving revision 1.2908
retrieving revision 1.2909
diff -u -b -r1.2908 -r1.2909
--- ChangeLog   18 Apr 2007 13:24:44 -0000      1.2908
+++ ChangeLog   18 Apr 2007 13:47:24 -0000      1.2909
@@ -1,3 +1,18 @@
+2007-04-18 Martin Guy <address@hidden>
+
+       * configure.ac: Introduce HAVE_LONG_TIMEZONE if extern long timezone
+         exists
+       * doc/C/asspec/date.xml: first draft
+       * server/asobj/Date.cpp: Complete its implementation
+       * server/asobj/Global.cpp: Use definitions of NAN and INFINITY from     
+         as_value.h
+       * server/as_value.h: add definition for INFINITY, as for NAN
+       * server/as_value.cpp: Reject accidental "Infinity" and "-Infinity"
+         string-to-number conversions (should give NaN);
+         Use NAN from as_value.h;
+         Conversion of an AS function to a number gives NaN, not 0.
+       * testsuite/actionscript.all/Date.as: Add extensive constructor tests
+
 2007-04-18 Sandro Santilli <address@hidden>
 
        * server/matrix.{cpp,h}: add transform_by_inverse(point&).

Index: configure.ac
===================================================================
RCS file: /sources/gnash/gnash/configure.ac,v
retrieving revision 1.290
retrieving revision 1.291
diff -u -b -r1.290 -r1.291
--- configure.ac        10 Apr 2007 18:18:45 -0000      1.290
+++ configure.ac        18 Apr 2007 13:47:24 -0000      1.291
@@ -15,7 +15,7 @@
 dnl  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 dnl  
 
-dnl $Id: configure.ac,v 1.290 2007/04/10 18:18:45 rsavoye Exp $
+dnl $Id: configure.ac,v 1.291 2007/04/18 13:47:24 martinwguy Exp $
 
 AC_PREREQ(2.50)
 AC_INIT(gnash, cvs)
@@ -488,12 +488,56 @@
 AC_LANG_POP(C++)
 AC_REPLACE_FUNCS(getopt)
 
-AC_CHECK_FUNCS(sysconf)
-AC_CHECK_FUNCS(shmget shmat shmdt mmap)
+dnl Date portability stuff, used in server/asobj/Date.cpp
 AC_CHECK_FUNCS(gettimeofday)
 AC_CHECK_FUNCS(ftime)
 AC_CHECK_FUNCS(tzset)
 AC_CHECK_FUNCS(localtime_r)
+
+AC_CACHE_CHECK([whether struct tm has tm_gmtoff], ac_cv_tm_gmtoff, [
+        AC_TRY_LINK([
+/* ctime(1) says "The glibc version of struct tm has additional fields
+ * defined  when _BSD_SOURCE was set before including <time.h>"
+ * In practice, you don't need to define it yourself (tested on glibc-2.2.1 
+ * and 2.3.6) but if you *do* define it yourself, it makes *all* functions
+ * favour BSD-like behaviour over of GNU/POSIX, which seems dangerous.
+ */
+// #define _BSD_SOURCE 1
+#include <time.h>
+], 
+                [ struct tm tm; long l = tm.tm_gmtoff; ], 
+                [ ac_cv_tm_gmtoff="yes" ],
+                [ ac_cv_tm_gmtoff="no" ]
+        )
+])
+if test "x$ac_cv_tm_gmtoff" = "xyes" ; then
+        AC_DEFINE(HAVE_TM_GMTOFF, [1], [struct tm has member tm_gmtoff])
+fi
+
+AC_CACHE_CHECK([whether timezone is a long], ac_cv_long_timezone, [
+        AC_TRY_LINK([
+/* On Linux/glibc, tzset(3) says "extern long timezone;" (seconds West of GMT)
+ * but on BSD char *timezone(int,int) is a function returning a string name.
+ * The BSD function timegm() may be the equivalent, but this should
+ * not be necessary because on BSD the code should use tm.tm_gmtoff instead
+ * (use of long timezone is a fallback strategy for when tm_gmtoff exists not).
+ */
+#include <stdio.h>
+#include <time.h>
+extern long timezone;
+], 
+                [ printf("%ld", timezone); ], 
+                [ ac_cv_long_timezone="yes" ],
+                [ ac_cv_long_timezone="no" ]
+        )
+])
+if test "x$ac_cv_long_timezone" = "xyes" ; then
+        AC_DEFINE(HAVE_LONG_TIMEZONE, [1], [extern timezone is a long integer, 
not a function])
+fi
+
+
+AC_CHECK_FUNCS(sysconf)
+AC_CHECK_FUNCS(shmget shmat shmdt mmap)
 AC_CHECK_FUNCS(memmove)
 AC_CHECK_FUNCS(strlcpy, AC_DEFINE(HAVE_STRLCPY_PROTO, [1],[Define if you have 
the strlcpy prototype]))
 AC_CHECK_FUNCS(strlcat, AC_DEFINE(HAVE_STRLCAT_PROTO, [1],[Define if you have 
the strlcat prototype]))

Index: doc/C/asspec/date.xml
===================================================================
RCS file: /sources/gnash/gnash/doc/C/asspec/date.xml,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -b -r1.1 -r1.2
--- doc/C/asspec/date.xml       29 Mar 2007 22:09:44 -0000      1.1
+++ doc/C/asspec/date.xml       18 Apr 2007 13:47:24 -0000      1.2
@@ -2,7 +2,7 @@
   <title>Date ActionScript Class</title>
 
   <para>
-    This class implements an Date object.
+    This class implements the Date object.
   </para>
 
   <sect5 id="datemethods">
@@ -14,6 +14,8 @@
          <term>getDate()</term>
          <listitem>
            <para>
+               Returns a Date's day-of-month from 1 to 31
+               according to local time.
            </para>
          </listitem>
        </varlistentry>
@@ -22,6 +24,9 @@
          <term>getDay()</term>
          <listitem>
            <para>
+               Returns the day-of-the-week for a Date,
+               according to local time,
+               in the range 0-6 where 0 means Sunday and 6 means Saturday.
            </para>
          </listitem>
        </varlistentry>
@@ -30,6 +35,11 @@
          <term>getFullYear()</term>
          <listitem>
            <para>
+               Returns the Gregorian year number for a Date,
+               according to local time.
+               Since Gnash currently uses POSIX date routines internally,
+               this probably only works for dates from
+               13 Dec 1901 to 19 Jan 2038.
            </para>
          </listitem>
        </varlistentry>
@@ -38,6 +48,9 @@
          <term>getHours()</term>
          <listitem>
            <para>
+               Returns the hour-of-the-day for a Date,
+               according to local time,
+               in the range 0-23.
            </para>
          </listitem>
        </varlistentry>
@@ -46,6 +59,8 @@
          <term>getMilliseconds()</term>
          <listitem>
            <para>
+               Returns the milliseconds component of a Date
+               as an integer in the range 0-999.
            </para>
          </listitem>
        </varlistentry>
@@ -54,6 +69,9 @@
          <term>getMinutes()</term>
          <listitem>
            <para>
+               Returns the minutes-past-the-hour for a Date,
+               according to local time,
+               in the range 0-59.
            </para>
          </listitem>
        </varlistentry>
@@ -62,6 +80,9 @@
          <term>getMonth()</term>
          <listitem>
            <para>
+               Returns the month of the year for a Date,
+               according to local time,
+               in the range 0-11 where 0 means January and 11 means December.
            </para>
          </listitem>
        </varlistentry>
@@ -70,6 +91,8 @@
          <term>getSeconds()</term>
          <listitem>
            <para>
+               Returns the seconds past the minute for a Date,
+               in the range 0-59.
            </para>
          </listitem>
        </varlistentry>
@@ -78,6 +101,11 @@
          <term>getTime()</term>
          <listitem>
            <para>
+               Returns the number of milliseconds elapsed since 
+               1 Jan 1970 00:00:00 in Universal Coordinated Time,
+               as a floating point number: fractions of milliseconds
+               are included.
+               Negative values indicate times before 1 Jan 1970.
            </para>
          </listitem>
        </varlistentry>
@@ -86,6 +114,20 @@
          <term>getTimezoneOffset()</term>
          <listitem>
            <para>
+               Returns the difference between Universal Coordinated Time
+               and the local time represented by a Date, including
+               Daylight Savings Time if it was in effect at that time
+               in the current locale.
+               The return value is in minutes; negative for timezones east of
+               Greenwich and positive for those west of Greenwich.
+           </para>
+           <para>
+               For example in the GMT+1 timezone, one hour east of Greenwich,
+               for a time when DST was not in effect,
+               the result would be -60.
+               In the same timezone when DST is in effect,
+               the extra hour in advance of UTC makes the value -120.
+               Positive values are returned for locales west of Greenwich.
            </para>
          </listitem>
        </varlistentry>
@@ -94,6 +136,8 @@
          <term>getUTCDate()</term>
          <listitem>
            <para>
+               Returns a Date's day-of-month from 1 to 31,
+               according to Universal Coordinated Time.
            </para>
          </listitem>
        </varlistentry>
@@ -102,6 +146,9 @@
          <term>getUTCDay()</term>
          <listitem>
            <para>
+               Returns the day-of-the-week for a Date,
+               according to local time,
+               in the range 0-6 where 0 means Sunday and 6 means Saturday.
            </para>
          </listitem>
        </varlistentry>
@@ -110,6 +157,11 @@
          <term>getUTCFullYear()</term>
          <listitem>
            <para>
+               Returns the Gregorian year number for a Date,
+               according to Universal Coordinated Time.
+               Since Gnash currently uses POSIX date routines internally,
+               this probably only works for dates from
+               13 Dec 1901 to 19 Jan 2038.
            </para>
          </listitem>
        </varlistentry>
@@ -118,6 +170,9 @@
          <term>getUTCHours()</term>
          <listitem>
            <para>
+                       Returns the hour-of-the-day for a Date,
+                       according to Universal Coordinated Time,
+               in the range 0-23.
            </para>
          </listitem>
        </varlistentry>
@@ -126,6 +181,8 @@
          <term>getUTCMilliseconds()</term>
          <listitem>
            <para>
+               Returns the milliseconds component of a Date
+               as an integer in the range 0-999.
            </para>
          </listitem>
        </varlistentry>
@@ -134,6 +191,9 @@
          <term>getUTCMinutes()</term>
          <listitem>
            <para>
+               Returns the minutes-past-the-hour for a Date,
+               according to Universal Coordinated Time,
+               in the range 0-59.
            </para>
          </listitem>
        </varlistentry>
@@ -142,6 +202,9 @@
          <term>getUTCMonth()</term>
          <listitem>
            <para>
+               Returns the month of the year for a Date,
+               according to Universal Coordinated Time,
+               in the range 0-11 where 0 means January and 11 means December.
            </para>
          </listitem>
        </varlistentry>
@@ -150,6 +213,8 @@
          <term>getUTCSeconds()</term>
          <listitem>
            <para>
+               Returns the seconds past the minute for a Date,
+               in the range 0-59.
            </para>
          </listitem>
        </varlistentry>
@@ -158,30 +223,91 @@
          <term>getYear()</term>
          <listitem>
            <para>
+               Returns the number of Gregorian years elapsed between 1900
+               and a Date,
+               according to local time.
+           </para>
+           <para>
+               For dates past 1st Jan 2000 it returns values from 100 onwards;
+               for years before 1900 it returns negative values.
+           </para>
+           <para>
+               This function is a historical wart left over from the days when
+               nobody could believe we would still be using Flash in 2000.
            </para>
          </listitem>
        </varlistentry>
 
        <varlistentry>
-         <term>setDate()</term>
+         <term>setDate(dayofmonth)</term>
          <listitem>
            <para>
+               Sets the day-of-month for a Date object,
+               in the range 1-31, leaving the year, month, and
+               time-of-day unchanged for valid values.
+           </para>
+           <para>
+               If dayofmonth is greater than the number of days in the
+               month in question, it wraps into the following month:
+               for example, trying to set the 35th to a date in January
+               will result in the 4th of February.
+               If it is zero or negative, this will take the Date back
+               to a previous month and possibly a previous year.
+           </para>
+           <para>
+               If there are no parameters to setDate,
+               if dayofmonth is not of type Number
+               (or a String that contains a decimal number
+               or the Boolean values "true" and "false",
+               which behave the same as 1 and 0)
+               is an infinity or NotANumber,
+               this sets the value of the Date object to "Not A Number",
+               which is converted to a string as "Invalid date".
            </para>
          </listitem>
        </varlistentry>
 
        <varlistentry>
-         <term>setFullYear()</term>
+         <term>setFullYear(year,[month[,dayofmonth]])</term>
          <listitem>
            <para>
+               If a single parameter is given, this
+               sets the Gregorian year number for a Date,
+               normally leaving the month and day-of-month unchanged.
+           </para>
+           <para>
+               When changing from a leap year to a non-leap year
+               when the date is set to 29th February,
+               the resulting date is 1st March of the same year.
+           </para>
+           <para>
+               If month, and maybe dayofmonth, are also given, they
+               simultaneously set the month (and day of month), following
+               the usual rules whereby excessively large or negative values
+               carry over to affect the month or year and still give a
+               valid date.
+           </para>
+           <para>
+               If any supplied value cannot be converted to a valid number,
+               the Date's value is set to NotANumber.
            </para>
          </listitem>
        </varlistentry>
 
        <varlistentry>
-         <term>setHours()</term>
+         <term>setHours(hour)</term>
          <listitem>
            <para>
+               Sets the hour-of-the-day, normally in the range 0-23,
+               leaving the calendar date and minutes/seconds unchanged.
+           </para>
+           <para>
+               Values greater than 23 will make the date roll over to one of
+               the following days; negative values will result in previous
+               dates.
+               If no parameter is given, or if it is not of a type that can be
+               converted to a number, the resulting date value is NotANumber,
+               which prints as "Invalid date".
            </para>
          </listitem>
        </varlistentry>
@@ -190,30 +316,117 @@
          <term>setMilliseconds()</term>
          <listitem>
            <para>
+               Sets the milliseconds with a resolution of one millisecond:
+               fractional parts of a millisecond are ignored.
+           </para>
+           <para>
+               The parameter is normally a value from 0-999, but values
+               outside this range will carry over into, or borrow from,
+               the seconds (and minutes, hours etc if necessary).
            </para>
+           <para>
+               If no parameters are given, or if the parameter cannot
+               be converted to a number, the Date's value is set to
+               NotANumber. Any extra parameters are ignored.
          </listitem>
        </varlistentry>
 
        <varlistentry>
-         <term>setMinutes()</term>
+         <term>setMinutes(minutes[,seconds[,milliseconds]])</term>
          <listitem>
            <para>
+               Sets the minutes-past-the-hour normally in the range 0-59,
+               leaving the calendar date and hour/seconds unchanged.
+           </para>
+           <para>
+               "Minutes" greater than 59 carry over into the hours (and
+               may consequently advance the date);
+               simiarly, negative values borrow from them.
+           </para>
+           <para>
+               The optional second and third parameters simultaneously set
+               the seconds and millisecond components,
+               with similar carry/borrow if they are outside the ranges
+               0-59 and 0-999;
+               fractions of seconds and milliseconds are ignored.
+           </para>
+           <para>
+               If no parameter is given, or if it is not of a type that can be
+               converted to a number, the resulting date value is NotANumber,
+               which prints as "Invalid date".
+               Gnash differs from the commercial Flash player in this,
+               which, given a non-numeric value for "minutes",
+               returns a seemingly random date such as 9th December, 2077 BC.
            </para>
          </listitem>
        </varlistentry>
 
        <varlistentry>
-         <term>setMonth()</term>
+         <term>setMonth(month[,day])</term>
          <listitem>
            <para>
+               Sets the month of the year, normally in the range 0-11,
+               leaving the year and time of day (in localtime) unchanged.
+           </para>
+           <para>
+               Values greater than 11 will make the date roll over into a
+               following year; negative values will result in previous
+               years.
+           </para>
+           <para>
+               If only the month is given, the new month has less days that
+               the old, and the day-of-month is beyond the end of the new
+               month, the date wraps over into the first days of the month
+               after the specified one. Gnash differs in this from the
+               commercial player, which leaves the date set to the last day
+               of the requested month.
+           </para>
+           <para>
+               If no parameter is given, or if it is not of a type that can
+               be converted to a number, the month is set to January without
+               changing the year.
+           </para>
+           <para>
+               If the optional extra parameter "day" is given, both the
+               month and day-of-month are set. As usual, day numbers beyond
+               the last day of the selected month wrap over into the following
+               month(s), and negative values take us back to previous months
+               and possibly years.
+           </para>
+           <para>
+               Unlike the "month" parameter, non-numeric values for "day"
+               result in the Date's value being set to NotANumber.
+           </para>
+           <para>
+               Any further parameters are ignored.
            </para>
          </listitem>
        </varlistentry>
 
        <varlistentry>
-         <term>setSeconds()</term>
+         <term>setSeconds(seconds[,milliseconds])</term>
          <listitem>
            <para>
+               Sets the seconds component of a Date.
+               If the value of "seconds" is from 0-59, the hours and
+               minutes will be unchanged.
+           </para>
+           <para>
+               An optional extra parameter can be used to simultanously
+               set the milliseconds, though only to a precision of
+               one millisecond: fractions of milliseconds can be given
+               but are ignored). Likewise, any fractional part of a second
+               is ignored.
+           </para>
+           <para>
+               As usual, values outside the range 0-999 for milliseconds
+               are (added or subtracted) from the seconds,
+               and values outside the range 0-59 for the seconds carry over
+               into the minutes, hours etc.
+           </para>
+           <para>
+               Non-numerical values for "seconds" or "milliseconds"
+               result in the Date's value being set to NotANumber.
            </para>
          </listitem>
        </varlistentry>
@@ -222,7 +435,15 @@
          <term>setTime()</term>
          <listitem>
            <para>
+               Sets a Date object to a specified number of milliseconds
+               since 1 Jan 1970 in Universal Coordinated Time.
+               Fractions of milliseconds are ignored;
+               the only way to set a a date to sub-millisecond accuracy
+               is to use the single-argument version of the Date constructor.
            </para>
+           <para>
+               If no parameters are supplied, or if the parameter cannot be
+               converted to a number, the Date's value is set to NotANumber.
          </listitem>
        </varlistentry>
 
@@ -230,6 +451,8 @@
          <term>setUTCDate()</term>
          <listitem>
            <para>
+               Is the same as setDate(),
+               but specifying the time in Universal Coordinated Time.
            </para>
          </listitem>
        </varlistentry>
@@ -238,6 +461,8 @@
          <term>setUTCFullYear()</term>
          <listitem>
            <para>
+               Is the same as setFullYear(),
+               but specifying the time in Universal Coordinated Time.
            </para>
          </listitem>
        </varlistentry>
@@ -246,6 +471,8 @@
          <term>setUTCHours()</term>
          <listitem>
            <para>
+               Is the same as setHours(),
+               but specifying the time in Universal Coordinated Time.
            </para>
          </listitem>
        </varlistentry>
@@ -254,6 +481,7 @@
          <term>setUTCMilliseconds()</term>
          <listitem>
            <para>
+               Is the same as setMilliseconds().
            </para>
          </listitem>
        </varlistentry>
@@ -262,6 +490,14 @@
          <term>setUTCMinutes()</term>
          <listitem>
            <para>
+               Is the same as setMinutes(),
+               but specifying the time in Universal Coordinated Time.
+           </para>
+           <para>
+               This differs from setMinutes in countries that have
+               a time offset that is not a whole number of hours and on
+               Lord Howe Island which also has daylight savings time of
+               half an hour.
            </para>
          </listitem>
        </varlistentry>
@@ -270,6 +506,8 @@
          <term>setUTCMonth()</term>
          <listitem>
            <para>
+               Is the same as setMonth(),
+               but specifying the time in Universal Coordinated Time.
            </para>
          </listitem>
        </varlistentry>
@@ -278,14 +516,19 @@
          <term>setUTCSeconds()</term>
          <listitem>
            <para>
+               Is the same as setSeconds(),
            </para>
          </listitem>
        </varlistentry>
 
        <varlistentry>
-         <term>setYear()</term>
+         <term>setYear(year[,month[,dayofmonth]])</term>
          <listitem>
            <para>
+               Is the same as setFullYear(), except that values from
+               0 to 99 specify the years 1900 to 1999, and negative values
+               specify a year prior to 1900. Thus the only way to specify
+               the year 55AD with this method is to use -1845.
            </para>
          </listitem>
        </varlistentry>
@@ -294,14 +537,41 @@
          <term>toString()</term>
          <listitem>
            <para>
+               Converts a Date object to a printable string in the form
+               "Thu Jan 1 00:00:00 GMT+0000 1970" in local time, according to
+               the local timezone and whether Daylight Saving Time
+               was in force at the time in question.
+           </para>
+           <para>
+               If the Date's value is NotANumber or Infinity,
+               the string "Invalid Date" is returned.
            </para>
          </listitem>
        </varlistentry>
 
        <varlistentry>
-         <term>UTC()</term>
+         
<term>UTC(year,month[,dayofmonth[,hour[,minutes[,seconds[,milliseconds]]]]])</term>
          <listitem>
            <para>
+               Is a static function that converts the specified time,
+               expressed in Universal Coordinated Time,
+               to a Date value. It is most often used in conjunction with
+               the Date constructor or the setTime method, to create a
+               Date object according to UTC.
+           </para>
+           <para>
+               All parameters are 0-based except "month" which is 1-based,
+               and the usual carry/borrow rules apply for oversized and
+               negative values.
+           </para>
+           <para>
+               A missing day-of-month defaults to the first of the month;
+               the other parameters default to zero.
+           </para>
+           <para>
+               If less than two paramemters are supplied, or if any supplied
+               parameters cannot be converted to numeric values, the Date's
+               value is set to NotANumber.
            </para>
          </listitem>
        </varlistentry>
@@ -333,7 +603,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -343,7 +613,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -353,7 +623,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -363,7 +633,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -373,7 +643,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -383,7 +653,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -393,7 +663,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -403,7 +673,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -413,7 +683,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -423,7 +693,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -433,7 +703,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -443,7 +713,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -453,7 +723,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -463,7 +733,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -473,7 +743,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -483,7 +753,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -493,7 +763,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -503,7 +773,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -513,7 +783,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -523,7 +793,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -533,7 +803,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -543,7 +813,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -553,7 +823,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -563,7 +833,13 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
+               </para>
+               <para>
+                 The commercial player, given d.setMinutes(), leaves the
+                 date set to a random value such as 9th December 2077 BC.
+                 Gnash gives NotANumber, in the same way as all the
+                 other functions.
                </para>
              </entry>
            </row>
@@ -573,7 +849,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -583,7 +859,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -593,7 +869,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -603,7 +879,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -613,7 +889,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -623,7 +899,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -633,7 +909,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -643,7 +919,8 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
+                 See setMinutes above.
                </para>
              </entry>
            </row>
@@ -653,7 +930,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -663,7 +940,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -673,7 +950,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -683,7 +960,7 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
                </para>
              </entry>
            </row>
@@ -693,7 +970,12 @@
              </entry>
              <entry valign="top" align="center">
                <para>
-                 This method is unimplemented.
+                 Implemented.
+               </para>
+               <para>
+                 The commercial player, given Date.UTC(Infinity, 0),
+                 returns -6.77681005679712e+19;
+                 Gnash returns NAN if any parameter is non-numeric.
                </para>
              </entry>
            </row>

Index: server/asobj/Date.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/Date.cpp,v
retrieving revision 1.41
retrieving revision 1.42
diff -u -b -r1.41 -r1.42
--- server/asobj/Date.cpp       18 Apr 2007 11:00:29 -0000      1.41
+++ server/asobj/Date.cpp       18 Apr 2007 13:47:24 -0000      1.42
@@ -22,10 +22,6 @@
 // Implements methods of the ActionScript "Date" class for Gnash
 //
 // TODO:
-//     implement static method Date.UTC
-//     Make Date constructor treat years <100 as after (or before) 1900.
-//     Check whether Date.TimezoneOffset just returns geographical timezone
-//     or if it also includes DST in force at the specified moment.
 //     What does Flash setTime() do/return if you hand it 0 parameters?
 //
 // BUGS:
@@ -36,20 +32,17 @@
 //     this is not worth doing unless we also implement full-range localtime
 //     operations too.
 //
-//     If day=31 and you setYear() to April, or if you change Feb 29 from a
-//     leap year to a non-leap year, the date should "wrap" into the next
-//     month; our current code does not modify the date at all.
-//
-//     If setMonth is called with one parameter, the new month has fewer
-//     days than the old and the old day is beyond the end of the new month,
-//     the day-of-month should be set to the last day of the requested month
-//     (our current code wraps it into the first days of the following month).
+//     We probably get negative datestamps (1901-1969) wrong sometimes but
+//     don't really care that much.
 //
 // FEATURES:
 //     Flash Player does not seem to respect TZ or the zoneinfo database;
 //     It changes to/from daylight saving time according to its own rules.
 //     We use the operating system's localtime routines.
 //
+//     Flash player does bizarre things for some argument combinations,
+//     returning datestamps of /6.*e+19  We don't bother doing this...
+//
 // It may be useful to convert this to use libboost's date_time stuff
 // http://www.boost.org/doc/html/date_time.html
 // Pros:
@@ -71,15 +64,15 @@
 //        static function main(mc) {
 //             var now = new Date();
 //             var s:String;
-//               _root.createTextField("tf",0,0,0,320,200);
 //             s = now.toString();     // or whatever
-//             trace(s);                       // output in gnash -v
+//              _root.createTextField("tf",0,0,0,320,200);
 //              _root.tf.text = now.toString(); // output in flash player
+//             trace(s);                       // output in gnash -v
 //        }
 // }
 // in test.as, compile with
 //     mtasc -swf test.swf -main -header 320:200:10 test.as
-// and open test.swf in the commercial Flash Player.
+// and get someone to open test.swf for you in the commercial Flash Player.
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -108,19 +101,21 @@
 // Declaration for replacement timezone functions
 // In the absence of gettimeofday() we use ftime() to get milliseconds,
 // but not for timezone offset bcos ftime's TZ stuff is unreliable.
-// For that we use tzset()/timezone if it is available
-// However, ftime() is the only reliable way to get the timezone offset.
+// For that we use tzset()/timezone if it is available.
+
+// The structure of these ifdefs mimics the structure of the code below
+// where these things are used if available.
 
-#if HAVE_FTIME
+#if !defined(HAVE_GETTIMEOFDAY) || (!defined(HAVE_TM_GMTOFF) && 
!defined(HAVE_TZSET))
+# if HAVE_FTIME
 # include <sys/timeb.h>                // for ftime()
+# endif
 #endif
 
-// Is broken on BSD where timezone(int,int) is a function (!)
-// See comment at line 497 for a better implementation
-#undef HAVE_TZSET      
-
-#if HAVE_TZSET
-extern long timezone;          // for tzset()/timezone
+#if !defined(HAVE_TM_GMTOFF)
+# if HAVE_LONG_TIMEZONE
+extern long timezone;          // for tzset()/long timezone;
+# endif
 #endif
 
 namespace gnash {
@@ -141,6 +136,11 @@
 // forward declarations
 static void utctime(double tim, struct tm *tmp, double *msecp);
 static double mkutctime(struct tm *tmp, double msec);
+static void local_date_to_tm_msec(double value, struct tm &tm, double &msec);
+static void utc_date_to_tm_msec(double value, struct tm &tm, double &msec);
+static double local_tm_msec_to_date(struct tm &tm, double &msec);
+static double utc_tm_msec_to_date(struct tm &tm, double &msec);
+static double rogue_date_args(const fn_call& fn, int maxargs);
 #endif
 
 // Select functions to implement _localtime_r and _gmtime_r
@@ -345,6 +345,7 @@
 //
 /// The constructor has three forms: 0 args, 1 arg and 2-7 args.
 /// new Date() sets the Date to the current time of day
+/// new Date(undefined[,*]) does the same.
 /// new Date(timeValue:Number) sets the date to a number of milliseconds since
 ///    1 Jan 1970 UTC
 /// new Date(year, month[,date[,hour[,minute[,second[,millisecond]]]]])
@@ -364,8 +365,20 @@
 
        date_as_object *date = new date_as_object;
 
+       // Reject all date specifications containing Infinities and NaNs.
+       // The commercial player does different things according to which
+       // args are NaNs or Infinities:
+       // for now, we just use rogue_date_args' algorithm
+       {
+               double foo;
+               if ((foo = rogue_date_args(fn, 7)) != 0.0) {
+                       date->value = foo;
+                       return as_value(date);
+               }
+       }
+
        // TODO: move this to date_as_object constructor
-       if (fn.nargs < 1) {
+       if (fn.nargs < 1 || fn.arg(0).is_undefined()) {
                // Set from system clock
 #ifdef HAVE_GETTIMEOFDAY
                struct timeval tv;
@@ -373,11 +386,14 @@
 
                gettimeofday(&tv,&tz);
                date->value = (double)tv.tv_sec * 1000.0 + tv.tv_usec / 1000.0;
-#else
+#elif HAVE_FTIME
                struct timeb tb;
                
                ftime (&tb);
                date->value = (double)tb.time * 1000.0 + tb.millitm;
+#else
+               // Poo! Use old time() to get seconds only
+               date->value = time((time_t *) 0) * 1000.0;
 #endif
        } else if (fn.nargs == 1) {
                // Set the value in milliseconds since 1970 UTC
@@ -523,19 +539,31 @@
 // date_getutcmilliseconds is implemented by date_getmilliseconds.
 
 
-// Return number of minutes east of GMT, also used in toString()
+// Return the difference between UTC and localtime+DST for a given date/time
+// as the number of minutes east of GMT.
 
-// Yet another implementation option is suggested by localtime(3):
-// "The glibc version of struct tm has additional fields
-// long tm_gmtoff;           /* Seconds east of UTC */
-// defined when _BSD_SOURCE was set before including <time.h>"
-
-static int minutes_east_of_gmt()
+static int minutes_east_of_gmt(struct tm &tm)
 {
-#if HAVE_TZSET
+#if HAVE_TM_GMTOFF
+       // tm_gmtoff is in seconds east of GMT; convert to minutes.
+       return((int) (tm.tm_gmtoff / 60));
+#else
+       // Find the geographical system timezone offset and add an hour if
+       // DST applies to the date.
+       // To get it really right I guess we should call both gmtime()
+       // and localtime() and look at the difference.
+       //
+       // The range of standard time is GMT-11 to GMT+14.
+       // The most extreme with DST is Chatham Island GMT+12:45 +1DST
+
+       int minutes_east;
+
+       // Find out system timezone offset...
+
+# if defined(HAVE_TZSET) && defined(HAVE_LONG_TIMEZONE)
        tzset();
-       return(-timezone/60); // timezone is seconds west of GMT
-#elif HAVE_FTIME
+       minutes_east = -timezone/60; // timezone is seconds west of GMT
+# elif HAVE_FTIME
        // ftime(3): "These days the contents of the timezone and dstflag
        // fields are undefined."
        // In practice, timezone is -120 in Italy when it should be -60.
@@ -543,8 +571,8 @@
                
        ftime (&tb);
        // tb.timezone is number of minutes west of GMT
-       return(-tb.timezone);
-#elif HAVE_GETTIMEOFDAY
+       minutes_east = -tb.timezone;
+# elif HAVE_GETTIMEOFDAY
        // gettimeofday(3):
        // "The use of the timezone structure is obsolete; the tz argument
        // should normally be specified as NULL. The tz_dsttime field has
@@ -554,17 +582,54 @@
        struct timeval tv;
        struct timezone tz;
        gettimeofday(&tv,&tz);
-       return(-tz.tz_minuteswest);
-#else
-       return(0);      // No idea.
-#endif
+       minutes_east = -tz.tz_minuteswest;
+# else
+       minutes_east = 0;       // No idea.
+# endif
+
+       // ...and adjust by one hour if DST was in force at that time.
+       //
+       // According to http://www.timeanddate.com/time/, the only place that
+       // uses DST != +1 hour is Lord Howe Island with half an hour. Tough.
+
+       if (tm.tm_isdst == 0) {
+               // DST exists and is not in effect
+       } else if (tm.tm_isdst > 0) {
+               // DST exists and was in effect
+               minutes_east += 60;
+       } else {
+               // tm_isdst is negative: cannot get TZ info.
+               // Convert and print in UTC instead.
+               log_error("Cannot get timezone information");
+               minutes_east = 0;
+       }
+
+       return minutes_east;
+#endif // HAVE_TM_OFFSET
 }
 
+
 /// \brief Date.getTimezoneOffset
-/// returns the difference between localtime and UTC.
+/// returns the difference between localtime and UTC that was in effect at the
+/// time specified by a Date object, according to local timezone and DST.
+/// For example, if you are in GMT+0100, the offset is -60
+
+static as_value date_gettimezoneoffset(const fn_call& fn) {
+       boost::intrusive_ptr<date_as_object> date = 
ensureType<date_as_object>(fn.this_ptr);
+       struct tm tm;
+       double msec;
+
+       if (fn.nargs > 0) {
+           IF_VERBOSE_ASCODING_ERRORS(
+               log_aserror("Date.getTimezoneOffset was called with 
parameters");
+           )
+       }
 
-static as_value date_gettimezoneoffset(const fn_call& /* fn */) {
-       return as_value(minutes_east_of_gmt());
+       // Turn Flash datestamp into tm structure...
+       local_date_to_tm_msec(date->value, tm, msec);
+
+       // ...and figure out the timezone/DST offset from that.
+       return as_value(-minutes_east_of_gmt(tm));
 }
 
 
@@ -574,11 +639,10 @@
 
 /// \brief Date.setTime
 /// sets a Date in milliseconds after January 1, 1970 00:00 UTC.
-/// Returns value is the same aqs the paramemeter.
+/// The return value is the same as the parameter.
 static as_value date_settime(const fn_call& fn) {
        boost::intrusive_ptr<date_as_object> date = 
ensureType<date_as_object>(fn.this_ptr);
 
-       // assert(fn.nargs == 1);
        if (fn.nargs < 1) {
            IF_VERBOSE_ASCODING_ERRORS(
                log_aserror(_("Date.setTime needs one argument"));
@@ -617,13 +681,13 @@
 // Two low-level functions to convert between datestamps and time structures
 // whose contents are in local time
 
-// convert flash datestamp (number of milliseconds since the epoch as a double)
+// convert flash datestamp (number of milliseconds since the epoch)
 // to time structure and remaining milliseconds expressed in localtime.
 static void
-local_date_to_tm_msec(date_as_object& date, struct tm &tm, double &msec)
+local_date_to_tm_msec(double value, struct tm &tm, double &msec)
 {
-       time_t t = (time_t)(date.value / 1000.0);
-       msec = std::fmod(date.value, 1000.0);
+       time_t t = (time_t)(value / 1000.0);
+       msec = std::fmod(value, 1000.0);
        _localtime_r(&t, &tm);  // break out date/time elements
 }
 
@@ -645,24 +709,24 @@
        }
 }
 
-// Two low-level functions to convert between datestamps and time structures
-// whose contents are in UTC
+// Two low-level functions to convert between Flash datestamps
+// and time structures whose contents are in UTC
 //
 // gmtime() will split it for us, but mktime() only works in localtime.
 
 static void
-utc_date_to_tm_msec(date_as_object& date, struct tm &tm, double &msec)
+utc_date_to_tm_msec(double value, struct tm &tm, double &msec)
 {
 #if USE_UTCCONV
-       utctime(date.value, &tm, &msec);
+       utctime(value, &tm, &msec);
 #else
-       time_t t = (time_t)(date.value / 1000.0);
-       msec = std::fmod(date.value, 1000.0);
+       time_t t = (time_t)(value / 1000.0);
+       msec = std::fmod(value, 1000.0);
        _gmtime_r(&t, &tm);
 #endif
 }
 
-// Until we find the correct algorithm, we can use mktime which, by
+// Until we find a better algorithm, we can use mktime which, by
 // experiment, seems to flip timezone at midnight, not at 2 in the morning,
 // so we use that to do year/month/day and put the unadjusted hours/mins/secs
 // in by hand. It's probably not right but it'll do for the moment.
@@ -701,9 +765,9 @@
 date_to_tm_msec(date_as_object& date, struct tm &tm, double &msec, bool utc)
 {
     if (utc)
-       utc_date_to_tm_msec(date, tm, msec);
+       utc_date_to_tm_msec(date.value, tm, msec);
     else
-       local_date_to_tm_msec(date, tm, msec);
+       local_date_to_tm_msec(date.value, tm, msec);
 }
 
 //
@@ -747,11 +811,13 @@
 static as_value _date_setfullyear(const fn_call& fn, bool utc) {
        boost::intrusive_ptr<date_as_object> date = 
ensureType<date_as_object>(fn.this_ptr);
 
-       // assert(fn.nargs >= 1 && fn.nargs <= 3);
        if (fn.nargs < 1) {
            IF_VERBOSE_ASCODING_ERRORS(
                log_aserror(_("Date.setFullYear needs one argument"));
            )
+           date->value = NAN;
+       } else if (rogue_date_args(fn, 3) != 0.0) {
+           date->value = NAN;
        } else {
            struct tm tm; double msec;
 
@@ -794,12 +860,18 @@
            IF_VERBOSE_ASCODING_ERRORS(
                log_aserror(_("Date.setYear needs one argument"));
            )
+           date->value = NAN;
+       } else if (rogue_date_args(fn, 3) != 0.0) {
+           date->value = NAN;
        } else {
            struct tm tm; double msec;
 
            date_to_tm_msec(*date, tm, msec, false);
            tm.tm_year = (int) fn.arg(0).to_number();
-           if (tm.tm_year < 100) tm.tm_year += 1900;
+           // tm_year is number of eyars since 1900, so if they gave a
+           // full year spec, we must adjust it.
+           if (tm.tm_year >= 100) tm.tm_year -= 1900;
+
            if (fn.nargs >= 2)
                    tm.tm_mon = (int) fn.arg(1).to_number();
            if (fn.nargs >= 3)
@@ -809,7 +881,7 @@
                    log_aserror(_("Date.setYear was called with more than three 
arguments"));
                )
            }
-           tm_msec_to_date(tm, msec, *date, false);
+           tm_msec_to_date(tm, msec, *date, false); // utc=false: use localtime
        }
        return as_value(date->value);
 }
@@ -822,6 +894,12 @@
 /// the day should be set to the last day of the specified month.
 /// This implementation currently wraps it into the next month, which is wrong.
 
+// If no arguments are given or if an invalid type is given,
+// the commercial player sets the month to January in the same year.
+// Only if the second parameter is present and has a non-numeric value,
+// the result is NAN.
+// We do not do the same cos it's a bugger to code.
+
 static as_value _date_setmonth(const fn_call& fn, bool utc) {
        boost::intrusive_ptr<date_as_object> date = 
ensureType<date_as_object>(fn.this_ptr);
 
@@ -830,13 +908,31 @@
            IF_VERBOSE_ASCODING_ERRORS(
                log_aserror(_("Date.setMonth needs one argument"));
            )
+           date->value = NAN;
+       } else if (rogue_date_args(fn, 2) != 0.0) {
+           date->value = NAN;
        } else {
            struct tm tm; double msec;
+           double monthvalue; // result from to_number()
 
            date_to_tm_msec(*date, tm, msec, utc);
-           tm.tm_mon = (int) fn.arg(0).to_number();
-           if (fn.nargs >= 2)
-                   tm.tm_mday = (int) fn.arg(2).to_number();
+
+           // It seems odd, but FlashPlayer takes all bad month values to mean
+           // January.
+           monthvalue =  fn.arg(0).to_number();
+           if (isnan(monthvalue) || isinf(monthvalue)) monthvalue = 0.0;
+           tm.tm_mon = (int) monthvalue;
+
+           // If the day-of-month value is invalid instead, the result is NAN.
+           if (fn.nargs >= 2) {
+               double mdayvalue = fn.arg(1).to_number();
+               if (isnan(mdayvalue) || isinf(mdayvalue)) {
+                   date->value = NAN;
+                   return as_value(date->value);
+               } else {
+                   tm.tm_mday = (int) mdayvalue;
+               }
+           }
            if (fn.nargs > 2) {
                IF_VERBOSE_ASCODING_ERRORS(
                    log_aserror(_("Date.setMonth was called with more than 
three arguments"));
@@ -860,6 +956,9 @@
            IF_VERBOSE_ASCODING_ERRORS(
                log_aserror(_("Date.setDate needs one argument"));
            )
+           date->value = NAN;  // Is what FlashPlayer sets
+       } else if (rogue_date_args(fn, 1) != 0.0) {
+           date->value = NAN;
        } else {
                struct tm tm; double msec;
 
@@ -895,6 +994,9 @@
            IF_VERBOSE_ASCODING_ERRORS(
                log_aserror(_("Date.setHours needs one argument"));
            )
+           date->value = NAN;  // Is what FlashPlayer sets
+       } else if (rogue_date_args(fn, 4) != 0.0) {
+           date->value = NAN;
        } else {
            struct tm tm; double msec;
 
@@ -932,6 +1034,10 @@
            IF_VERBOSE_ASCODING_ERRORS(
                log_aserror(_("Date.setMinutes needs one argument"));
            )
+           date->value = NAN;  // FlashPlayer instead leaves the date set to
+                               // a random value such as 9th December 2077 BC
+       } else if (rogue_date_args(fn, 3) != 0.0) {
+           date->value = NAN;
        } else {
            struct tm tm; double msec;
 
@@ -965,6 +1071,9 @@
            IF_VERBOSE_ASCODING_ERRORS(
                log_aserror(_("Date.setSeconds needs one argument"));
            )
+           date->value = NAN;  // Same as commercial player
+       } else if (rogue_date_args(fn, 2) != 0.0) {
+           date->value = NAN;
        } else {
            // We *could* set seconds [and milliseconds] without breaking the
            // structure out and reasembling it. We do it the same way as the
@@ -981,6 +1090,8 @@
                    log_aserror(_("Date.setMinutes was called with more than 
three arguments"));
                )
            }
+           // This is both setSeconds and setUTCSeconds.
+           // Use utc to avoid needless worrying about timezones.
            tm_msec_to_date(tm, msec, *date, utc);
        }
        return as_value(date->value);
@@ -994,9 +1105,12 @@
            IF_VERBOSE_ASCODING_ERRORS(
                log_aserror(_("Date.setMilliseconds needs one argument"));
            )
+           date->value = NAN;
+       } else if (rogue_date_args(fn, 1) != 0.0) {
+           date->value = NAN;
        } else {
            // Zero the milliseconds and set them from the argument.
-           date->value = std::fmod(date->value, 1000.0) + (int) 
fn.arg(0).to_number();
+           date->value = date->value - std::fmod(date->value, 1000.0) + (int) 
fn.arg(0).to_number();
            if (fn.nargs > 1) {
                IF_VERBOSE_ASCODING_ERRORS(
                    log_aserror(_("Date.setMilliseconds was called with more 
than one argument"));
@@ -1048,38 +1162,27 @@
 
        boost::intrusive_ptr<date_as_object> date = 
ensureType<date_as_object>(fn.this_ptr);
        
-       time_t t = (time_t) (date->value / 1000.0);
+       /// NAN and infinities all print as "Invalid Date"
+       if (isnan(date->value) || isinf(date->value)) {
+               strcpy(buffer, "Invalid Date");
+               return as_value((char *)&buffer);
+       }
+
+       // The date value split out to year, month, day, hour etc and millisecs
        struct tm tm;
+       double msec;
+       // Time zone offset (including DST) as hours and minutes east of GMT
        int tzhours, tzminutes;
 
-       _localtime_r(&t, &tm);
+       local_date_to_tm_msec(date->value, tm, msec);
 
        // At the meridian we need to print "GMT+0100" when Daylight Saving
        // Time is in force, "GMT+0000" when it isn't, and other values for
        // other places around the globe when DST is/isn't in force there.
-       //
-       // For now, just take time East of GMT and add an hour if DST is
-       // active. To get it right I guess we should call both gmtime()
-       // and localtime() and look at the difference.
-       //
-       // According to http://www.timeanddate.com/time/, the only place that
-       // uses DST != +1 hour is Lord Howe Island with half an hour. Tough.
-
-       tzhours = (tzminutes = minutes_east_of_gmt()) / 60, tzminutes %= 60;
 
-       if (tm.tm_isdst == 0) {
-               // DST exists and is not in effect
-       } else if (tm.tm_isdst > 0) {
-               // DST exists and is in effect
-               tzhours++;
-               // The range of standard time is GMT-11 to GMT+14.
-               // The most extreme with DST is Chatham Island GMT+12:45 +1DST
-       } else {
-               // tm_isdst is negative: cannot get TZ info.
-               // Convert and print in UTC instead.
-               _gmtime_r(&t, &tm);
-               tzhours = tzminutes = 0;
-       }
+       // Split offset into hours and minutes
+       tzminutes = minutes_east_of_gmt(tm);
+       tzhours = tzminutes / 60, tzminutes %= 60;
 
        // If timezone is negative, both hours and minutes will be negative
        // but for the purpose of printing a string, only the hour needs to
@@ -1113,11 +1216,19 @@
 // This probably doesn't handle exceptional cases such as NaNs and infinities
 // the same as the commercial player. What that does is:
 // - if any argument is NaN, the result is NaN
-// - if one or more arguments are +Infinity, the result is +Infinity
-// - if one or more arguments are -Infinity, the result is -Infinity
-// - if both +Infinity and -Infinity are present in the args, result is NaN.
+// - if one or more of the optional arguments are +Infinity,
+//     the result is +Infinity
+// - if one or more of the optional arguments are -Infinity,
+//     the result is -Infinity
+// - if both +Infinity and -Infinity are present in the optional args,
+//     or if one of the first two arguments is not numeric (including Inf),
+//     the result is NaN.
+// Actually, given a first parameter of Infinity,-Infinity or NAN,
+// it returns -6.77681005679712e+19 but that's just crazy.
+//
+// We test for < 2 parameters and return undefined, but given any other
+// non-numeric arguments we give NAN.
 
-static double rogue_date_args(const fn_call& fn);      // Forward decl
 
 static as_value date_utc(const fn_call& fn) {
        struct tm tm;   // Date structure for values down to seconds
@@ -1128,13 +1239,13 @@
            IF_VERBOSE_ASCODING_ERRORS(
                log_aserror(_("Date.UTC needs one argument"));
            )
-           return as_value();
+           return as_value();  // undefined
        }
 
        // Check for presence of NaNs and Infinities in the arguments 
        // and return the appropriate value if so.
-       if ( (result = rogue_date_args(fn)) != 0.0) {
-               return as_value(result);
+       if ( (result = rogue_date_args(fn, 7)) != 0.0) {
+               return as_value(NAN);
        }
 
        // Preset default values
@@ -1175,8 +1286,10 @@
 
 // Auxillary function checks for Infinities and NaN in a function's args and
 // returns 0.0 if there are none, 
+// plus (or minus) infinity if positive (or negative) infinites are present,
+// NAN is there are NANs present, or a mixture of positive and negative infs.
 static double
-rogue_date_args(const fn_call& fn) {
+rogue_date_args(const fn_call& fn, int maxargs) {
        // Two flags: Did we find any +Infinity (or -Infinity) values in the
        // argument list? If so, "infinity" must be set to the kind that we
        // found.
@@ -1185,7 +1298,10 @@
        double infinity = 0.0;  // The kind of infinity we found.
                                // 0.0 == none yet.
 
-       for (unsigned int i = 0; i < fn.nargs; i++) {
+       // Only check the present parameters, up to the stated maximum number
+       if (fn.nargs < maxargs) maxargs = fn.nargs;
+
+       for (unsigned int i = 0; i < maxargs; i++) {
                double arg = fn.arg(i).to_number();
 
                if (isnan(arg)) return(NAN);

Index: server/asobj/Global.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/Global.cpp,v
retrieving revision 1.59
retrieving revision 1.60
diff -u -b -r1.59 -r1.60
--- server/asobj/Global.cpp     18 Apr 2007 11:00:29 -0000      1.59
+++ server/asobj/Global.cpp     18 Apr 2007 13:47:24 -0000      1.60
@@ -17,7 +17,7 @@
 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 //
 
-/* $Id: Global.cpp,v 1.59 2007/04/18 11:00:29 jgilmore Exp $ */
+/* $Id: Global.cpp,v 1.60 2007/04/18 13:47:24 martinwguy Exp $ */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -435,13 +435,11 @@
        init_member("isNaN", new builtin_function(as_global_isnan));
        init_member("isFinite", new builtin_function(as_global_isfinite));
 
-       // NaN should only be in _global since SWF6, but this is just because
-       // SWF5 or lower did not have a "_global" reference at all, most likely
-       init_member("NaN", as_value(std::numeric_limits<double>::quiet_NaN()));
-
-       // Infinity should only be in _global since SWF6, but this is just 
because
-       // SWF5 or lower did not have a "_global" reference at all, most likely
-       init_member("Infinity", 
as_value(std::numeric_limits<double>::infinity()));
+       // NaN and Infinity should only be in _global since SWF6,
+       // but this is just because SWF5 or lower did not have a "_global"
+       // reference at all, most likely.
+       init_member("NaN", as_value(NAN));
+       init_member("Infinity", as_value(INFINITY));
 
        if ( vm.getSWFVersion() < 6 ) goto extscan;
        //-----------------------

Index: server/as_value.h
===================================================================
RCS file: /sources/gnash/gnash/server/as_value.h,v
retrieving revision 1.44
retrieving revision 1.45
diff -u -b -r1.44 -r1.45
--- server/as_value.h   16 Apr 2007 18:23:05 -0000      1.44
+++ server/as_value.h   18 Apr 2007 13:47:24 -0000      1.45
@@ -14,7 +14,7 @@
 // along with this program; if not, write to the Free Software
 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
-/* $Id: as_value.h,v 1.44 2007/04/16 18:23:05 strk Exp $ */
+/* $Id: as_value.h,v 1.45 2007/04/18 13:47:24 martinwguy Exp $ */
 
 #ifndef GNASH_AS_VALUE_H
 #define GNASH_AS_VALUE_H
@@ -49,6 +49,10 @@
 #       define NAN (std::numeric_limits<double>::quiet_NaN())
 #endif
 
+#ifndef INFINITY
+#       define INFINITY (std::numeric_limits<double>::infinity());
+#endif
+
 
 #ifndef isnan
 # define isnan(x) \

Index: server/as_value.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/as_value.cpp,v
retrieving revision 1.38
retrieving revision 1.39
diff -u -b -r1.38 -r1.39
--- server/as_value.cpp 18 Apr 2007 09:35:42 -0000      1.38
+++ server/as_value.cpp 18 Apr 2007 13:47:24 -0000      1.39
@@ -259,25 +259,31 @@
                        // @@ Moock says the rule here is: if the
                        // string is a valid float literal, then it
                        // gets converted; otherwise it is set to NaN.
-                       //
-                       // Also, "Infinity", "-Infinity", and "NaN"
-                       // are recognized by strtod() but not by Flash Player.
                        char* tail=0;
                        m_number_value = strtod(m_string_value.c_str(), &tail);
+                       // Detect failure by "tail" still being at the start of
+                       // the string or there being extra junk after the
+                       // converted characters.
                        if ( tail == m_string_value.c_str() || *tail != 0 )
                        {
                                // Failed conversion to Number.
                                m_number_value = NAN;
                        }
+
+                       // "Infinity" and "-Infinity" are recognized by strtod()
+                       // but Flash Player returns NaN for them.
+                       if ( isinf(m_number_value) ) {
+                               m_number_value = NAN;
+                       }
+
                        return m_number_value;
                }
 
                case NULLTYPE:
                case UNDEFINED:
                        // Evan: from my tests
-                       // Martin: I tried var foo = new Number(null) and got 
NaN
-                       if ( swfversion >= 7 ) return 
std::numeric_limits<double>::quiet_NaN();
-                       else return 0;
+                       // Martin: FlashPlayer6 gives 0; FP9 gives NaN.
+                       return ( swfversion >= 7 ? NAN : 0 );
 
                case BOOLEAN:
                        // Evan: from my tests
@@ -288,7 +294,6 @@
                        return m_number_value;
 
                case OBJECT:
-               case AS_FUNCTION:
                {
                        // @@ Moock says the result here should be
                        // "the return value of the object's valueOf()
@@ -299,7 +304,6 @@
                        //log_msg(_("OBJECT to number conversion, env is %p"), 
env);
 
                        as_object* obj = m_object_value; 
-                       bool gotValidValueOfResult = false;
                        if ( env )
                        {
                                std::string methodname = "valueOf";
@@ -310,7 +314,6 @@
                                        as_value ret = call_method0(method, 
env, obj);
                                        if ( ret.is_number() )
                                        {
-                                               gotValidValueOfResult=true;
                                                return ret.m_number_value;
                                        }
                                        else
@@ -323,11 +326,14 @@
                                        log_msg(_("get_member(%s) returned 
false"), methodname.c_str());
                                }
                        }
-                       if ( ! gotValidValueOfResult )
-                       {
                                return obj->get_numeric_value(); 
                        }
-               }
+
+               case AS_FUNCTION:
+                       // This used to be the same case as AS_OBJECT,
+                       // but empirically "new String(_root.createTextField)"
+                       // or any other function returns NAN.
+                       return NAN;
 
                case MOVIECLIP:
                        // This is tested, no valueOf is going
@@ -339,6 +345,7 @@
                        // every GUI's movie canvas shrinks to size 0x0. No 
idea why.
                        return NAN; // 0.0;
        }
+       /* NOTREACHED */
 }
 
 // Conversion to boolean for SWF7 and up

Index: testsuite/actionscript.all/Date.as
===================================================================
RCS file: /sources/gnash/gnash/testsuite/actionscript.all/Date.as,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -b -r1.20 -r1.21
--- testsuite/actionscript.all/Date.as  27 Mar 2007 09:05:23 -0000      1.20
+++ testsuite/actionscript.all/Date.as  18 Apr 2007 13:47:24 -0000      1.21
@@ -1,4 +1,4 @@
-// 
+/N/ 
 //   Copyright (C) 2005, 2006 Free Software Foundation, Inc.
 //
 // This program is free software; you can redistribute it and/or modify
@@ -20,7 +20,7 @@
 // compile this test case with Ming makeswf, and then
 // execute it like this gnash -1 -r 0 -v out.swf
 
-rcsid="$Id: Date.as,v 1.20 2007/03/27 09:05:23 strk Exp $";
+rcsid="$Id: Date.as,v 1.21 2007/04/18 13:47:24 martinwguy Exp $";
 
 #include "check.as"
 
@@ -32,12 +32,12 @@
 // returning 2147483647 instead of the correct value.
 check_equals (Date.UTC(2000,0,1).valueOf(), 946684800000.0);
 
-// test the Date constructor.
+// test the Date constructor exists.
 // This specific value is used below to check conversion back to year/mon/day 
etc
 var d = new Date(70,1,2,3,4,5,6);
-check (d);
+check (d != undefined);
 
-// test methods existance
+// test methods' existence
 check (d.getDate != undefined);
 check (d.getDay != undefined);
 check (d.getFullYear != undefined);
@@ -121,105 +121,323 @@
 
 #endif
 
-// var d = new Date(70,1,2,3,4,5,6);   // See above
-trace ("Testing random d");
-check_equals (d.getFullYear(), 1970);
-check_equals (d.getYear(), 70);
-check_equals (d.getMonth(), 1);
-check_equals (d.getDate(), 2);
-check_equals (d.getHours(), 3);
-check_equals (d.getMinutes(), 4);
-check_equals (d.getSeconds(), 5);
-check_equals (d.getMilliseconds(), 6);
-
-// Test decoding methods
-// Check the epoch, 1 Jan 1970
-trace ("Testing 1 Jan 1970 UTC");
-check_equals (d.setTime(0), 0);
-check_equals (d.getTime(), 0);
-check_equals (d.getUTCFullYear(), 1970);
-check_equals (d.getUTCMonth(), 0);
-check_equals (d.getUTCDate(), 1);
-check_equals (d.getUTCDay(), 4);       // It was a Thursday
-check_equals (d.getUTCHours(), 0);
-check_equals (d.getUTCMinutes(), 0);
-check_equals (d.getUTCSeconds(), 0);
-check_equals (d.getUTCMilliseconds(), 0);
-check_equals (d.valueOf(), 0);
+// Some values we will use to test things
+    var zero = 0.0;
+    var plusinfinity = 1.0/zero;
+    var minusinfinity = -1.0/zero;
+    var notanumber = zero/zero;
+
+// Check Date constructor in its many forms,
+// (also uses valueOf() and toString() methods)
+
+// Constructor with no args sets current localtime
+    var d = new Date();
+       check (d != undefined);
+       // Check it's a valid number after 1 April 2007
+       check (d.valueOf() > 1175385600000.0)
+       // and before Jan 1 2037 00:00:00
+       check (d.valueOf() < 2114380800000.0)
+
+// Constructor with first arg == undefined also sets current localtime
+    var d2 = new Date(undefined);
+       check (d2 != undefined);
+       check (d2.valueOf() >= d.valueOf());
+// that shouldn't have taken more than five seconds!
+       check (d2.valueOf() < d.valueOf() + 5000);
+    delete d2;
+
+// One numeric argument sets milliseconds since 1970 UTC
+    delete d; var d = new Date(0);
+       // Check UTC "get" methods too
+       check_equals(d.valueOf(), 0);
+       check_equals(d.getTime(), 0);
+       check_equals(d.getUTCFullYear(), 1970);
+       check_equals(d.getUTCMonth(), 0);
+       check_equals(d.getUTCDate(), 1);
+       check_equals(d.getUTCDay(), 4); // It was a Thursday
+       check_equals(d.getUTCHours(), 0);
+       check_equals(d.getUTCMinutes(), 0);
+       check_equals(d.getUTCSeconds(), 0);
+       check_equals(d.getUTCMilliseconds(), 0);
+// Check other convertible types
+// Booleans convert to 0 and 1
+    var foo = true; delete d; var d = new Date(foo);
+       check_equals(d.valueOf(), 1);
+    foo = false; delete d; var d = new Date(foo);
+       check_equals(d.valueOf(), 0);
+// Numeric strings
+    foo = "12345"; delete d; var d = new Date(foo);
+       check_equals(d.valueOf(), 12345.0);
+    foo = "12345.0"; delete d; var d = new Date(foo);
+       check_equals(d.valueOf(), 12345.0);
+    foo = "12345.5"; delete d; var d = new Date(foo);
+       check_equals(d.valueOf(), 12345.5);     // Sets fractions of msec ok?
+    foo = "-12345"; delete d; var d = new Date(foo);
+       check_equals(d.valueOf(), -12345.0);
+// Bad numeric values
+       // NAN
+    delete d; var d = new Date(notanumber);
+       check_equals(d.valueOf().toString(), "NaN");
+       check_equals(d.toString(), "Invalid Date");
+       // Infinity
+    delete d; var d = new Date(plusinfinity);
+       check_equals(d.valueOf().toString(), "Infinity");
+       check_equals(d.toString(), "Invalid Date");
+       // -Infinity
+    delete d; var d = new Date(minusinfinity);
+       check_equals(d.valueOf().toString(), "-Infinity");
+       check_equals(d.toString(), "Invalid Date");
+// Bogus values: non-numeric strings
+       foo = "bones"; delete d; var d = new Date(foo);
+       check_equals(d.valueOf().toString(), "NaN");
+       foo = "1234X"; delete d; var d = new Date(foo);
+       check_equals(d.valueOf().toString(), "NaN");
+// Bogus types: a function
+       foo = d.valueOf; var d2 = new Date(foo);
+       check_equals(d2.valueOf().toString(), "NaN");
+       delete d2;
+
+// Constructor with two numeric args means year and month in localtime.
+// Now we check the localtime decoding methods too.
+// Negative year means <1900; 0-99 means 1900-1999; 100- means 100-)
+// Month is 0-11. month>11 increments year; month<0 decrements year.
+    delete d; var d = new Date(70,0);  // 1 Jan 1970 00:00:00 localtime
+       check_equals(d.getYear(), 70);
+       check_equals(d.getFullYear(), 1970);
+       check_equals(d.getMonth(), 0);
+       check_equals(d.getDate(), 1);
+       check_equals(d.getDay(), 4);    // It was a Thursday
+       check_equals(d.getHours(), 0);
+       check_equals(d.getMinutes(), 0);
+       check_equals(d.getSeconds(), 0);
+       check_equals(d.getMilliseconds(), 0);
+// Check four-figure version - should be the same.
+    var d2 = new Date(1970,0); check_equals(d.valueOf(), d2.valueOf());
+// Check four-figure version and non-zero month
+    delete d; var d = new Date(2000,3);        // 1 April 2000 00:00:00 
localtime
+       check_equals(d.getYear(), 100);
+       check_equals(d.getFullYear(), 2000);
+       check_equals(d.getMonth(), 3);
+       check_equals(d.getDate(), 1);
+       check_equals(d.getDay(), 6);    // It was a Saturday
+       check_equals(d.getHours(), 0);
+       check_equals(d.getMinutes(), 0);
+       check_equals(d.getSeconds(), 0);
+       check_equals(d.getMilliseconds(), 0);
+// Check month overflow/underflow
+    delete d; var d = new Date(2000,12);
+       check_equals(d.getFullYear(), 2001);
+       check_equals(d.getMonth(), 0);
+    delete d; var d = new Date(2000,-18);
+       check_equals(d.getFullYear(), 1998);
+       check_equals(d.getMonth(), 6);
+// Bad numeric value handling: year is an invalid number with >1 arg
+// The commercial player for these first three cases gives
+// -6.77681005679712e+19  Tue Jan -719527 00:00:00 GMT+0000
+// but that doesn't seem worth emulating...
+    delete d; var d = new Date(notanumber,0);
+       check_equals(d.valueOf().toString(), "NaN");
+    delete d; var d = new Date(plusinfinity,0);
+       check_equals(d.valueOf().toString(), "Infinity");
+    delete d; var d = new Date(minusinfinity,0);
+       check_equals(d.valueOf().toString(), "-Infinity");
+// Bad numeric value handling: month is an invalid number
+    delete d; var d = new Date(0,notanumber);
+       check_equals(d.valueOf().toString(), "NaN");
+    delete d; var d = new Date(0,plusinfinity);
+       check_equals(d.valueOf().toString(), "Infinity");
+    delete d; var d = new Date(0,minusinfinity);
+       check_equals(d.valueOf().toString(), "-Infinity");
+
+// Constructor with three numeric args means year month day-of-month
+    delete d; var d = new Date(2000,0,1); // 1 Jan 2000 00:00:00 localtime
+       check_equals(d.getFullYear(), 2000);
+       check_equals(d.getMonth(), 0);
+       check_equals(d.getDate(), 1);
+// Check day-of-month overflow/underflow
+    delete d; var d = new Date(2000,0,32); // 32 Jan -> 1 Feb
+       check_equals(d.getFullYear(), 2000);
+       check_equals(d.getMonth(), 1);
+       check_equals(d.getDate(), 1);
+    delete d; var d = new Date(2000,1,0); // 0 Feb -> 31 Jan
+       check_equals(d.getFullYear(), 2000);
+       check_equals(d.getMonth(), 0);
+       check_equals(d.getDate(), 31);
+    delete d; var d = new Date(2000,0,-6); // -6 Jan 2000 -> 25 Dec 1999
+       check_equals(d.getFullYear(), 1999);
+       check_equals(d.getMonth(), 11);
+       check_equals(d.getDate(), 25);
+// Bad numeric value handling when day-of-month is an invalid number
+// A bad month always returns NaN but a bad d-o-m returns the infinities.
+    delete d; var d = new Date(2000,0,notanumber);
+       check_equals(d.valueOf().toString(), "NaN");
+    delete d; var d = new Date(2000,0,plusinfinity);
+       check_equals(d.valueOf().toString(), "Infinity");
+    delete d; var d = new Date(2000,0,minusinfinity);
+       check_equals(d.valueOf().toString(), "-Infinity");
+    // Check bad string value
+    foo = "bones"; delete d; var d = new Date(2000,0,foo);
+       check_equals(d.valueOf().toString(), "NaN");
+
+// Constructor with four numeric args means year month day-of-month hour
+    delete d; var d = new Date(2000,0,1,12);
+       check_equals(d.getHours(), 12);
+       check_equals(d.getMinutes(), 0);
+       check_equals(d.getSeconds(), 0);
+       check_equals(d.getMilliseconds(), 0);
+    // Check that fractional parts of hours are ignored
+    delete d; var d = new Date(2000,0,1,12.5);
+       check_equals(d.getHours(), 12);
+       check_equals(d.getMinutes(), 0);
+    // Check hours overflow/underflow
+    delete d; var d = new Date(2000,0,1,25);
+       check_equals(d.getDate(), 2);
+       check_equals(d.getHours(), 1);
+    // Bad hours, like bad d-o-m, return infinites.
+    delete d; var d = new Date(2000,0,1,notanumber);
+       check_equals(d.valueOf().toString(), "NaN");
+    delete d; var d = new Date(2000,0,1,plusinfinity);
+       check_equals(d.valueOf().toString(), "Infinity");
+    delete d; var d = new Date(2000,0,1,minusinfinity);
+       check_equals(d.valueOf().toString(), "-Infinity");
+    // Check bad string value
+    foo = "bones"; delete d; var d = new Date(2000,0,1,foo);
+       check_equals(d.valueOf().toString(), "NaN");
+
+// Constructor with five numeric args means year month day-of-month hour min
+    delete d; var d = new Date(2000,0,1,12,30);
+       check_equals(d.getHours(), 12);
+       check_equals(d.getMinutes(), 30);
+       check_equals(d.getSeconds(), 0);
+       check_equals(d.getMilliseconds(), 0);
+    // Check minute overflow/underflow
+    delete d; var d = new Date(2000,0,1,12,70);
+       check_equals(d.getHours(), 13);
+       check_equals(d.getMinutes(), 10);
+       check_equals(d.getSeconds(), 0);
+    delete d; var d = new Date(2000,0,1,12,-120);
+       check_equals(d.getHours(), 10);
+       check_equals(d.getMinutes(), 0);
+       check_equals(d.getSeconds(), 0);
+    // Infinite minutes return infinites.
+    delete d; var d = new Date(2000,0,1,0,notanumber);
+       check_equals(d.valueOf().toString(), "NaN");
+    delete d; var d = new Date(2000,0,1,0,plusinfinity);
+       check_equals(d.valueOf().toString(), "Infinity");
+    delete d; var d = new Date(2000,0,1,0,minusinfinity);
+       check_equals(d.valueOf().toString(), "-Infinity");
+    // Check bad string value
+    foo = "bones"; delete d; var d = new Date(2000,0,1,0,foo);
+       check_equals(d.valueOf().toString(), "NaN");
+
+// Constructor with six numeric args means year month d-of-m hour min sec
+// Check UTC seconds here too since it should be the same.
+    delete d; var d = new Date(2000,0,1,0,0,45);
+       check_equals(d.getHours(), 0);
+       check_equals(d.getMinutes(), 0);
+       check_equals(d.getSeconds(), 45);
+       check_equals(d.getUTCSeconds(), 45);
+       check_equals(d.getMilliseconds(), 0);
+    // Check second overflow/underflow
+    delete d; var d = new Date(2000,0,1,12,0,70);
+       check_equals(d.getHours(), 12);
+       check_equals(d.getMinutes(), 1);
+       check_equals(d.getSeconds(), 10);
+    delete d; var d = new Date(2000,0,1,12,0,-120);
+       check_equals(d.getHours(), 11);
+       check_equals(d.getMinutes(), 58);
+       check_equals(d.getSeconds(), 0);
+    // Infinite seconds return infinites.
+    delete d; var d = new Date(2000,0,1,0,0,notanumber);
+       check_equals(d.valueOf().toString(), "NaN");
+    delete d; var d = new Date(2000,0,1,0,0,plusinfinity);
+       check_equals(d.valueOf().toString(), "Infinity");
+    delete d; var d = new Date(2000,0,1,0,0,minusinfinity);
+       check_equals(d.valueOf().toString(), "-Infinity");
+    // Check bad string value
+    foo = "bones"; delete d; var d = new Date(2000,0,1,0,0,foo);
+       check_equals(d.valueOf().toString(), "NaN");
+
+// Constructor with seven numeric args means year month dom hour min sec msec
+// Check UTC milliseconds here too since it should be the same.
+    delete d; var d = new Date(2000,0,1,0,0,0,500);
+       check_equals(d.getHours(), 0);
+       check_equals(d.getMinutes(), 0);
+       check_equals(d.getSeconds(), 0);
+       check_equals(d.getMilliseconds(), 500);
+       check_equals(d.getUTCMilliseconds(), 500);
+    // Fractions of milliseconds are ignored here
+    delete d; var d = new Date(2000,0,1,0,0,0,500.5);
+       check_equals(d.getMilliseconds(), 500.0);
+    // Check millisecond overflow/underflow
+    delete d; var d = new Date(2000,0,1,12,0,0,1000);
+       check_equals(d.getMinutes(), 0);
+       check_equals(d.getSeconds(), 1);
+       check_equals(d.getMilliseconds(), 0);
+    delete d; var d = new Date(2000,0,1,12,0,0,-120000);
+       check_equals(d.getHours(), 11);
+       check_equals(d.getMinutes(), 58);
+       check_equals(d.getSeconds(), 0);
+    // Infinite milliseconds return infinites.
+    delete d; var d = new Date(2000,0,1,0,0,0,notanumber);
+       check_equals(d.valueOf().toString(), "NaN");
+    delete d; var d = new Date(2000,0,1,0,0,0,plusinfinity);
+       check_equals(d.valueOf().toString(), "Infinity");
+    delete d; var d = new Date(2000,0,1,0,0,0,minusinfinity);
+       check_equals(d.valueOf().toString(), "-Infinity");
+    // Check bad string value
+    foo = "bones"; delete d; var d = new Date(2000,0,1,0,0,0,foo);
+       check_equals(d.valueOf().toString(), "NaN");
+    // Finally, check that a millisecond is enough to overflow/underflow a year
+    delete d; var d = new Date(1999,11,31,23,59,59,1001);
+       check_equals(d.getFullYear(), 2000);
+       check_equals(d.getMonth(), 0);
+       check_equals(d.getDate(), 1);
+       check_equals(d.getMinutes(), 0);
+       check_equals(d.getSeconds(), 0);
+       check_equals(d.getMilliseconds(), 1);
+    delete d; var d = new Date(2000,0,1,0,0,0,-1);
+       check_equals(d.getFullYear(), 1999);
+       check_equals(d.getMonth(), 11);
+       check_equals(d.getDate(), 31);
+       check_equals(d.getMinutes(), 59);
+       check_equals(d.getSeconds(), 59);
+       check_equals(d.getMilliseconds(), 999);
+// If a mixture of infinities and/or NaNs are present the result is NaN.
+    delete d; var d = new Date(2000,0,1,plusinfinity,minusinfinity,0,0);
+       check_equals(d.valueOf().toString(), "NaN");
+
+// It's hard to test TimezoneOffset because the values will be different
+// depending upon where geographically you run the tests.
+// We do what we can without knowing where we are!
 
-trace ("Testing 1 Jan 2000 UTC");
-d.setUTCFullYear(2000, 0, 1);
-d.setUTCHours(0, 0, 0);
-check_equals (d.getUTCFullYear(), 2000);
-check_equals (d.getUTCMonth(), 0);
-check_equals (d.getUTCDate(), 1);
-check_equals (d.getUTCDay(), 6);       // It was a Saturday
+// Set midnight local time, adjust for tzoffset
+// and this should give us midnight UTC.
+//
+// If we are in GMT+1 then TimezoneOffset is -60.
+// If we set midnight localtime in the GMT+1 zone,
+// that is 23:00 the day before in UTC (because in GMT+1 clock times happen
+// an hour earlier than they do in "real" time).
+// Thus to set UTC to midnight we need to subtract the TimezoneOffset.
+delete d;
+var d = new Date(2000, 0, 1, 0, 0, 0, 0);
+d.setTime(d.getTime() - (60000 * d.getTimezoneOffset()));
 check_equals (d.getUTCHours(), 0);
-check_equals (d.getUTCMinutes(), 0);
-check_equals (d.getUTCSeconds(), 0);
-check_equals (d.getUTCMilliseconds(), 0);
-check_equals (d.valueOf(), 946684800000.0);    // Same as flashplayer gives
 
-trace ("Testing 1 Jul 2000 UTC");
-d.setUTCFullYear(2000, 6, 1);
-d.setUTCHours(0, 0, 0);
-check_equals (d.getUTCFullYear(), 2000);
-check_equals (d.getUTCMonth(), 6);
-check_equals (d.getUTCDate(), 1);
-check_equals (d.getUTCDay(), 6);       // It was a Saturday
+// Try the same thing in July to get one with DST and one without
+d = new Date(2000, 6, 1, 0, 0, 0, 0);
+d.setTime(d.getTime() - (60000 * d.getTimezoneOffset()));
 check_equals (d.getUTCHours(), 0);
-check_equals (d.getUTCMinutes(), 0);
-check_equals (d.getUTCSeconds(), 0);
-check_equals (d.getUTCMilliseconds(), 0);
-check_equals (d.valueOf(), 962409600000.0);    // Same as flashplayer gives
 
-trace ("Testing 1 Jan 2000 localtime");
-// The many-argument version of the Date constructor sets the d in localtime
-delete d;
-var d = new Date(2000, 0, 1, 0, 0, 0, 0);
-check_equals (d.getFullYear(), 2000);
-check_equals (d.getYear(), 100);
-check_equals (d.getMonth(), 0);
-check_equals (d.getDate(), 1);
-check_equals (d.getDay(), 6);  // It was a Saturday
-check_equals (d.getHours(), 0);
-check_equals (d.getMinutes(), 0);
-check_equals (d.getSeconds(), 0);
-check_equals (d.getMilliseconds(), 0);
-
-trace ("Testing 1 Jul 2000 localtime");
-// The many-argument version of the Date constructor sets the d in localtime
-delete d;
-var d = new Date(2000, 6, 1, 0, 0, 0, 0);
-check_equals (d.getFullYear(), 2000);
-check_equals (d.getYear(), 100);
-check_equals (d.getMonth(), 6);
-check_equals (d.getDate(), 1);
-check_equals (d.getDay(), 6);  // It was a Saturday
-check_equals (d.getHours(), 0);
-check_equals (d.getMinutes(), 0);
-check_equals (d.getSeconds(), 0);
-check_equals (d.getMilliseconds(), 0);
-
-// Test TimezoneOffset and local hours by setting a d to the 1 Jan 2000 UTC
-// offset by the tzoffset so that localtime should be 00:00 or 01:00
-// (according to whether DST is active or not)
-
-trace ("Testing timezone offset");
-var tzoffset = new Number(d.getTimezoneOffset());      // in mins east of GMT
-trace("timezone offset = " + tzoffset.toString());
-d.setUTCFullYear(2000, 0, 1);
-d.setUTCHours(0, 0, 0, 0);
-d.setTime(d.getTime() - (60000*tzoffset));
-note("d.getHours(): "+d.getHours());
-check (d.getHours() >= 0);
-//check (d.getHours() <= 1);
 
-// Test behaviour when you set the time during DST then change the d to
-// a non-DST d.
+// Test behaviour when you set the time during DST then change
+// to a non-DST date.
 // setUTCHours should preserve the time of day in UTC;
 // setHours should preserve the time of day in localtime.
-trace ("Testing hour when setting d into/out of DST");
+//
+// We assume that January/December and June/July will have different DST values
+
+trace ("Testing hour when setting date into/out of DST");
 d.setUTCFullYear(2000, 0, 1);
 d.setUTCHours(0, 0, 0, 0);
 d.setUTCMonth(6);




reply via email to

[Prev in Thread] Current Thread [Next in Thread]