jsdate.c revision 6b15695578f07a3f72c4c9475c1a261a3021472a
359a38ce40498397028473d956691915ed3e849atavmjong-free/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
359a38ce40498397028473d956691915ed3e849atavmjong-free * ***** BEGIN LICENSE BLOCK *****
359a38ce40498397028473d956691915ed3e849atavmjong-free * Version: MPL 1.1/GPL 2.0/LGPL 2.1
359a38ce40498397028473d956691915ed3e849atavmjong-free * The contents of this file are subject to the Mozilla Public License Version
359a38ce40498397028473d956691915ed3e849atavmjong-free * 1.1 (the "License"); you may not use this file except in compliance with
359a38ce40498397028473d956691915ed3e849atavmjong-free * the License. You may obtain a copy of the License at
359a38ce40498397028473d956691915ed3e849atavmjong-free * Software distributed under the License is distributed on an "AS IS" basis,
359a38ce40498397028473d956691915ed3e849atavmjong-free * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
359a38ce40498397028473d956691915ed3e849atavmjong-free * for the specific language governing rights and limitations under the
359a38ce40498397028473d956691915ed3e849atavmjong-free * The Original Code is Mozilla Communicator client code, released
359a38ce40498397028473d956691915ed3e849atavmjong-free * March 31, 1998.
359a38ce40498397028473d956691915ed3e849atavmjong-free * The Initial Developer of the Original Code is
359a38ce40498397028473d956691915ed3e849atavmjong-free * Netscape Communications Corporation.
359a38ce40498397028473d956691915ed3e849atavmjong-free * Portions created by the Initial Developer are Copyright (C) 1998
3fad3df12ae2d320c12871d471eb0faf5f187cbdAlex Valavanis * the Initial Developer. All Rights Reserved.
359a38ce40498397028473d956691915ed3e849atavmjong-free * Contributor(s):
359a38ce40498397028473d956691915ed3e849atavmjong-free * Alternatively, the contents of this file may be used under the terms of
359a38ce40498397028473d956691915ed3e849atavmjong-free * either of the GNU General Public License Version 2 or later (the "GPL"),
359a38ce40498397028473d956691915ed3e849atavmjong-free * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
359a38ce40498397028473d956691915ed3e849atavmjong-free * in which case the provisions of the GPL or the LGPL are applicable instead
359a38ce40498397028473d956691915ed3e849atavmjong-free * of those above. If you wish to allow use of your version of this file only
359a38ce40498397028473d956691915ed3e849atavmjong-free * under the terms of either the GPL or the LGPL, and not to allow others to
359a38ce40498397028473d956691915ed3e849atavmjong-free * use your version of this file under the terms of the MPL, indicate your
359a38ce40498397028473d956691915ed3e849atavmjong-free * decision by deleting the provisions above and replace them with the notice
359a38ce40498397028473d956691915ed3e849atavmjong-free * and other provisions required by the GPL or the LGPL. If you do not delete
359a38ce40498397028473d956691915ed3e849atavmjong-free * the provisions above, a recipient may use your version of this file under
359a38ce40498397028473d956691915ed3e849atavmjong-free * the terms of any one of the MPL, the GPL or the LGPL.
359a38ce40498397028473d956691915ed3e849atavmjong-free * ***** END LICENSE BLOCK ***** */
359a38ce40498397028473d956691915ed3e849atavmjong-free * JS date methods.
652485ad88d2a42f827c7e355220efeb3b2e37afLiam P. White * "For example, OS/360 devotes 26 bytes of the permanently
359a38ce40498397028473d956691915ed3e849atavmjong-free * resident date-turnover routine to the proper handling of
359a38ce40498397028473d956691915ed3e849atavmjong-free * December 31 on leap years (when it is Day 366). That
359a38ce40498397028473d956691915ed3e849atavmjong-free * might have been left to the operator."
359a38ce40498397028473d956691915ed3e849atavmjong-free * Frederick Brooks, 'The Second-System Effect'.
359a38ce40498397028473d956691915ed3e849atavmjong-free * The JS 'Date' object is patterned after the Java 'Date' object.
359a38ce40498397028473d956691915ed3e849atavmjong-free * Here is an script:
359a38ce40498397028473d956691915ed3e849atavmjong-free * today = new Date();
359a38ce40498397028473d956691915ed3e849atavmjong-free * print(today.toLocaleString());
3eb97a45889abb73fa05c413b45785ea682f07c5Jon A. Cruz * weekDay = today.getDay();
359a38ce40498397028473d956691915ed3e849atavmjong-free * These Java (and ECMA-262) methods are supported:
359a38ce40498397028473d956691915ed3e849atavmjong-free * getDate (getUTCDate)
359a38ce40498397028473d956691915ed3e849atavmjong-free * getDay (getUTCDay)
359a38ce40498397028473d956691915ed3e849atavmjong-free * getHours (getUTCHours)
359a38ce40498397028473d956691915ed3e849atavmjong-free * getMinutes (getUTCMinutes)
359a38ce40498397028473d956691915ed3e849atavmjong-free * getMonth (getUTCMonth)
359a38ce40498397028473d956691915ed3e849atavmjong-free * getSeconds (getUTCSeconds)
359a38ce40498397028473d956691915ed3e849atavmjong-free * getMilliseconds (getUTCMilliseconds)
359a38ce40498397028473d956691915ed3e849atavmjong-free * getTimezoneOffset
359a38ce40498397028473d956691915ed3e849atavmjong-free * getFullYear (getUTCFullYear)
5f19756f48574526dda8abedebf811c9d1456e80Markus Engel * setDate (setUTCDate)
359a38ce40498397028473d956691915ed3e849atavmjong-free * setHours (setUTCHours)
359a38ce40498397028473d956691915ed3e849atavmjong-free * setMinutes (setUTCMinutes)
359a38ce40498397028473d956691915ed3e849atavmjong-free * setMonth (setUTCMonth)
359a38ce40498397028473d956691915ed3e849atavmjong-free * setSeconds (setUTCSeconds)
359a38ce40498397028473d956691915ed3e849atavmjong-free * setMilliseconds (setUTCMilliseconds)
359a38ce40498397028473d956691915ed3e849atavmjong-free * setYear (setFullYear, setUTCFullYear)
359a38ce40498397028473d956691915ed3e849atavmjong-free * toGMTString (toUTCString)
359a38ce40498397028473d956691915ed3e849atavmjong-free * toLocaleString
359a38ce40498397028473d956691915ed3e849atavmjong-free * These Java methods are not supported
359a38ce40498397028473d956691915ed3e849atavmjong-free * 11/97 - jsdate.c has been rewritten to conform to the ECMA-262 language
3eb97a45889abb73fa05c413b45785ea682f07c5Jon A. Cruz * definition and reduce dependence on NSPR. NSPR is used to get the current
359a38ce40498397028473d956691915ed3e849atavmjong-free * time in milliseconds, the time zone offset, and the daylight savings time
359a38ce40498397028473d956691915ed3e849atavmjong-free * offset for a given time. NSPR is also used for Date.toLocaleString(), for
652485ad88d2a42f827c7e355220efeb3b2e37afLiam P. White * locale-specific formatting, and to get a string representing the timezone.
359a38ce40498397028473d956691915ed3e849atavmjong-free * (Which turns out to be platform-dependent.)
359a38ce40498397028473d956691915ed3e849atavmjong-free * (I did some performance tests by timing how long it took to run what
359a38ce40498397028473d956691915ed3e849atavmjong-free * I had of the js ECMA conformance tests.)
359a38ce40498397028473d956691915ed3e849atavmjong-free * - look at saving results across multiple calls to supporting
359a38ce40498397028473d956691915ed3e849atavmjong-free * functions; the toString functions compute some of the same values
359a38ce40498397028473d956691915ed3e849atavmjong-free * multiple times. Although - I took a quick stab at this, and I lost
359a38ce40498397028473d956691915ed3e849atavmjong-free * rather than gained. (Fractionally.) Hard to tell what compilers/processors
359a38ce40498397028473d956691915ed3e849atavmjong-free * are doing these days.
359a38ce40498397028473d956691915ed3e849atavmjong-free * - look at tweaking function return types to return double instead
359a38ce40498397028473d956691915ed3e849atavmjong-free * of int; this seems to make things run slightly faster sometimes.
359a38ce40498397028473d956691915ed3e849atavmjong-free * (though it could be architecture-dependent.) It'd be good to see
359a38ce40498397028473d956691915ed3e849atavmjong-free * how this does on win32. (Tried it on irix.) Types could use a
359a38ce40498397028473d956691915ed3e849atavmjong-free * general going-over.
359a38ce40498397028473d956691915ed3e849atavmjong-free * Supporting functions - ECMA 15.9.1.*
359a38ce40498397028473d956691915ed3e849atavmjong-free#define MinutesPerDay (HoursPerDay * MinutesPerHour)
359a38ce40498397028473d956691915ed3e849atavmjong-free#define SecondsPerDay (MinutesPerDay * SecondsPerMinute)
359a38ce40498397028473d956691915ed3e849atavmjong-free#define SecondsPerHour (MinutesPerHour * SecondsPerMinute)
359a38ce40498397028473d956691915ed3e849atavmjong-free/* Work around msvc double optimization bug by making these runtime values; if
359a38ce40498397028473d956691915ed3e849atavmjong-free * they're available at compile time, msvc optimizes division by them by
359a38ce40498397028473d956691915ed3e849atavmjong-free * computing the reciprocal and multiplying instead of dividing - this loses
359a38ce40498397028473d956691915ed3e849atavmjong-free * when the reciprocal isn't representable in a double.
359a38ce40498397028473d956691915ed3e849atavmjong-freestatic jsdouble msPerDay = SecondsPerDay * 1000.0;
3eb97a45889abb73fa05c413b45785ea682f07c5Jon A. Cruzstatic jsdouble msPerHour = SecondsPerHour * 1000.0;
3eb97a45889abb73fa05c413b45785ea682f07c5Jon A. Cruzstatic jsdouble msPerMinute = SecondsPerMinute * 1000.0;
359a38ce40498397028473d956691915ed3e849atavmjong-free#define msPerHour (SecondsPerHour * msPerSecond)
359a38ce40498397028473d956691915ed3e849atavmjong-free#define msPerMinute (SecondsPerMinute * msPerSecond)
359a38ce40498397028473d956691915ed3e849atavmjong-free#define DaysInYear(y) ((y) % 4 == 0 && ((y) % 100 || ((y) % 400 == 0)) \
359a38ce40498397028473d956691915ed3e849atavmjong-free/* math here has to be f.p, because we need
359a38ce40498397028473d956691915ed3e849atavmjong-free * floor((1968 - 1969) / 4) == -1
359a38ce40498397028473d956691915ed3e849atavmjong-free#define DayFromYear(y) (365 * ((y)-1970) + floor(((y)-1969)/4.0) \
359a38ce40498397028473d956691915ed3e849atavmjong-free - floor(((y)-1901)/100.0) + floor(((y)-1601)/400.0))
359a38ce40498397028473d956691915ed3e849atavmjong-free#define TimeFromYear(y) (DayFromYear(y) * msPerDay)
359a38ce40498397028473d956691915ed3e849atavmjong-free jsint y = (jsint) floor(t /(msPerDay*365.2425)) + 1970;
359a38ce40498397028473d956691915ed3e849atavmjong-free#define InLeapYear(t) (JSBool) (DaysInYear(YearFromTime(t)) == 366)
359a38ce40498397028473d956691915ed3e849atavmjong-free#define DayWithinYear(t, year) ((intN) (Day(t) - DayFromYear(year)))
359a38ce40498397028473d956691915ed3e849atavmjong-free * The following array contains the day of year for the first day of
359a38ce40498397028473d956691915ed3e849atavmjong-free * each month, where index 0 is January, and day 0 is January 1.
359a38ce40498397028473d956691915ed3e849atavmjong-free {0.0, 31.0, 59.0, 90.0, 120.0, 151.0, 181.0, 212.0, 243.0, 273.0, 304.0, 334.0},
359a38ce40498397028473d956691915ed3e849atavmjong-free {0.0, 31.0, 60.0, 91.0, 121.0, 152.0, 182.0, 213.0, 244.0, 274.0, 305.0, 335.0}
359a38ce40498397028473d956691915ed3e849atavmjong-free#define DayFromMonth(m, leap) firstDayOfMonth[leap][(intN)m];
359a38ce40498397028473d956691915ed3e849atavmjong-free return d + 1;
359a38ce40498397028473d956691915ed3e849atavmjong-free/* LocalTZA gets set by js_InitDateClass() */
652485ad88d2a42f827c7e355220efeb3b2e37afLiam P. White /* abort if NaN */
652485ad88d2a42f827c7e355220efeb3b2e37afLiam P. White /* put our t in an LL, and map it to usec for prtime */
652485ad88d2a42f827c7e355220efeb3b2e37afLiam P. White#define AdjustTime(t) fmod(LocalTZA + DaylightSavingTA(t), msPerDay)
652485ad88d2a42f827c7e355220efeb3b2e37afLiam P. White intN result = (intN) fmod(floor(t/msPerHour), HoursPerDay);
359a38ce40498397028473d956691915ed3e849atavmjong-free intN result = (intN) fmod(floor(t / msPerMinute), MinutesPerHour);
if (result < 0)
return result;
static intN
if (result < 0)
return result;
static jsdouble
if (month < 0)
+ monthday
return result;
&& !((d < 0 ? -d : d) > HalfTimeDomain)) \
static const char* wtb[] = {
static int ttb[] = {
static JSBool
if (ignoreCase) {
s1off++;
s2off++;
count--;
if (count == 0) {
return result;
static jsdouble
return result;
static JSBool
jsdouble d;
return JS_FALSE;
if (!JSDOUBLE_IS_FINITE(d)) {
d = TIMECLIP(d);
static JSBool
size_t i = 0;
int prevc = 0;
if (limit == 0)
goto syntax;
while (i < limit) {
prevc = c;
while (i < limit) {
if (--depth <= 0)
goto syntax;
tzoffset = n;
if (year >= 0)
goto syntax;
goto syntax;
if (hour < 0)
else if (min < 0)
goto syntax;
if (mon < 0)
else if (mday < 0)
goto syntax;
goto syntax;
if (tzoffset < 0)
tzoffset -= n;
tzoffset += n;
} else if (mday < 0) {
goto syntax;
prevc = 0;
prevc = c;
while (i < limit) {
goto syntax;
for (k = (sizeof(wtb)/sizeof(char*)); --k >= 0;)
if (action != 0) {
if (action < 0) {
goto syntax;
hour = 0;
if (mon < 0) {
goto syntax;
goto syntax;
prevc = 0;
goto syntax;
if (sec < 0)
sec = 0;
if (min < 0)
min = 0;
if (hour < 0)
hour = 0;
return JS_TRUE;
return JS_TRUE;
*result = 0;
return JS_FALSE;
static JSBool
if (!str)
return JS_FALSE;
return JS_TRUE;
static JSBool
static jsdouble *
return NULL;
static JSBool
if (!date)
return JS_FALSE;
static JSBool
if (!date)
return JS_FALSE;
static JSBool
if (!date)
return JS_FALSE;
static JSBool
if (!date)
return JS_FALSE;
static JSBool
if (!date)
return JS_FALSE;
static JSBool
if (!date)
return JS_FALSE;
static JSBool
if (!date)
return JS_FALSE;
static JSBool
if (!date)
return JS_FALSE;
static JSBool
if (!date)
return JS_FALSE;
static JSBool
if (!date)
return JS_FALSE;
static JSBool
if (!date)
return JS_FALSE;
static JSBool
if (!date)
return JS_FALSE;
static JSBool
if (!date)
return JS_FALSE;
static JSBool
if (!date)
return JS_FALSE;
static JSBool
if (!date)
return JS_FALSE;
static JSBool
if (!date)
return JS_FALSE;
static JSBool
if (!date)
return JS_FALSE;
static JSBool
if (!date)
return JS_FALSE;
return JS_FALSE;
static JSBool
uintN i;
if (!date)
return JS_FALSE;
* the Date.setWhatever functions in ECMA are only varargs
* d.setMilliseconds()" returns NaN. Blech.
if (argc == 0)
for (i = 0; i < argc; i++) {
return JS_FALSE;
if (local)
if (local)
static JSBool
static JSBool
static JSBool
static JSBool
static JSBool
static JSBool
static JSBool
static JSBool
static JSBool
uintN i;
if (!date)
return JS_FALSE;
if (argc == 0)
for (i = 0; i < argc; i++) {
return JS_FALSE;
lorutime = +0.;
if (local)
if (local)
static JSBool
static JSBool
static JSBool
static JSBool
static JSBool
static JSBool
static JSBool
jsdouble t;
if (!date)
return JS_FALSE;
return JS_FALSE;
static const char* days[] =
static const char* months[] =
static JSBool
if (!date)
return JS_FALSE;
if (!str)
return JS_FALSE;
return JS_TRUE;
/* for Date.toLocaleString; interface to PRMJTime date struct.
if (findEquivalent) {
typedef enum formatspec {
} formatspec;
static JSBool
for (i = 0; i < tzlen; i++) {
switch (format) {
case FORMATSPEC_FULL:
case FORMATSPEC_DATE:
case FORMATSPEC_TIME:
if (!str)
return JS_FALSE;
return JS_TRUE;
static JSBool
if (!date)
return JS_FALSE;
if (result_len == 0)
if (!str)
return JS_FALSE;
return JS_TRUE;
static JSBool
static JSBool
static JSBool
static JSBool
if (!date)
return JS_FALSE;
static JSBool
if (!date)
return JS_FALSE;
#if JS_HAS_TOSOURCE
#include <string.h>
#include "jsdtoa.h"
static JSBool
if (!date)
return JS_FALSE;
if (!numStr) {
return JS_FALSE;
if (!bytes) {
return JS_FALSE;
if (!str) {
return JS_FALSE;
return JS_TRUE;
static JSBool
if (!date)
return JS_FALSE;
static JSBool
if (argc == 0)
if (!str)
return JS_FALSE;
#if JS_HAS_TOSOURCE
static jsdouble *
if (!date)
return NULL;
return date;
static JSBool
jsdouble d;
if (argc == 0) {
if (!date)
return JS_FALSE;
return JS_FALSE;
if (!date)
return JS_FALSE;
if (!date)
return JS_FALSE;
if (!str)
return JS_FALSE;
return JS_FALSE;
if (!date)
return JS_FALSE;
return JS_TRUE;
if (!date)
return JS_FALSE;
return JS_TRUE;
JSObject *
if (!proto)
return NULL;
return NULL;
if (!proto_date)
return NULL;
return proto;
if (!obj)
return NULL;
if (!date)
return NULL;
return obj;
return obj;
return JS_FALSE;
return JS_TRUE;
JS_FRIEND_API(int)
JS_FRIEND_API(int)
JS_FRIEND_API(int)
JS_FRIEND_API(int)
JS_FRIEND_API(int)
JS_FRIEND_API(int)
JS_FRIEND_API(void)
if (!date)
local = 0;
JS_FRIEND_API(void)
if (!date)
JS_FRIEND_API(void)
if (!datep)
date,
JS_FRIEND_API(void)
if (!date)
JS_FRIEND_API(void)
if (!date)
JS_FRIEND_API(void)
if (!date)
return (*date);