By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,689 Members | 1,718 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,689 IT Pros & Developers. It's quick & easy.

Numeric Date Validation

P: n/a

It has appeared that ancient sources give a method for Numeric Date
Validation that involves numerous tests to determine month length;
versions are often posted by incomers here. That sort of code seems
unnecessarily long.

For some while, the following approach has been given here :-

function ValidDate(y, m, d) { // m = 0..11 ; y m d integers, y!=0
with (new Date(y, m, d))
return (getMonth()==m && getDate()==d) }

and it may remain the shortest code. But it does require, in every
case, the creation and disposal of a Date Object.

The following is about 50% longer in code, but about four times faster
in my system - and it seems to be right, too.

function DateOK(Y, M, D) {
return D>0 && (D<=[,31,28,31,30,31,30,31,31,30,31,30,31][M] ||
D==29 && M==2 && Y%4==0 && (Y%100>0 || Y%400==0) ) }

Note that checking for 1 <= M <= 12 is inherent, and that the Leapness
of the year is only determined if the date given is February 29th.

Also, it is easy to use only the quadrennial rule if it is certain that
dates are in 1901-2099, or only two rules for 2001-2399.

Comments ? Tests ??

--
John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v4.00 IE 4
<URL:http://jibbering.com/faq/> Jim Ley's FAQ for news:comp.lang.javascript
<URL:http://www.merlyn.demon.co.uk/js-index.htm> jscr maths, dates, sources.
<URL:http://www.merlyn.demon.co.uk/> TP/BP/Delphi/jscr/&c, FAQ items, links.
Jul 23 '05 #1
Share this Question
Share on Google+
30 Replies


P: n/a
Dr John Stockton <sp**@merlyn.demon.co.uk> writes:
The following is about 50% longer in code, but about four times faster
in my system - and it seems to be right, too.

function DateOK(Y, M, D) {
return D>0 && (D<=[,31,28,31,30,31,30,31,31,30,31,30,31][M] ||
D==29 && M==2 && Y%4==0 && (Y%100>0 || Y%400==0) ) }
I notice that you generate a new Array object for each call. You
could keep the date length array in variable and reuse it. It would
probably even be measureably faster (haven't tested though).
Note that checking for 1 <= M <= 12 is inherent, and that the Leapness
of the year is only determined if the date given is February 29th.
Or if the month is invalid. How about:

var __months = [,31,28,31,30,31,30,31,31,30,31,30,31]
function DateOK2(Y, M, D) {
var ML = __months[M];
return D>0 && ML && (D<=ML ||
D==29 && Y%4==0 && (Y%100!=0 || Y%400==0) ) }

(M==2 is unnecessary, as ML && D>ML && D==29 implies M==2, but it
might be reasonable to keep it for readability).

Ok, a quick speed test in IE shows this version to be four times
faster than the above (which was only about twice as fast as
ValidDate, when testing only on February 29ths (not really fair :)).
Comments ? Tests ??


About Feb 29ths:

The test Y%100>0 fails for Y<=0, because -96 % 100 == -96, not 4.
Change >0 to !=0 and that works.

It still fails for Y=0 for some reason. ... ah, probably because
Date maps Y=0 to year 1900, and your test doesn't. Since your
opponent is cheating, you win by default :)

/L
--
Lasse Reichstein Nielsen - lr*@hotpop.com
DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
'Faith without judgement merely degrades the spirit divine.'
Jul 23 '05 #2

P: n/a
In article <c2**************@merlyn.demon.co.uk>, Dr John Stockton
<sp**@merlyn.demon.co.uk> wrote:
It has appeared that ancient sources give a method for Numeric Date
Validation that involves numerous tests to determine month length;
versions are often posted by incomers here. That sort of code seems
unnecessarily long.

For some while, the following approach has been given here :-

function ValidDate(y, m, d) { // m = 0..11 ; y m d integers, y!=0
with (new Date(y, m, d))
return (getMonth()==m && getDate()==d) }

and it may remain the shortest code. But it does require, in every
case, the creation and disposal of a Date Object.

The following is about 50% longer in code, but about four times faster
in my system - and it seems to be right, too.

function DateOK(Y, M, D) {
return D>0 && (D<=[,31,28,31,30,31,30,31,31,30,31,30,31][M] ||
D==29 && M==2 && Y%4==0 && (Y%100>0 || Y%400==0) ) }

Note that checking for 1 <= M <= 12 is inherent, and that the Leapness
of the year is only determined if the date given is February 29th.

Also, it is easy to use only the quadrennial rule if it is certain that
dates are in 1901-2099, or only two rules for 2001-2399.

Comments ? Tests ??


Is the following correct for just a leap year check?

ayear is a 4 digit year.

var isLeapYear = ayear%4 == 0 && ayear%100 > 0 || ayear%400 == 0;

I always get confused on the sequence of evaluation (first && and then
|| unless parenthesis are used).

--
Dennis M. Marks
http://www.dcs-chico.com/~denmarks/
Replace domain.invalid with dcsi.net
-----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
-----== Over 100,000 Newsgroups - 19 Different Servers! =-----
Jul 23 '05 #3

P: n/a
Lasse Reichstein Nielsen wrote on 19 apr 2004 in comp.lang.javascript:
Or if the month is invalid. How about:

var __months = [,31,28,31,30,31,30,31,31,30,31,30,31]
function DateOK2(Y, M, D) {
var ML = __months[M];
return D>0 && ML && (D<=ML ||
D==29 && Y%4==0 && (Y%100!=0 || Y%400==0) ) }

(M==2 is unnecessary, as ML && D>ML && D==29 implies M==2, but it
might be reasonable to keep it for readability).

Ok, a quick speed test in IE shows this version to be four times
faster than the above (which was only about twice as fast as
ValidDate, when testing only on February 29ths (not really fair :)).


Why this quest for speed?
Do you all want to test an enormous database for false entries?
Usually this test is for human interface validation only, I think,
so speed is not that important.

Personally, I would let the system do the thinking for me:

function dateOK(Y,M,D){
var da = new Date(Y,M-1,D)
return Y == da.getFullYear() &&
M-1 == da.getMonth() &&
D == da.getDate()
}

This also checkes for decimals, strings, negatives, etc.
correctly validating strings are allowed, like year '02004',month '3.00'
returns false if year<100

--
Evertjan.
The Netherlands.
(Please change the x'es to dots in my emailaddress)
Jul 23 '05 #4

P: n/a
Fox


Lasse Reichstein Nielsen wrote:

Dr John Stockton <sp**@merlyn.demon.co.uk> writes:
The following is about 50% longer in code, but about four times faster
in my system - and it seems to be right, too.

function DateOK(Y, M, D) {
return D>0 && (D<=[,31,28,31,30,31,30,31,31,30,31,30,31][M] ||
D==29 && M==2 && Y%4==0 && (Y%100>0 || Y%400==0) ) }
I notice that you generate a new Array object for each call. You
could keep the date length array in variable and reuse it. It would
probably even be measureably faster (haven't tested though).
Note that checking for 1 <= M <= 12 is inherent, and that the Leapness
of the year is only determined if the date given is February 29th.


Or if the month is invalid. How about:

var __months = [,31,28,31,30,31,30,31,31,30,31,30,31]
function DateOK2(Y, M, D) {
var ML = __months[M];
return D>0 && ML && (D<=ML ||
D==29 && Y%4==0 && (Y%100!=0 || Y%400==0) ) }

(M==2 is unnecessary, as ML && D>ML && D==29 implies M==2, but it
might be reasonable to keep it for readability).

Ok, a quick speed test in IE shows this version to be four times
faster than the above (which was only about twice as fast as
ValidDate, when testing only on February 29ths (not really fair :)).
Comments ? Tests ??


About Feb 29ths:

The test Y%100>0 fails for Y<=0, because -96 % 100 == -96, not 4.
Change >0 to !=0 and that works.


Y should not be negative unless BCE dates, in which case you would add
4712, then perform the leapyear test (but only y % 4 == 0 -- this is why
the Julian calendar got so out of whack over the centuries)

It still fails for Y=0 for some reason. ... ah, probably because
Date maps Y=0 to year 1900, and your test doesn't. Since your
opponent is cheating, you win by default :)
The new Date object is only valid for the Gregorian calendar: Oct 15,
1582 and forward in time. The "full" year should always be used in the
new Date model. The year 0 is "mapped" to 1900 for "backward
compatibility" when the date object would accept 1 or 2 digit years
(pre-y2k). It really doesn't matter that Date supports 2-digit years
since the Gregorian calendar support in Date does not include (accurate
or correct) dates prior to Oct 15, 1582.

BTW -- there is *no* year 0 -- the calendar goes from 1 CE to 1 BCE
(going backwards). Year = 0 should be considered invalid (I don't
believe there is even a Day 0 in the Julian calendar -- Day 1 was Jan 1
4713 BCE [plus the Romans did not have a zero digit]).


/L
--
Lasse Reichstein Nielsen - lr*@hotpop.com
DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
'Faith without judgement merely degrades the spirit divine.'

Jul 23 '05 #5

P: n/a
On Sun, 18 Apr 2004 15:56:39 -0700, Dennis M. Marks
<de******@domain.invalid> wrote:

[snip]
Is the following correct for just a leap year check?
Not quite. You are correct that && is before ||, but that makes your
expression incorrect: || needs to be evaluated before && in this case.
Here's how the expression would be evaluated:

((( ayear % 4 ) == 0 ) && (( ayear % 100 ) > 0 )) || (( ayear % 400 ) ==
0 )

simplified to

( !( ayear % 4 ) && ( ayear % 100 )) || !( ayear % 400 )

Notice the difference between the one above, and mine (and Dr Stockton's)
below.
ayear is a 4 digit year.

var isLeapYear = ayear%4 == 0 && ayear%100 > 0 || ayear%400 == 0;

I always get confused on the sequence of evaluation (first && and then
|| unless parenthesis are used).


That's why I only remember one fact about any operator precedence table:
that parentheses are first. I'd write the line above:

var isLeapYear = ( !( ayear % 4 ) && (( ayear % 100 ) || !( ayear % 400
)));

It avoids any ambiguity, unless you can't read through all the parentheses.

Mike

--
Michael Winter
M.******@blueyonder.co.invalid (replace ".invalid" with ".uk" to reply)
Jul 23 '05 #6

P: n/a
Fox


Dr John Stockton wrote:

It has appeared that ancient sources give a method for Numeric Date
Validation that involves numerous tests to determine month length;
versions are often posted by incomers here. That sort of code seems
unnecessarily long.

For some while, the following approach has been given here :-

function ValidDate(y, m, d) { // m = 0..11 ; y m d integers, y!=0
with (new Date(y, m, d))
return (getMonth()==m && getDate()==d) }

and it may remain the shortest code. But it does require, in every
case, the creation and disposal of a Date Object.
That depends on your point of view and what you consider a valid date
entered by a user (and it *must* be entered by a user, otherwise *why*
would you need to validate your own code?)

The Date object has very W I D E latitude in what it considers a valid
date and it is usually *best* to let the language deal with itself.

At it's most simple, a valid date is the following:

Date.prototype.valid = function()
{
return !(this == "Invalid Date" || isNaN(this));
}

This routine handles gecko and M$ versions of the Date object and
assures that the values under test will produce a valid Date object
instance. E.g.:

(new Date("howdy")).valid() => false
As to your concern for "the shortest code" for a validation script: No
validation code for user input (in html) is ever "time-critical" - so
whatever it takes to get the job done -- anything under 1/30th of a
second is faster than most humans can perceive...and the difference
between the "old way" and your "new proposal" can be measured in
milliseconds (probably less than 50). Unless you have to process
thousands of dates...well, I seriously doubt you'd find anyone with the
patience to spend on that amount of data entry to quantify the gain in efficiency.

Your concern about "disposal" of Date objects is non sequitur. It is
automatic in JavaScript and is not something we have the possibility of
having direct access to. Simply exiting a function in which a Date is
created as a local variable will cause automatic disposal. For global
Date objects, simply reuse as few as minimally required, or set the
object to null when through with them in order to "coerce" automatic
garbage disposal. The "timing" of the disposal cannot be guaranteed.


The following is about 50% longer in code, but about four times faster
in my system - and it seems to be right, too.

function DateOK(Y, M, D) {
return D>0 && (D<=[,31,28,31,30,31,30,31,31,30,31,30,31][M] ||
D==29 && M==2 && Y%4==0 && (Y%100>0 || Y%400==0) ) }

Note that checking for 1 <= M <= 12 is inherent, and that the Leapness
of the year is only determined if the date given is February 29th.
for leapyears, the Date object will correctly return Feb 29 data --
considering the date is already valid (that is, not "Invalid Date" in
gecko or NaN in IE) for the 60th day into a leapyear, otherwise Mar 1.
If the information about leapyear is important, then 1) if all that's
needed is the year:

Number.prototype.leapyear = function()
{
return (this % 4 == 0 && this % 100 != 0) || this % 400 == 0;
}

e.g.: year.leapyear() or (2004).leapyear()

or 2) from a Date instance:

Date.prototype.isLeapYear = function()
{
return this.getFullYear().leapyear(); // so years can be tested both ways
}

// this is good from 1582 until the end of the Gregorian Calendar
As mentioned, the Date Object offers considerable latitude for valid
data entry. Why allow it? Simplicity. For instance, to retrieve the
180th day of a year:

var day180 = new Date(year, 0, 180);

var oneThirdIntoYear = new Date(year, 0, (year.leapyear() ? 366 :
365)/3); // May 1
// the Date Object automatically converts the fractional part to an
integer value

the last day of June is:

var lastofJune = new Date(year, 6, 0); // where july = 6 => returns June
30 w/day of week, etc...

[ also, by the same token:
var isLeapYear = (new Date(year, 2, 0)).getDate() == 29;
// or new Date(year, 1, 29).getMonth() == 1; ]

10000 days from 6/1/2004:

new Date(2004, 5, 1 + 10000);

These are all valid Date representations. Filtered through "ValidDate"
they are "out of range" and disqualified.

The following are also valid (in Date):

var m = null;
var d = null;
var y = 2004;

new Date(y, m, d) => Dec 31 2003

m = 11;
d = 1;
y = null;
new Date(y, m, d) => Dec 1 1900 [*see my note to Lasse about year=0]

[null values are equivalent to 0 in Date]

Also, it is easy to use only the quadrennial rule if it is certain that
dates are in 1901-2099, or only two rules for 2001-2399.
as far as I can tell, the latest versions of JS have implemented correct
Gregorian Dates (including leapyear for 1600). Dates before Oct 15, 1582
seem to be incorrect [Oct 5-14 1582 should not exist, but they do in
gecko and IE and Oct 4 1582 shows Mon -- it should be Thu]. So why
restrict the formula and remove the generality when it can be used
throughout the entire range of dates the Date object is now capable of representing?

Comments ? Tests ??

ValidDate(12004, 2, 1) is a valid date, yet still meaningless in most
contexts (barring astronomical calculations.) Validating a date entry
from a form by a user is basically an exercise in catching typos,
otherwise, an example like this defeats both our purposes - we still
need to rely on the intrisic scrupulousness of the serious user. Anyone
else "bent" on providing meaningless values can pretty much easily do so
[unless the validation is much more strict in its limits, e.g., credit
card expiration date validation -- from "this month" to about 5 years hence...]

if you use the Date object's approach to "month management" (zero-based
months) you can reduce the days array to:

var days = [31,28,31,30,31,30,31,31,30,31,30,31];


Fox
*****************
Jul 23 '05 #7

P: n/a
JRS: In article <18*************************@domain.invalid>, seen in
news:comp.lang.javascript, Dennis M. Marks <de******@domain.invalid>
posted at Sun, 18 Apr 2004 15:56:39 :

Is the following correct for just a leap year check?

ayear is a 4 digit year.

var isLeapYear = ayear%4 == 0 && ayear%100 > 0 || ayear%400 == 0;

There are only four possible types of Gregorian Year Number :
Divisible by 400 e.g. 2000
Others Divisible by 100 e.g. 2100
Others Divisible by 4 e.g. 2104
Others e.g. 2105

It would not take long for you to test all four.

It is reasonable to assume that the precedences of the operators are the
same in all current browsers; OTOH, most programmers prefer parentheses
to doubt. Function Biss, in js-date4.htm, will retain its parentheses.

--
John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v4.00 IE 4
<URL:http://jibbering.com/faq/> Jim Ley's FAQ for news:comp.lang.javascript
<URL:http://www.merlyn.demon.co.uk/js-index.htm> jscr maths, dates, sources.
<URL:http://www.merlyn.demon.co.uk/> TP/BP/Delphi/jscr/&c, FAQ items, links.
Jul 23 '05 #8

P: n/a
JRS: In article <is**********@hotpop.com>, seen in
news:comp.lang.javascript, Lasse Reichstein Nielsen <lr*@hotpop.com>
posted at Mon, 19 Apr 2004 00:40:57 :
Dr John Stockton <sp**@merlyn.demon.co.uk> writes:
The following is about 50% longer in code, but about four times faster
in my system - and it seems to be right, too.

function DateOK(Y, M, D) {
return D>0 && (D<=[,31,28,31,30,31,30,31,31,30,31,30,31][M] ||
D==29 && M==2 && Y%4==0 && (Y%100>0 || Y%400==0) ) }
I notice that you generate a new Array object for each call. You
could keep the date length array in variable and reuse it. It would
probably even be measureably faster (haven't tested though).


It trebles the speed for Feb 29, and quadruples it for commoner valid
days. But it is more tiresome to display in my js-date4.htm.

Note that checking for 1 <= M <= 12 is inherent, and that the Leapness
of the year is only determined if the date given is February 29th.


Or if the month is invalid. How about:

var __months = [,31,28,31,30,31,30,31,31,30,31,30,31]
function DateOK2(Y, M, D) {
var ML = __months[M];
return D>0 && ML && (D<=ML ||
D==29 && Y%4==0 && (Y%100!=0 || Y%400==0) ) }


ISTM that, for almost all purposes, failure of validation should be a
rare event and means that a slow process, such as re-entering the data,
will be needed; therefore the speed of failure, unless unreasonable, is
only of minor importance. But the change is easy.

(M==2 is unnecessary, as ML && D>ML && D==29 implies M==2, but it
might be reasonable to keep it for readability).
Good.

Ok, a quick speed test in IE shows this version to be four times
faster than the above (which was only about twice as fast as
ValidDate, when testing only on February 29ths (not really fair :)).
Comments ? Tests ??


About Feb 29ths:

The test Y%100>0 fails for Y<=0, because -96 % 100 == -96, not 4.
Change >0 to !=0 and that works.

It still fails for Y=0 for some reason. ... ah, probably because
Date maps Y=0 to year 1900, and your test doesn't. Since your
opponent is cheating, you win by default :)


Somewhere on my WWW site it says that, if the year may be small, then
D = new Date(0) ; D.setFullYear(Y, M, D)
is better than
D = new Date(Y, M, D)
also that new Date(0) is faster and safer than new Date() unless "now"
is needed.

Actually, Year 0 was not a leap year, and neither was Year 4, so it is
Year 4 that is wrong - the actual calendar, from -44 to +4, was the
Miscalculated Julian Calendar.
Unfortunately, it is now so fast that in order to compare its speed with
ValidDate directly in a reasonable time, the loop-counts must be varied.

I must think about a library function that uses setTimeout to time a
named routine for a given time ...
Another thought : if a Date Object is needed anyway, is checking as
above then creating better than creating and then checking it? If a
Date Object stores only ms-from-1970, then getMonth & getDate must
repeat work; but a smart Date Object could cache Y M D h m s ... In my
MSIE4,
DateOK(Y, M, D) ; X = new Date()
is twice as fast as
ValidDate(Y, M-1, D)

--
John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v4.00 IE 4
<URL:http://jibbering.com/faq/> Jim Ley's FAQ for news:comp.lang.javascript
<URL:http://www.merlyn.demon.co.uk/js-index.htm> jscr maths, dates, sources.
<URL:http://www.merlyn.demon.co.uk/> TP/BP/Delphi/jscr/&c, FAQ items, links.
Jul 23 '05 #9

P: n/a
In article <40***************@fxmahoney.com>, Fox <fo*@fxmahoney.com>
writes

<snip>
The new Date object is only valid for the Gregorian calendar:
Date objects *implement* the Gregorian calendar.
Oct 15,
1582 and forward in time.
Are you saying the Pope's technical advisors weren't allowed to
calculate Gregorian dates before the Pope signed his proclamation making
them compulsory ? Rhubarb.

<snip>BTW -- there is *no* year 0 -- the calendar goes from 1 CE to 1 BCE
It's a matter of which representation of numbers you find it convenient
to display. For doing arithmetic modern binary numbers are more
convenient.

<snip>4713 BCE [plus the Romans did not have a zero digit]).


Back then no-one knew there was going to be a C to be B, so how can you
use BC numbers ?

Also, shouldn't you be writing MMMMDCCXIII (approx.).

John
--
John Harris
Jul 23 '05 #10

P: n/a
JRS: In article <Xn********************@194.109.133.29>, seen in
news:comp.lang.javascript, Evertjan. <ex**************@interxnl.net>
posted at Mon, 19 Apr 2004 08:14:28 :

Why this quest for speed?
Do you all want to test an enormous database for false entries?
Usually this test is for human interface validation only, I think,
so speed is not that important.
Seeking efficiency is educational; the training means that one is likely
to achieve greater efficiency when it really matters.

Personally, I would let the system do the thinking for me:

function dateOK(Y,M,D){
var da = new Date(Y,M-1,D)
return Y == da.getFullYear() &&
M-1 == da.getMonth() &&
D == da.getDate()
}
AFAICS, only two of those equality tests are needed.

This also checkes for decimals, strings, negatives, etc.
correctly validating strings are allowed, like year '02004',month '3.00'
returns false if year<100


History did not start in the Year 100.

--
John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v4.00 MIME.
Web <URL:http://www.merlyn.demon.co.uk/> - w. FAQish topics, links, acronyms
PAS EXE etc : <URL:http://www.merlyn.demon.co.uk/programs/> - see 00index.htm
Dates - miscdate.htm moredate.htm js-dates.htm pas-time.htm critdate.htm etc.
Jul 23 '05 #11

P: n/a
JRS: In article <40***************@fxmahoney.com>, seen in
news:comp.lang.javascript, Fox <fo*@fxmahoney.com> posted at Mon, 19 Apr
2004 04:03:46 :
Y should not be negative unless BCE dates, in which case you would add
4712, then perform the leapyear test (but only y % 4 == 0 -- this is why
the Julian calendar got so out of whack over the centuries)
No reason to act as if the Julian Calendar was abandoned in or about the
Year 0.

The new Date object is only valid for the Gregorian calendar: Oct 15,
1582 and forward in time. The "full" year should always be used in the
new Date model. The year 0 is "mapped" to 1900 for "backward
compatibility" when the date object would accept 1 or 2 digit years
(pre-y2k). It really doesn't matter that Date supports 2-digit years
since the Gregorian calendar support in Date does not include (accurate
or correct) dates prior to Oct 15, 1582.
No, it covers about +-275000 years from 1970. Before 1582-10-15 (or
possibly 1752-09-14, and much later in Russia) the Gregorian Calendar is
described as proleptic. One only needs to remember that civil dates
have not always been Gregorian.

BTW -- there is *no* year 0 -- the calendar goes from 1 CE to 1 BCE
(going backwards). Year = 0 should be considered invalid (I don't
believe there is even a Day 0 in the Julian calendar -- Day 1 was Jan 1
4713 BCE [plus the Romans did not have a zero digit]).


There is a year 0, between years -1 and +1. A calendar with such years
is called astronomical. Javascript uses it where years are type Number,
but not where they are parts of a full date string.

Neither the Julian nor the Gregorian Calendar has a Day 0; they only
have day counts starting at 1 for each month.

BC 4713-01-01 is the start of the Julian Day/Date [Number] count; but
the start of its Day 1 is noon GMT. Note that it is named for an
entirely different Julian - Scaliger's dad, not the Emperor. See
<URL:http://www.merlyn.demon.co.uk/moredate.htm#Jul>, "Which Julian?".

The term Chronological JD can be used for a count starting at the local
midnight which began that solar day.
The Javascript Date Object implements the Astronomical Proleptic
Calendar over a range of exactly +-10^8 days centred on 1970-01-01
00:00:00 GMT - as ECMA-262 requires.

--
John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v4.00 MIME.
Web <URL:http://www.merlyn.demon.co.uk/> - w. FAQish topics, links, acronyms
PAS EXE etc : <URL:http://www.merlyn.demon.co.uk/programs/> - see 00index.htm
Dates - miscdate.htm moredate.htm js-dates.htm pas-time.htm critdate.htm etc.
Jul 23 '05 #12

P: n/a
JRS: In article <op**************@news-text.blueyonder.co.uk>, seen in
news:comp.lang.javascript, Michael Winter <M.******@blueyonder.co.invali
d> posted at Mon, 19 Apr 2004 11:41:09 :
Not quite. You are correct that && is before ||, but that makes your
expression incorrect: || needs to be evaluated before && in this case.
Here's how the expression would be evaluated:

((( ayear % 4 ) == 0 ) && (( ayear % 100 ) > 0 )) || (( ayear % 400 ) ==
0 )

simplified to

( !( ayear % 4 ) && ( ayear % 100 )) || !( ayear % 400 )

Notice the difference between the one above, and mine (and Dr Stockton's)
below.

One needs to test.

I believe that the numbers should appear in the order 4 100 400, to make
the best use of short-circuit evaluation possible.

But the three "%" results are not independent; there are only four types
of year number , not eight. Thus there is not necessarily a unique
combination of order-of-operation required for the right result.

Your preference may be - doubtless is - right; but that does not mean
that all other preferences give the wrong answer.

--
John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v4.00 IE 4
<URL:http://jibbering.com/faq/> Jim Ley's FAQ for news:comp.lang.javascript
<URL:http://www.merlyn.demon.co.uk/js-index.htm> jscr maths, dates, sources.
<URL:http://www.merlyn.demon.co.uk/> TP/BP/Delphi/jscr/&c, FAQ items, links.
Jul 23 '05 #13

P: n/a
Dr John Stockton wrote on 19 apr 2004 in comp.lang.javascript:
function dateOK(Y,M,D){
var da = new Date(Y,M-1,D)
return Y == da.getFullYear() &&
M-1 == da.getMonth() &&
D == da.getDate()
}


AFAICS, only two of those equality tests are needed.


That would not be very educational.
This also checkes for decimals, strings, negatives, etc.
correctly validating strings are allowed, like year '02004',month
'3.00' returns false if year<100


History did not start in the Year 100.


Why confine onself merely to history, what about prehistoric dates ?

==============

These sub 100 year inputs can be expanded
to the "nearest" 4 digit year numbers

[again intentionally educationally non optimized]:

if (Y>=0 && Y<35) Y += 2000
if (Y>=35 && Y<100) Y += 1900
--
Evertjan.
The Netherlands.
(Please change the x'es to dots in my emailaddress)
Jul 23 '05 #14

P: n/a
On Mon, 19 Apr 2004 21:55:17 +0100, Dr John Stockton
<sp**@merlyn.demon.co.uk> wrote:
JRS: In article <op**************@news-text.blueyonder.co.uk>, seen in
news:comp.lang.javascript, Michael Winter
<M.******@blueyonder.co.invalid> posted at Mon, 19 Apr 2004 11:41:09 :
Not quite. You are correct that && is before ||, but that makes your
expression incorrect: || needs to be evaluated before && in this case.
Here's how the expression would be evaluated:

((( ayear % 4 ) == 0 ) && (( ayear % 100 ) > 0 )) || (( ayear % 400 )
==
0 )

simplified to

( !( ayear % 4 ) && ( ayear % 100 )) || !( ayear % 400 )

Notice the difference between the one above, and mine (and Dr
Stockton's) below.
One needs to test.


Probably. :)
I believe that the numbers should appear in the order 4 100 400, to make
the best use of short-circuit evaluation possible.

But the three "%" results are not independent; there are only four types
of year number , not eight. Thus there is not necessarily a unique
combination of order-of-operation required for the right result.

Your preference may be - doubtless is - right; but that does not mean
that all other preferences give the wrong answer.


When I first wrote my response, I was comparing the order of evaluation to
the form you presented (which is the same form I remember seeing from
other sources). It was a blind comparison. I did think later that the
order might not be quite so important.

This sort of thing occurs more often than I'd like, but as I hadn't
reached a conclusion, I hadn't sought to make another post.

A simple test, taking years from 0 to 10000[1], shows no difference in
result. However, there is a *very* slight difference in execution time,
which makes mine faster (even when forcing the result to boolean using
!!(expr)).

Mike
[1] I realise that a reasoned choice would be more desirable, but it
should suffice.

--
Michael Winter
M.******@blueyonder.co.invalid (replace ".invalid" with ".uk" to reply)
Jul 23 '05 #15

P: n/a
Hold on a sec. First of all, your expression (Method 1)
( !( ayear % 4 ) && ( ayear % 100 )) || !( ayear % 400 )


is saying a year is a leap year iff
((it's divisible by 4) AND (it's not divisible by 100)) OR
(it's divisible by 400).

But that's the same as (Method 2):
a year is a leap year iff
(it's divisible by 4) AND ((it's not divisible by 100) OR
(it's divisible by 400))

In other words, from a logical point of view, you don't
NEED the grouping parentheses. But they DO make
a difference (theoretically, anyway. YOU can do the testing).
Let's just check out how many times each condition gets
executed.

Method 1:
Year not divisible by 4: first and last expressions
Year divisible by 4/ not by 100: first two
Year divisible by 400: all three

Method 2:
Year not divisible by 4: first one only
Year divisible by 4/ not by 100: first two
Year divisible by 400: all three

So in 75% of all cases, Method 2 will have only one test
to two for Method 1.

But wait, there's more. Since you've come to the right
newsgroup, tonight only, we'll throw in a special simplification,
to get rid of not one, but two of those pesky modulo operators.
Who needs extra divisions, after all? So here you have it -
Method 2, simplified:

isLeapYear = !( ayear & 3 ) && (( ayear % 25 != 0 ) || !( ayear & 15 ))
From Bit Tiddle City,
Csaba Gabor

PS. If you leave out the != 0 part in the second condition, your result
in the case of leap years not divisible by 400 will be numeric (nonzero -
the result of ayear % 25) instead of boolean true, which would be OK
for most of my purposes.
Jul 23 '05 #16

P: n/a
On Tue, 20 Apr 2004 03:53:04 +0200, Csaba Gabor <ne**@CsabaGabor.com>
wrote:
Hold on a sec. First of all, your expression (Method 1)
Actually, my expression was method 2. The first two expressions I stated
were representations of Dennis' test once operator precedence was applied.
My proposed expression was the last in my first post.
( !( ayear % 4 ) && ( ayear % 100 )) || !( ayear % 400 )


is saying a year is a leap year iff
((it's divisible by 4) AND (it's not divisible by 100)) OR
(it's divisible by 400).

But that's the same as (Method 2):
a year is a leap year iff
(it's divisible by 4) AND ((it's not divisible by 100) OR
(it's divisible by 400))

In other words, from a logical point of view, you don't
NEED the grouping parentheses. But they DO make
a difference (theoretically, anyway. YOU can do the testing).
Let's just check out how many times each condition gets
executed.

Method 1:
Year not divisible by 4: first and last expressions
Year divisible by 4/ not by 100: first two
Year divisible by 400: all three

Method 2:
Year not divisible by 4: first one only
Year divisible by 4/ not by 100: first two
Year divisible by 400: all three

So in 75% of all cases, Method 2 will have only one test
to two for Method 1.


I hadn't thought about it before (I was just rattling off code without
much thought, as I said earlier), but during testing I noticed that not
all results were boolean. When I examined the expression, I came to your
same conclusion.
But wait, there's more. Since you've come to the right
newsgroup, tonight only, we'll throw in a special simplification,
to get rid of not one, but two of those pesky modulo operators.
Who needs extra divisions, after all? So here you have it -
Method 2, simplified:

isLeapYear = !( ayear & 3 ) && (( ayear % 25 != 0 ) || !( ayear & 15 ))


I realised that Dr Stockton was indicating more than what I responded to,
but I was too tired to consider what. My (still) tired brain thanks you. :)

The first bitwise operation was obvious in its effect (a common enough
optimisation), but I couldn't think why the third was using 15. I then
noticed you changed the second to 25. A prime example of why I normally
avoid thinking too hard in the morning.

Mike
[1] I didn't expect && to operate the same way as || for non-boolean
types. Not having used it in that manner before, whereas I often use ||
for setting default values, I don't suppose there was much reason to.

--
Michael Winter
M.******@blueyonder.co.invalid (replace ".invalid" with ".uk" to reply)
Jul 23 '05 #17

P: n/a
JRS: In article <Xn*******************@194.109.133.29>, seen in
news:comp.lang.javascript, Evertjan. <ex**************@interxnl.net>
posted at Mon, 19 Apr 2004 22:43:50 :
Why confine onself merely to history, what about prehistoric dates ?
Javascript will handle back past BC 270000, using proleptic Gregorian;
my site has the essentials for Julian. "Actual" calendars other than
those are either too troublesome or not interesting enough, though I
have some Hebrew calendar stuff in Pascal.

These sub 100 year inputs can be expanded
to the "nearest" 4 digit year numbers

[again intentionally educationally non optimized]:

if (Y>=0 && Y<35) Y += 2000
if (Y>=35 && Y<100) Y += 1900

But some people will actually want to refer to years before AD 100.

--
John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v4.00 MIME.
Web <URL:http://www.merlyn.demon.co.uk/> - w. FAQish topics, links, acronyms
PAS EXE etc : <URL:http://www.merlyn.demon.co.uk/programs/> - see 00index.htm
Dates - miscdate.htm moredate.htm js-dates.htm pas-time.htm critdate.htm etc.
Jul 23 '05 #18

P: n/a
JRS: In article <op**************@news-text.blueyonder.co.uk>, seen in
news:comp.lang.javascript, Michael Winter <M.******@blueyonder.co.invali
d> posted at Mon, 19 Apr 2004 23:12:30 :
A simple test, taking years from 0 to 10000[1], shows no difference in
result. However, there is a *very* slight difference in execution time,
which makes mine faster (even when forcing the result to boolean using
!!(expr)). [1] I realise that a reasoned choice would be more desirable, but it
should suffice.


Since the Calendar repeats every 400 years, 1 to 10000 would be better,
but only in principle.

--
John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v4.00 MIME.
Web <URL:http://www.merlyn.demon.co.uk/> - w. FAQish topics, links, acronyms
PAS EXE etc : <URL:http://www.merlyn.demon.co.uk/programs/> - see 00index.htm
Dates - miscdate.htm moredate.htm js-dates.htm pas-time.htm critdate.htm etc.
Jul 23 '05 #19

P: n/a
JRS: In article <40******@andromeda.datanet.hu>, seen in
news:comp.lang.javascript, Csaba Gabor <ne**@CsabaGabor.com> posted at
Tue, 20 Apr 2004 03:53:04 :
isLeapYear = !( ayear & 3 ) && (( ayear % 25 != 0 ) || !( ayear & 15 ))
!( ayear & 3 || !( ayear & 15 ) && ayear % 25 )

omits the != 0 but still gives a Boolean result in every case; it has
the same number of other operations.
Now tested in <URL:http://www.merlyn.demon.co.uk/js-date4.htm#MaYL>, but
not timed.
From Bit Tiddle City,


Tiddle != Twiddle

--
John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v4.00 IE 4
<URL:http://jibbering.com/faq/> Jim Ley's FAQ for news:comp.lang.javascript
<URL:http://www.merlyn.demon.co.uk/js-index.htm> jscr maths, dates, sources.
<URL:http://www.merlyn.demon.co.uk/> TP/BP/Delphi/jscr/&c, FAQ items, links.
Jul 23 '05 #20

P: n/a
Evertjan. wrote:

function dateOK(Y,M,D){
var da = new Date(Y,M-1,D)
return Y == da.getFullYear() &&
M-1 == da.getMonth() &&
D == da.getDate()
}
It would validate "dateOK(2000,2000,2000)", would it not?
Mick

This also checkes for decimals, strings, negatives, etc.
correctly validating strings are allowed, like year '02004',month '3.00'
returns false if year<100

Jul 23 '05 #21

P: n/a
Mick White <mw******@rochester.rr.com> writes:
Evertjan. wrote:
function dateOK(Y,M,D){
var da = new Date(Y,M-1,D)
return Y == da.getFullYear() &&
M-1 == da.getMonth() &&
D == da.getDate()
}


It would validate "dateOK(2000,2000,2000)", would it not?


Try (and see that it doesn't).

/L
--
Lasse Reichstein Nielsen - lr*@hotpop.com
DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
'Faith without judgement merely degrades the spirit divine.'
Jul 23 '05 #22

P: n/a
Lasse Reichstein Nielsen wrote:
<snip>> var __months = [,31,28,31,30,31,30,31,31,30,31,30,31]
function DateOK2(Y, M, D) {
var ML = __months[M];
return D>0 && ML && (D<=ML ||
D==29 && Y%4==0 && (Y%100!=0 || Y%400==0) ) }

<snip>

The comparison operation on - ML - reminded me that a - <= - comparison
of an object with a number will call the object's - valueOf - method,
and so the possibility of putting an object with an overridden -
valueOf - method into index 2 of the months length array and have that
method return 28 or 29 based on the year:-

var DateOK3 = (function(){
var _y;
var __months = [
NaN,31,
{valueOf:function(){
return (((_y&3)||((_y&15)&&(!(_y%25))))?28:29);
}},
31,30,31,30,31,31,30,31,30,31
];
return (function(Y, M, D){
_y = Y;
return (D > 0) && (D <= __months[M]);
});
})();

Which takes advantage of undefined values from - __months[M] - type
converting to NaN for the comparison and so returns false from - (D <=
__months[M]) - when - M - is out of the appropriate range and has the
merit of always returning a boolean value.

Richard.
Jul 23 '05 #23

P: n/a
> >isLeapYear = !( ayear & 3 ) && (( ayear % 25 != 0 ) || !( ayear & 15 ))

!( ayear & 3 || !( ayear & 15 ) && ayear % 25 )


Hmmm, that's very interesting. My first inclination was to say that
swapping those last two arguments was going to lead the last one being
evaluated (almost) all the time (since it's checking for divisibility by
400,
only true 1/400 of the time) but that's not correct since the 25 is doing
much of the work. That being the case, the situation becomes murkier
and depends much more on the efficiency of the various operations.
In particular, the last operation (the presumed expensive Mod 25)
is only going to be done 1/16th of the time as opposed to the 1/4 on
the top line. Now I'm real curious as to which wins out on time, if either.

Thanks for that post,

Csaba,
a bit toddler
Jul 23 '05 #24

P: n/a
JRS: In article <40******@andromeda.datanet.hu>, seen in
news:comp.lang.javascript, Csaba Gabor <ne**@CsabaGabor.com>
posted at Wed, 21 Apr 2004 04:00:36 :
>isLeapYear = !( ayear & 3 ) && (( ayear % 25 != 0 ) || !( ayear & 15 ))


!( ayear & 3 || !( ayear & 15 ) && ayear % 25 )


Hmmm, that's very interesting. My first inclination was to say that
swapping those last two arguments was going to lead the last one being
evaluated (almost) all the time (since it's checking for divisibility by
400,
only true 1/400 of the time) but that's not correct since the 25 is doing
much of the work. That being the case, the situation becomes murkier
and depends much more on the efficiency of the various operations.
In particular, the last operation (the presumed expensive Mod 25)
is only going to be done 1/16th of the time as opposed to the 1/4 on
the top line. Now I'm real curious as to which wins out on time, if either.

The tests will be performed on order (assumption). The most effective
tests are those where the two possible results are most nearly equally
probable (general rule). 4 < 16 < 25.
PII/300, MSIE4 :-
1000 // ; var D0, D1, D2, J, isLeapYear, ayear

D0 = new Date()
for (J=0 ; J<K ; J++) for (ayear=2000 ; ayear<2400 ; ayear++)
isLeapYear = !( ayear & 3 ) && (( ayear % 25 != 0 ) || !( ayear & 15 ))
D1 = new Date()
for (J=0 ; J<K ; J++) for (ayear=2000 ; ayear<2400 ; ayear++)
isLeapYear = !( ayear & 3 || !( ayear & 15 ) && ayear % 25 )
D2 = new Date()
for (J=0 ; J<K ; J++) for (ayear=2000 ; ayear<2400 ; ayear++)
isLeapYear = !( ayear & 3 )
D3 = new Date()

X = [D1-D0, D2-D1, D3-D2]
Executing in <URL:http://www.merlyn.demon.co.uk/js-quick.htm>, typical
results are 3680,3620,3240 3740,3620,3190. About half of the time is
taken by loop overhead; the difference is a few percent, with mine being
faster.

Unveiling the var makes things faster.

The RmEv button, used above, gives much shorter times that the Eval
button - so thanks to Richard, who can possibly explain why!

....

<URL:http://www.merlyn.demon.co.uk/js-date4.htm#MaYL> now includes speed
testing (LeapSloth). It was designed on a system with time resolution
about 55 ms x 300 MHz CPU cycles; those with relatively faster CPUs may
need, and should be willing, to increase the year range tested by a
multiple of 400. Routines not using Objects are *much* quicker.

--
John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v4.00 IE 4
<URL:http://jibbering.com/faq/> Jim Ley's FAQ for news:comp.lang.javascript
<URL:http://www.merlyn.demon.co.uk/js-index.htm> jscr maths, dates, sources.
<URL:http://www.merlyn.demon.co.uk/> TP/BP/Delphi/jscr/&c, FAQ items, links.
Jul 23 '05 #25

P: n/a
Dr John Stockton wrote:
<snip>
The RmEv button, used above, gives much shorter times that the Eval
button - so thanks to Richard, who can possibly explain why!

<snip>

As I recall the point of the - remoteEval - was to avoid evaling the
expression in a scope derived from the event handling function's
execution context because the event handling function is provided with a
custom scope chain that may modify the interpretation of identifiers
used in the code that is evaled. It is probably this custom scope chain
that is influencing the execution speed of the code in the two contexts.

The execution context of the - remoteEval - function will only include
its Activation/Variable object and the global object, so any identifier
resolution will only involve the examination of these two objects.

IE adds the - document -, the form element and the - this - object to
the scope chain of its event handlers (Mozilla adds more objects), so
the resolution of an identifier that refers to a global variable will
necessitate a search of all of these objects (in addition to the
Activation/Variable object from the event handler's execution context
and the global object). The speed of resolution of local variables will
depend on whether the added objects are above the event handler's
Activation/Variable object in the scope chain (as would be the case if
they had been added using the - with - statement) or whether they are
below it.

On the other hand each test seems to be doing about as much identifier
resolution (except the last) so the relative speed results are still
meaningful in either test.

Richard.
Jul 23 '05 #26

P: n/a
JRS: In article <c6*******************@news.demon.co.uk>, seen in
news:comp.lang.javascript, Richard Cornford
<Ri*****@litotes.demon.co.uk> posted at Tue, 20 Apr 2004 23:17:04 :
Lasse Reichstein Nielsen wrote:
<snip>> var __months = [,31,28,31,30,31,30,31,31,30,31,30,31]
function DateOK2(Y, M, D) {
var ML = __months[M];
return D>0 && ML && (D<=ML ||
D==29 && Y%4==0 && (Y%100!=0 || Y%400==0) ) }

To avoid getting a result which is neither true nor false (but is
equivalent to false), I put !! before ML.
<snip>

The comparison operation on - ML - reminded me that a - <= - comparison
of an object with a number will call the object's - valueOf - method,
and so the possibility of putting an object with an overridden -
valueOf - method into index 2 of the months length array and have that
method return 28 or 29 based on the year:-

var DateOK3 = (function(){
var _y;
var __months = [
NaN,31,
{valueOf:function(){
return (((_y&3)||((_y&15)&&(!(_y%25))))?28:29);
}},
31,30,31,30,31,31,30,31,30,31
];
return (function(Y, M, D){
_y = Y;
return (D > 0) && (D <= __months[M]);
});
})();

Which takes advantage of undefined values from - __months[M] - type
converting to NaN for the comparison and so returns false from - (D <=
__months[M]) - when - M - is out of the appropriate range and has the
merit of always returning a boolean value.


Remarkable code. But it appears to work (though seems, tested with
2002-02-29, *marginally* slower than the best of the others). It's
testable in <URL:http://www.merlyn.demon.co.uk/js-dates4.htm#DVal>.

Alas, unless I wrap the above in a "normal" function, it's not amenable
to my usual code display technique.
Thanks for your RmEv explanation.

--
John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v4.00 IE 4
<URL:http://jibbering.com/faq/> Jim Ley's FAQ for news:comp.lang.javascript
<URL:http://www.merlyn.demon.co.uk/js-index.htm> jscr maths, dates, sources.
<URL:http://www.merlyn.demon.co.uk/> TP/BP/Delphi/jscr/&c, FAQ items, links.
Jul 23 '05 #27

P: n/a
"Dr John Stockton" wrote:
Richard Cornford posted:
Lasse Reichstein Nielsen wrote:
<snip>> var __months = [,31,28,31,30,31,30,31,31,30,31,30,31]
function DateOK2(Y, M, D) {
var ML = __months[M];
return D>0 && ML && (D<=ML ||
D==29 && Y%4==0 && (Y%100!=0 || Y%400==0) ) }

To avoid getting a result which is neither true nor false (but is
equivalent to false), I put !! before ML.
The comparison operation on - ML - reminded me that a - <= -
comparison of an object with a number will call the object's
- valueOf - method, and so the possibility of putting an object
with an overridden - valueOf - method into index 2 of the months
length array and have that method return 28 or 29 based on the
year:-
var DateOK3 = (function(){
var _y;
var __months = [
NaN,31,
{valueOf:function(){
return (((_y&3)||((_y&15)&&(!(_y%25))))?28:29);
}},
31,30,31,30,31,31,30,31,30,31
];
return (function(Y, M, D){
_y = Y;
return (D > 0) && (D <= __months[M]);
});
})();

Which takes advantage of undefined values from - __months[M] - type
converting to NaN for the comparison and so returns false from -
(D <= __months[M]) - when - M - is out of the appropriate range
and has the merit of always returning a boolean value.


Remarkable code. But it appears to work (though seems, tested with
2002-02-29, *marginally* slower than the best of the others). It's
testable in <URL:http://www.merlyn.demon.co.uk/js-dates4.htm#DVal>.


Yes, my speed tests give Lasse's the edge (4% or so, with a range of
dates some of which are invalid).

On the other hand, I was looking a Lasse's logic and I think it can be
faster still:-

return (D <= __months[M])? (D > 0) :
(D==29) && (M==2) && !( ((Y&3)||((Y&15)&&(!(Y%25)))) );

As out of range - M - values return undefined from - __months[M] -,
which type-convert to NaN for the comparison, only in range - M - values
can produce true results from - (D <= __months[M]) - so the - (D > 0) -
test can be moved so that it only applies when the comparison returns
true.

The only condition where a false value for - (D <= __months[M]) - will
eventually leave the function returning true is when D == 29, M ==2 and
the year makes February 29 days long. If - D - was less than zero is
would not equal 29. There is also no longer any need to test the value
returned from - __months[M] - separately by type converting it as it
would only type-convert to true if - M == 2 -, removing the need for the
ML local variable and the assignment operation..

Finally, using the expression that I used to positively select day
lengths of 28 for February, and applying the NOT operator allows that
final expression to return a boolean value even though two of its
intermediate values are numeric.

I make it 6-10% faster than Lasse's original (with !!ML). The version I
was using for testing was:-

var DateOK2b = (function(){
var __months = [NaN,31,28,31,30,31,30,31,31,30,31,30,31]
return (function(Y, M, D){
return (D <= __months[M])? (D > 0) :
(D==29) &&
(M==2) &&
!( ((Y&3)||((Y&15)&&(!(Y%25)))) );
});
})();
Alas, unless I wrap the above in a "normal" function, it's not
amenable to my usual code display technique.

<snip>

It isn't strictly necessary that the __months array be held in a
closure. I like the idea of bundling the two together and keeping
__months free from external influences. It might also be slightly faster
to resolve the identifier - __months - in the closure as the global
object has many more properties to be considered. But that isn't going
to help when it comes to displaying the string value of the resulting
(inner) function object.

Richard.
Jul 23 '05 #28

P: n/a
JRS: In article <c6**********@hercules.btinternet.com>, seen in
news:comp.lang.javascript, Richard Cornford <ri*****@litotes.demon.co.uk>
posted at Sat, 24 Apr 2004 13:36:28 :

I make it 6-10% faster than Lasse's original (with !!ML). The version I
was using for testing was:-

var DateOK2b = (function(){
var __months = [NaN,31,28,31,30,31,30,31,31,30,31,30,31]
return (function(Y, M, D){
return (D <= __months[M])? (D > 0) :
(D==29) &&
(M==2) &&
!( ((Y&3)||((Y&15)&&(!(Y%25)))) );
});
})();


OK. But && M==2 seems superfluous. Should NaN (instead of blank) be
faster?

It's not obvious how best to speed-test - one should cover all 1461 good
dates in 4 years, or 146097 in 400, but how many & which bad ones?

I wonder why the using Date Object is so slow; possibly in order to
accommodate out-of-range fields.
I've been re-looking at Zeller's Concordance (and have been in
communication with one of his great-grandsons). In converting Y M D to
day-of-week, Zeller separated out the century, which seems simpler for
manual arithmetic; but, at least on a computer, ISTM better not to :-
<URL:http://www.merlyn.demon.co.uk/zeller-c.htm#DDCC> boxes 1 & 3
Box 3 gives a much faster way of converting Y M D to a day count than
using a Date Object (at least, in my system).

That function is repeated at
<URL:http://www.merlyn.demon.co.uk/dayscale.htm#CDD> Box 1
and Box 2 gives an inverse. ISTM unlikely that one can do much better
for the forward function; but the inverse might be improvable ....

--
John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v4.00 MIME.
Web <URL:http://www.merlyn.demon.co.uk/> - w. FAQish topics, links, acronyms
PAS EXE etc : <URL:http://www.merlyn.demon.co.uk/programs/> - see 00index.htm
Dates - miscdate.htm moredate.htm js-dates.htm pas-time.htm critdate.htm etc.
Jul 23 '05 #29

P: n/a
Your discussion on speed of date validation is very interesting. Maybe
you can get my date calculator down to one single line ; -)

--
Dennis Marks
http://www.dcs-chico.com/~denmarks/
To reply change none to dcsi.
-----= Posted via Newsfeeds.Com, Uncensored Usenet News =-----
http://www.newsfeeds.com - The #1 Newsgroup Service in the World!
-----== Over 100,000 Newsgroups - 19 Different Servers! =-----
Jul 23 '05 #30

P: n/a
Dr John Stockton wrote:
Richard Cornford posted:
I make it 6-10% faster than Lasse's original (with !!ML). The version
I was using for testing was:-

var DateOK2b = (function(){
var __months = [NaN,31,28,31,30,31,30,31,31,30,31,30,31]
return (function(Y, M, D){
return (D <= __months[M])? (D > 0) :
(D==29) &&
(M==2) &&
!( ((Y&3)||((Y&15)&&(!(Y%25)))) );
});
})();
OK. But && M==2 seems superfluous.


It is necessary as M <= 0, or M >= 13 will refer to undefined (or NaN at
index zero) values and - D <= __months[M]) - will type convert those
undefined values into NaN for the comparison. All comparisons with NaN
return false, entering the branch where M == 2 is tested in order to
eliminate those out-of-range possibilities (which may still coincide
with D == 29, tested first as that would literally be a coincidence).
But I thought that testing M was better than using a local variable -
var ML = __months[M] - and applying a type-converting test to ML instead
(as it produces a boolean result in one operation and avoids the
assignment and additional work in variable instantiation).
Should NaN (instead of
blank) be faster?
I assume you mean starting the array - [NaN,31,28 - instead of -
[,31,28, -. It should be very fractionally faster when M == 0 as it
avoids a type-conversion to NaN from undefined, but I used it because I
don't trust javascript implementations to handle sparse array literals
consistently, so I avoid them when I can.
It's not obvious how best to speed-test - one should cover all 1461
good dates in 4 years, or 146097 in 400, but how many & which bad
ones?
I thought it only fair to use some month values outside of the
acceptable range along with some dates of zero or less and greater than
31 while comparing the various functions. But optimisation should be the
fast verification of correct date combinations as users should get those
right more often than not.
I wonder why the using Date Object is so slow; possibly in order to
accommodate out-of-range fields.
If you think IE's Date object is slow you haven't seen Opera 7.11
struggling through my first test script. :)
I've been re-looking at Zeller's Concordance (and have been in
communication with one of his great-grandsons). In converting Y M D
to day-of-week, Zeller separated out the century, which seems simpler
for manual arithmetic; but, at least on a computer, ISTM better not
to :- <URL:http://www.merlyn.demon.co.uk/zeller-c.htm#DDCC>
boxes 1 & 3
Box 3 gives a much faster way of converting Y M D to a day count than
using a Date Object (at least, in my system).

That function is repeated at
<URL:http://www.merlyn.demon.co.uk/dayscale.htm#CDD> Box 1
and Box 2 gives an inverse. ISTM unlikely that one can do much better
for the forward function; but the inverse might be improvable ....


I am going to be very pressed for time over the next couple of days but
I will have a look at that when I get the chance.

Richard.
Jul 23 '05 #31

This discussion thread is closed

Replies have been disabled for this discussion.