gnash-commit
[Top][All Lists]
Advanced

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

[Gnash-commit] gnash ChangeLog server/asobj/Date.cpp testsuite...


From: Martin Guy
Subject: [Gnash-commit] gnash ChangeLog server/asobj/Date.cpp testsuite...
Date: Wed, 07 Feb 2007 18:51:15 +0000

CVSROOT:        /sources/gnash
Module name:    gnash
Changes by:     Martin Guy <martinwguy> 07/02/07 18:51:14

Modified files:
        .              : ChangeLog 
        server/asobj   : Date.cpp 
        testsuite/actionscript.all: Date.as 

Log message:
        Completed reverse-engineering of get/set Date methods needing check for
        ftime() and added testsuite for same

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/gnash/ChangeLog?cvsroot=gnash&r1=1.2267&r2=1.2268
http://cvs.savannah.gnu.org/viewcvs/gnash/server/asobj/Date.cpp?cvsroot=gnash&r1=1.19&r2=1.20
http://cvs.savannah.gnu.org/viewcvs/gnash/testsuite/actionscript.all/Date.as?cvsroot=gnash&r1=1.14&r2=1.15

Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/gnash/gnash/ChangeLog,v
retrieving revision 1.2267
retrieving revision 1.2268
diff -u -b -r1.2267 -r1.2268
--- ChangeLog   7 Feb 2007 18:20:35 -0000       1.2267
+++ ChangeLog   7 Feb 2007 18:51:14 -0000       1.2268
@@ -1,3 +1,10 @@
+2007-02-06 Martin Guy <address@hidden>
+
+       * server/asobj/Data.cpp: Completed reverse engineering of get/set
+         methods
+       * configure.ac: Added check for ftime()
+       * testsuite/actionscript.all/Date.as: Add tests for get/set methods
+
 2007-02-07 Sandro Santilli <address@hidden>
 
        * server/debugger.h: const-correctness fixes.

Index: server/asobj/Date.cpp
===================================================================
RCS file: /sources/gnash/gnash/server/asobj/Date.cpp,v
retrieving revision 1.19
retrieving revision 1.20
diff -u -b -r1.19 -r1.20
--- server/asobj/Date.cpp       6 Feb 2007 18:03:38 -0000       1.19
+++ server/asobj/Date.cpp       7 Feb 2007 18:51:14 -0000       1.20
@@ -22,6 +22,15 @@
 //
 // TODO:
 //     implement static method Date.UTC
+// BUGS:
+//     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 handles a huge range of dates, including
+//     thousands of years BC, but the localtime code here only works for
+//     valid Unix dates Dec 13 20:45:52 1901 - Jan 19 03:14:07 2038.
+//     Our UTC code could be hacked into working outside this range but
 //
 // To probe FlashPlayer functionality put something like:
 // class Test {
@@ -29,8 +38,11 @@
 //
 //        static function main(mc) {
 //             var now = new Date();
+//             var s:String;
 //               _root.createTextField("tf",0,0,0,320,200);
-//              _root.tf.text = now.toString();
+//             s = now.toString();     // or whatever
+//             trace(s);                       // output in gnash -v
+//              _root.tf.text = now.toString(); // output in flash player
 //        }
 // }
 // in test.as, compile with
@@ -61,21 +73,53 @@
 // but not for timezone offset bcos ftime's TZ stuff is unreliable.
 // For that we use tzset()/timezone if it is available
 
-#ifndef HAVE_GETTIMEOFDAY
+#if HAVE_GETTIMEOFDAY
 # include <sys/timeb.h>                // for ftime()
-# ifdef HAVE_TZSET
+# if HAVE_TZSET
        extern long timezone;   // for tzset()/timezone
 # endif
 #endif
 
 namespace gnash {
 
-#ifdef HAVE_LOCALTIME_R
-       // Use the library functions
-#      define _gmtime_r gmtime_r
+// We have our own UTC time converter that works with Flash timestamps
+// (double milliseconds after 1970) rather than the time-limited time_t.
+// Define USE_UTCCONV as 1 to use these versions;
+// Undefine USE_UTCCONV or define it as 0 to use gmtime_r() and mktime()
+// for UTC date conversions (the mktime() versions sometimes set the time
+// wrong by an hour).
+#define USE_UTCCONV 1
+
+#if USE_UTCCONV
+// forward declarations
+static void utctime(double tim, struct tm *tmp, double *msecp);
+static double mkutctime(struct tm *tmp, double msec);
+#endif
+
+// Select functions to implement _localtime_r and _gmtime_r
+// For localtime we use the glibc stuff; for UTC we prefer our own routines
+// because the C library does not provide a function to convert
+// from struct tm to datestamp in UTC.
+
+#if HAVE_LOCALTIME_R
+       // Use the library function
 #      define _localtime_r localtime_r
-#else
-// Roll our own compatible versions rather checking the ifdef everywhere
+
+# if USE_UTCCONV
+static struct tm *
+_gmtime_r(time_t *t, struct tm *tm)
+{
+       double msec;
+       utctime(*t * 1000.0, tm, &msec);
+       return(tm);
+}
+# else
+#      define _gmtime_r gmtime_r
+# endif
+
+#else // HAVE_LOCALTIME_R
+
+// Roll our own compatible versions rather than checking the ifdef everywhere
 static struct tm *
 _localtime_r(time_t *t, struct tm *tm)
 {
@@ -87,14 +131,43 @@
 static struct tm *
 _gmtime_r(time_t *t, struct tm *tm)
 {
+#if USE_UTCCONV
+       double msec;
+       utctime(*t * 1000.0, &tm, &msec);
+#else
        struct tm *tmp;
        tmp = gmtime(t);
        memcpy(tm, tmp, sizeof(struct tm));
        return(tm);
-}
 #endif
+}
+#endif // HAVE_LOCALTIME_R
+
+// A modified version of mktime that works in localtime on struct tm
+// without you having to set tm_isdst.
+// If the real mktime() sees isdst==0 with a DST date, it sets
+// t_isdst and modifies the hour fields, but we need to set the
+// specified hour in the localtime in force at that time.
+//
+// To do this we set tm_isdst to the correct value for that moment in time
+// by doing an initial conversion of the time to find out is_dst for that
+// moment without DST, then do the real conversion.
+// This may get things wrong around the hour when the clocks go back or forth.
+static time_t
+_mktime(struct tm *tmp)
+{
+       struct tm tm2 = *tmp;
+       time_t t2;
+
+               tm2.tm_isdst = 0;
+       t2 = mktime(&tm2);              // Convert the time without DST,
+       _localtime_r(&t2, &tm2);        // find out whether DST was in force
+       tmp->tm_isdst = tm2.tm_isdst;   // and apply that to the given time
+       return(mktime(tmp));
+}
 
-// forwrd declarations
+
+// forward declarations
 static void date_new(const fn_call& fn);
 static void date_getdate(const fn_call& fn);
 static void date_getday(const fn_call& fn);
@@ -267,14 +340,6 @@
                 tm.tm_mday = 1;
                 tm.tm_mon = (int) fn.arg(1).to_number();
                 tm.tm_year = (int) fn.arg(0).to_number();
-               // We need to know whether DST was in effect at the date they
-               // mention to know how to interpret the hour they specify.
-               // In fact this is impossible bcos on the day that the
-               // clocks go back there are two hours of time with the same
-               // local year-month-day-hour-minute values.
-               // Example: 1995 Apr 2 01:00-59 and 02:00-59 give the same UTC,
-               // both in GMT (which is wrong: BST started 26 March!)
-               // We'll do our best...
 
                switch (fn.nargs) {
                default:
@@ -282,7 +347,8 @@
                        log_aserror("Date constructor called with more than 7 
arguments");
                    )
                case 7:
-                       millisecs = fn.arg(6).to_number();
+                       // fractions of milliseconds are ignored
+                       millisecs = (int)fn.arg(6).to_number();
                case 6:
                        tm.tm_sec = (int)fn.arg(5).to_number();
                case 5:
@@ -301,9 +367,8 @@
                        // Fractional part of a year is ignored.
                        if (tm.tm_year >= 100) tm.tm_year -= 1900;
                }
-               // Experimentally, glibc mktime ignores and tm_isdst and sets
-               // it from the date, applying it at midnight (not at 2am)
-               utcsecs = mktime(&tm);  // mktime converts from local time
+
+               utcsecs = _mktime(&tm); // convert from local time
                if (utcsecs == -1) {
                        // mktime could not represent the time
                        log_error("Date() failed to initialise from arguments");
@@ -338,28 +403,18 @@
 // Functions to return broken-out elements of the date and time.
 
 // We use a prototype macro to generate the function bodies because the many
-// individual functions are almost identical.
-//
-// localtime() and gmtime() return pointers to static structures, which is
-// not thread-safe, so we use the local-storage variants localtime_r gmtime_r
-// if they are available, hence two versions of the macro here.
+// individual functions are small and almost identical.
+
+// This calls _gmtime_r and _localtime_r, which are defined above into
+// gmtime_r and localtime_r or our own local equivalents.
 
-#if HAVE_LOCALTIME_R
 #define date_get_proto(function, timefn, element) \
        static void function(const fn_call& fn) { \
                date_as_object* date = ensure_date_object(fn.this_ptr); \
                time_t t = (time_t)(date->value / 1000.0); \
                struct tm tm; \
-               fn.result->set_int(timefn##_r(&t, &tm)->element); \
-       }
-#else
-#define date_get_proto(function, timefn, element) \
-       static void function(const fn_call& fn) { \
-               date_as_object* date = ensure_date_object(fn.this_ptr); \
-               time_t t = (time_t)(date->value / 1000.0); \
-               fn.result->set_int(timefn(&t)->element); \
+               fn.result->set_int(_##timefn##_r(&t, &tm)->element); \
        }
-#endif
 
 /// \brief Date.getYear returns the year of the specified Date object
 /// according to local time. The year is the full year minus 1900.
@@ -439,24 +494,31 @@
 
 static int minutes_east_of_gmt()
 {
-#ifdef HAVE_GETTIMEOFDAY
-       struct timeval tv;
-       struct timezone tz;
-       gettimeofday(&tv,&tz);
-       return(-tz.tz_minuteswest);
-#elif defined(HAVE_TZSET)
+#if HAVE_TZSET
        tzset();
        return(-timezone/60); // timezone is seconds west of GMT
-#else
+#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.
-       // Still, mancansa d'asu, t'acuma i buoi.
        struct timeb tb;
                
        ftime (&tb);
        // tb.timezone is number of minutes west of GMT
        return(-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
+       // never been used under Linux; it has not been and will not be
+       // supported by libc or glibc."
+       // Still, mancansa d'asu, t'acuma i buoi.
+       struct timeval tv;
+       struct timezone tz;
+       gettimeofday(&tv,&tz);
+       return(-tz.tz_minuteswest);
+#else
+       return(0);      // No idea.
 #endif
 }
 
@@ -502,8 +564,7 @@
 // The Adobe player 9 behaves strangely. e.g., after "new date = Date(0)":
 // date.setYear(1970); date.setMonth(1); date.setDate(29); gives Mar 1 but
 // date.setYear(1970); date.setDate(29); date.setMonth(1); gives Feb 28
-// I doubt we can reproduce its exact operation, so just let mktime do what
-// it wants with rogue values.
+// For now, just let mktime do as it pleases with rogue values.
 
 // We need two sets of the same functions: those that take localtime values
 // and those that take UTC (GMT) values.
@@ -526,11 +587,13 @@
 }
 
 // convert Unix time structure and the remaining milliseconds to
-// Flash datestamp
+// Flash datestamp.
+// To prevent mktime() from altering the hour if tm_isdst is wrong, we have to
+// do a preliminary pass to set tm_isdst.
 static void
 local_tm_msec_to_date(struct tm &tm, double &msec, date_as_object* &date)
 {
-       time_t t = mktime(&tm);
+       time_t t = _mktime(&tm);
 
        // Reconstruct the time value and put the milliseconds back in.
        // If mktime fails to reconstruct the date, change nothing.
@@ -544,15 +607,18 @@
 // Two low-level functions to convert between datestamps and time structures
 // whose contents are in UTC
 //
-// Unfortunately, mktime() only works in localtime.
-// gmtime() will split it for us, but how do we put it back together again?
+// 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)
 {
+#if USE_UTCCONV
+       utctime(date->value, &tm, &msec);
+#else
        time_t t = (time_t)(date->value / 1000.0);
        msec = std::fmod(date->value, 1000.0);
        _gmtime_r(&t, &tm);
+#endif
 }
 
 // TODO:
@@ -564,6 +630,9 @@
 static void
 utc_tm_msec_to_date(struct tm &tm, double &msec, date_as_object* &date)
 {
+#if USE_UTCCONV
+       date->value = mkutctime(&tm, msec);
+#else
        time_t t = mktime(&tm);
        if (t == (time_t)(-1)) {
            log_error("utc_tm_msec_to_date failed to convert back to Date");
@@ -573,6 +642,7 @@
        }
        
        date->value = t * 1000.0 + msec;
+#endif
 }
 
 // Now the generic version of these two functions that switch according to
@@ -620,6 +690,19 @@
 /// If changing the year or month results in an impossible date, it is
 /// normalised: 29 Feb becomes 1 Mar, 31 April becomes 1 May etc.
 
+// When changing the year/month/date from a date in Daylight Saving Time to a
+// date not in DST or vice versa, with setYear and setFullYear the hour of day
+// remains the same in *local time* not in UTC.
+// So if a date object is set to midnight in January and you change the date
+// to June, it will still be midnight localtime.
+//
+// When using setUTCFullYear instead, the time of day remains the same *in UTC*
+// so, in the northern hemisphere, changing midnight from Jan to June gives
+// 01:00 localtime.
+//
+// Heaven knows what happens if it is 1.30 localtime and you change the date
+// to the day the clocks go forward.
+
 static void _date_setfullyear(const fn_call& fn, bool utc) {
        date_as_object* date = ensure_date_object(fn.this_ptr);
 
@@ -653,11 +736,11 @@
 /// If year is an integer between 0-99, setYear sets the year at 1900 + year;
 /// otherwise, the year is a four-digit one.
 //
-/// Contrary to the spec at sephiroth.it, this takes and acts on optional
-/// parameters month and day; if they are unspecified their values are not
-/// changed.
-///
-/// There is no setUTCYear() function.
+// Contrary to the spec at sephiroth.it, this takes and acts on optional
+// parameters month and day; if they are unspecified their values are not
+// changed.
+//
+// There is no setUTCYear() function.
 
 static void date_setyear(const fn_call& fn) {
        date_as_object* date = ensure_date_object(fn.this_ptr);
@@ -694,7 +777,7 @@
 /// month: An integer from 0 (January) to 11 (December).
 /// date: An integer from 1 to 31. [optional]
 
-static void _date_setmonth(const fn_call& fn, bool utc=false) {
+static void _date_setmonth(const fn_call& fn, bool utc) {
        date_as_object* date = ensure_date_object(fn.this_ptr);
 
        // assert(fn.nargs >= 1 && fn.nargs <= 2);
@@ -724,7 +807,7 @@
 //
 /// date: An integer from 1 to 31
 
-static void _date_setdate(const fn_call& fn, bool utc=false) {
+static void _date_setdate(const fn_call& fn, bool utc) {
        date_as_object* date = ensure_date_object(fn.this_ptr);
 
        if (fn.nargs < 1) {
@@ -757,11 +840,15 @@
 ///
 /// If optional fields are omitted, their values in the Date object
 /// are left the same as they were.
-///
-/// Contrary to the spec at sephiroth.it, this takes and acts on optional
-/// parameters min, sec and millisec.
+//
+// Contrary to the spec at sephiroth.it, this takes and acts on optional
+// parameters min, sec and millisec.
+//
+// Flash Player only takes notice of the whole part of millisec,
+// truncating it, not rounding it. The only way to set a fractional number of
+// milliseconds is to use setTime(n) or call the constructor with one argmuent.
 
-static void _date_sethours(const fn_call& fn, bool utc=false) {
+static void _date_sethours(const fn_call& fn, bool utc) {
        date_as_object* date = ensure_date_object(fn.this_ptr);
 
        // assert(fn.nargs >= 1 && fn.nargs <= 4);
@@ -779,7 +866,7 @@
            if (fn.nargs >= 3)
                    tm.tm_sec = (int) fn.arg(2).to_number();
            if (fn.nargs >= 4)
-                   msec = fn.arg(3).to_number();
+                   msec = (int) fn.arg(3).to_number();
            if (fn.nargs > 4) {
                IF_VERBOSE_ASCODING_ERRORS(
                    log_aserror("Date.setHours was called with more than four 
arguments");
@@ -797,7 +884,7 @@
 /// Contrary to the spec at sephiroth.it, this takes and acts on optional
 /// extra parameters secs and millisecs.
 
-static void _date_setminutes(const fn_call& fn, bool utc=false) {
+static void _date_setminutes(const fn_call& fn, bool utc) {
        date_as_object* date = ensure_date_object(fn.this_ptr);
 
        //assert(fn.nargs >= 1 && fn.nargs <= 3);
@@ -813,7 +900,7 @@
            if (fn.nargs >= 2)
                    tm.tm_sec = (int) fn.arg(1).to_number();
            if (fn.nargs >= 3)
-                   msec = fn.arg(2).to_number();
+                   msec = (int) fn.arg(2).to_number();
            if (fn.nargs > 3) {
                IF_VERBOSE_ASCODING_ERRORS(
                    log_aserror("Date.setMinutes was called with more than 
three arguments");
@@ -828,7 +915,7 @@
 /// the milliseconds for the specified Date object in local time
 /// and returns the new time in milliseconds.
 
-static void _date_setseconds(const fn_call& fn, bool utc=false) {
+static void _date_setseconds(const fn_call& fn, bool utc) {
        date_as_object* date = ensure_date_object(fn.this_ptr);
 
        // assert(fn.nargs >= 1 && fn.nargs <= 2);
@@ -846,7 +933,7 @@
            date_to_tm_msec(date, tm, msec, utc);
            tm.tm_sec = (int) fn.arg(0).to_number();
            if (fn.nargs >= 2)
-                   msec = fn.arg(1).to_number();
+                   msec = (int) fn.arg(1).to_number();
            if (fn.nargs > 2) {
                IF_VERBOSE_ASCODING_ERRORS(
                    log_aserror("Date.setMinutes was called with more than 
three arguments");
@@ -867,7 +954,7 @@
            )
        } else {
            // Zero the milliseconds and set them from the argument.
-           date->value = std::fmod(date->value, 1000.0) + 
fn.arg(0).to_number();
+           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");
@@ -1010,5 +1097,120 @@
 
 }
 
+#ifdef USE_UTCCONV
+/*
+ * This routine converts time as follows.
+ * The epoch is 00:00 Jan 1 1970 GMT.
+ * The argument time is in seconds since then.
+ * utctime() fills the structure pointed to by tmp as follows:
+ *
+ *     tm_sec          seconds (0-59)
+ *     tm_min          minutes (0-59)
+ *     tm_hour         hours (0-23)
+ *     tm_mday         day of month (1-31)
+ *     tm_mon          month (0-11)
+ *     tm_year         year - 1900 (70- )
+ *     tm_wday         weekday (0-6, Sun is 0)
+ *     tm_yday         day of the year (0-364/5)
+ *     tm_isdst        is daylight saving time in force? (always 0 = GMT)
+ *
+ *     Reference: Algorithm 199 by Robert G. Tantzen
+ *     from "Collected Algorithms from ACM" Volume 1
+ *     Published by the Association for Computing Machinery, 1980.
+ *     See http://portal.acm.org/citation.cfm?id=390020 (pay-to-know site)
+ *     See also http://ftp.unicamp.br/pub/unix-c/calendars/jday-jdate.c
+ *
+ *     When munging this, bear in mind that for calculation
+ *     the year starts on March the 1st (yday == 0)
+ *
+ *     These routines have been tested exhaistively against gmtime() and
+ *     may work for dates outside the range that gmtime() can handle
+ *     (Dec 13 20:45:52 1901 - Jan 19 03:14:07 2038)
+ *     Dates up to 2100 should work; ones before 1900 I doubt it.
+ */
+
+static void
+utctime(double tim, struct tm *tmp, double *msecp)
+{
+       register int d; /* workhorse variable */
+       register int y, m, a;
+
+       /*
+        *      This routine is good until year 2100.
+        */
+
+       *msecp = std::fmod(tim, 1000.0); tim = trunc(tim / 1000.0);
+       tmp->tm_sec = (d = (int) std::fmod(tim, 86400.0)) % 60;
+       tmp->tm_min = (d/=60) % 60;
+       tmp->tm_hour = d/60;
+
+       d = (int) trunc(tim / 86400.0); /* no of days after 1 Jan 1970 */
+
+       /* Make time of day positive when time is negative */
+       if (tim < 0) {
+               if (*msecp < 0) { *msecp += 1000; tmp->tm_sec--; }
+               if (tmp->tm_sec < 0) { tmp->tm_sec += 60; tmp->tm_min--; }
+               if (tmp->tm_min < 0) { tmp->tm_min += 60; tmp->tm_hour--; }
+               if (tmp->tm_hour < 0) { tmp->tm_hour += 24; d--; }
+       }
+
+       /*
+        * d is the day number after 1 Jan 1970. Generate day of the week.
+        * The addend is 4 mod 7 (1/1/1970 was Thursday)
+        */
+
+       if (d >= -4) tmp->tm_wday = (d+4)%7;
+       else tmp->tm_wday = 6 - (((-5)-d)%7);
+
+       // 693902 is the days from 1st March 0000 to 1st Jan 1900
+       // 25567 is the days from 1st Jan 1900 to 1st Jan 1970
+       // 10957 is the days from 1st Jan 1970 to 1st Jan 2000
+       // 1461 is the number of days in 4 years
+
+       /* deal with years 2000-2099 */
+       if ( d > 10957+59 /* 29 Feb 2000 */ ) y = 100; else y = 0;
+       y += ( d = ( 4 * ( d + 693902+25567 ) - 1 ) % 146097 | 3 ) / 1461;
+       a = ( d = ( d % 1461 ) / 4 + 1 ) - 307;
+       m = ( ( d *= 5 ) - 3 ) / 153;
+       tmp->tm_mday = ( d + 2 - 153 * m ) / 5;
+
+       /* adjust for fact that day==0 is 1st Mar */
+       if ((m += 2) > 11) { m -= 12; y++; }
+       tmp->tm_yday = ( a >= 0 ? a : a+365 );
+       if ( (y & 3) == 0 && a < 0) tmp->tm_yday++;
+       tmp->tm_mon=m;
+       tmp->tm_year=y;
+       tmp->tm_isdst = 0;
+}
+
+/* Convert a gregorian calendar date to milliseconds since 1 Jan 1970 UTC */
+static double
+mkutctime(struct tm *tmp, double msec)
+{
+       int d = tmp->tm_mday;
+       int m = tmp->tm_mon + 1;
+       int ya = tmp->tm_year;  /* Years since 1900 */
+       int k;  /* day number since 1 Jan 1900 */
+
+       // For calculation, convert to a year starting on 1 March
+       if (m > 2) m -= 3;
+       else {
+               m += 9;
+               ya--;
+       }
+
+       k = (1461 * ya) / 4 + (153 * m + 2) / 5 + d + 58;
+
+       /* K is now the day number since 1 Jan 1900.
+        * Convert to minutes since 1 Jan 1970 */
+       /* 25567 is the number of days from 1 Jan 1900 to 1 Jan 1970 */
+       k = ((k - 25567) * 24 + tmp->tm_hour) * 60 + tmp->tm_min;
+       
+       // Converting to double after minutes allows for +/- 4082 years with
+       // 32-bit signed integers.
+       return  (k * 60.0 + tmp->tm_sec) * 1000.0 + msec;
+}
+#endif // UTCCONV
+
 } // end of gnash namespace
 

Index: testsuite/actionscript.all/Date.as
===================================================================
RCS file: /sources/gnash/gnash/testsuite/actionscript.all/Date.as,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -b -r1.14 -r1.15
--- testsuite/actionscript.all/Date.as  2 Feb 2007 10:31:32 -0000       1.14
+++ testsuite/actionscript.all/Date.as  7 Feb 2007 18:51:14 -0000       1.15
@@ -20,14 +20,14 @@
 // 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.14 2007/02/02 10:31:32 strk Exp $";
+rcsid="$Id: Date.as,v 1.15 2007/02/07 18:51:14 martinwguy Exp $";
 
 #include "check.as"
 
 check (Date);
 
 // test the Date constuctor
-var date = new Date;
+var date = new Date(70,1,2,3,4,5,6,7);
 check (date);
 
 // test methods existance
@@ -111,3 +111,118 @@
 check_equals (date.tostring, undefined);
 
 #endif
+
+// Test decoding methods
+// Check the epoch, 1 Jan 1970
+trace ("Testing 1 Jan 1970 UTC");
+check_equals (date.setTime(0), 0);
+check_equals (date.getTime(), 0);
+check_equals (date.getUTCFullYear(), 1970);
+check_equals (date.getUTCMonth(), 0);
+check_equals (date.getUTCDate(), 1);
+check_equals (date.getUTCDay(), 4);    // It was a Thursday
+check_equals (date.getUTCHours(), 0);
+check_equals (date.getUTCMinutes(), 0);
+check_equals (date.getUTCSeconds(), 0);
+check_equals (date.getUTCMilliseconds(), 0);
+check_equals (date.valueOf(), 0);
+
+// localtime functions and toString are hard to test cos we can't find out
+// whether DST is in force or not.
+// However, DST only add 0 to 1 hour to the local hour so we can set the
+// UTC time to compensate for the year-long offset and check it is between
+// 0 and 1
+trace ("Testing 1 Jan 2000 UTC");
+date.setUTCFullYear(2000, 0, 1);
+date.setUTCHours(0, 0, 0);
+check_equals (date.getUTCFullYear(), 2000);
+check_equals (date.getUTCMonth(), 0);
+check_equals (date.getUTCDate(), 1);
+check_equals (date.getUTCDay(), 6);    // It was a Saturday
+check_equals (date.getUTCHours(), 0);
+check_equals (date.getUTCMinutes(), 0);
+check_equals (date.getUTCSeconds(), 0);
+check_equals (date.getUTCMilliseconds(), 0);
+check_equals (date.valueOf(), 946684800000.0); // I asked flashplayer
+
+trace ("Testing 1 Jul 2000 UTC");
+date.setUTCFullYear(2000, 6, 1);
+date.setUTCHours(0, 0, 0);
+check_equals (date.getUTCFullYear(), 2000);
+check_equals (date.getUTCMonth(), 6);
+check_equals (date.getUTCDate(), 1);
+check_equals (date.getUTCDay(), 6);    // It was a Saturday
+check_equals (date.getUTCHours(), 0);
+check_equals (date.getUTCMinutes(), 0);
+check_equals (date.getUTCSeconds(), 0);
+check_equals (date.getUTCMilliseconds(), 0);
+check_equals (date.valueOf(), 962409600000.0); // I asked flashplayer
+
+trace ("Testing 1 Jan 2000 localtime");
+// The many-argument version of the Date constructor sets the date in localtime
+delete date;
+var date = new Date(2000, 0, 1, 0, 0, 0, 0);
+check_equals (date.getFullYear(), 2000);
+check_equals (date.getYear(), 100);
+check_equals (date.getMonth(), 0);
+check_equals (date.getDate(), 1);
+check_equals (date.getDay(), 6);       // It was a Saturday
+check_equals (date.getHours(), 0);
+check_equals (date.getMinutes(), 0);
+check_equals (date.getSeconds(), 0);
+check_equals (date.getMilliseconds(), 0);
+
+trace ("Testing 1 Jul 2000 localtime");
+// The many-argument version of the Date constructor sets the date in localtime
+delete date;
+var date = new Date(2000, 6, 1, 0, 0, 0, 0);
+check_equals (date.getFullYear(), 2000);
+check_equals (date.getYear(), 100);
+check_equals (date.getMonth(), 6);
+check_equals (date.getDate(), 1);
+check_equals (date.getDay(), 6);       // It was a Saturday
+check_equals (date.getHours(), 0);
+check_equals (date.getMinutes(), 0);
+check_equals (date.getSeconds(), 0);
+check_equals (date.getMilliseconds(), 0);
+
+// Test TimezoneOffset and local hours by setting a date 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(date.getTimezoneOffset());   // in mins east of GMT
+trace("timezone offset = " + tzoffset.toString());
+date.setUTCFullYear(2000, 0, 1);
+date.setUTCHours(0, 0, 0, 0);
+date.setTime(date.getTime() - (60000*tzoffset));
+check (date.getHours() >= 0);
+check (date.getHours() <= 1);
+
+// Test behaviour when you set the time during DST then change the date 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 date into/out of DST");
+date.setUTCFullYear(2000, 0, 1);
+date.setUTCHours(0, 0, 0, 0);
+date.setUTCMonth(6);
+check_equals (date.getUTCHours(), 0);
+
+date.setUTCFullYear(2000, 6, 1);
+date.setUTCHours(0, 0, 0, 0);
+date.setUTCMonth(11);
+check_equals (date.getUTCHours(), 0);
+
+date.setFullYear(2000, 0, 1);
+date.setHours(0, 0, 0, 0);
+date.setMonth(6);
+check_equals (date.getHours(), 0);
+
+date.setFullYear(2000, 6, 1);
+date.setHours(0, 0, 0, 0);
+date.setMonth(11);
+check_equals (date.getHours(), 0);
+
+// It's not easy to test the toString() code here cos we cannot find out from
+// within AS whether DST is in effect or not.




reply via email to

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