[Top][All Lists]
[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);
- [Gnash-commit] gnash ChangeLog configure.ac doc/C/asspec/date....,
Martin Guy <=