Numeric Date Validation

D

Dr John Stockton

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 ??
 
L

Lasse Reichstein Nielsen

Dr John Stockton said:
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
 
E

Evertjan.

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
 
F

Fox

Lasse said:
Dr John Stockton said:
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]).
 
D

Dr John Stockton

JRS: In article <180420041556393671%[email protected]>, seen in
news:comp.lang.javascript said:
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.
 
M

Michael Winter

On Sun, 18 Apr 2004 15:56:39 -0700, Dennis M. Marks

[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
 
F

Fox

Dr said:
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
*****************
 
D

Dr John Stockton

JRS: In article <[email protected]>, seen in
news:comp.lang.javascript said:
Dr John Stockton said:
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 :)).


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)
 
J

John G Harris

writes

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.

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.

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
 
D

Dr John Stockton

JRS: In article <[email protected]>, seen in
news:comp.lang.javascript said:
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.
 
D

Dr John Stockton

JRS: In article <[email protected]>, seen in
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.
 
D

Dr John Stockton

JRS: In article <[email protected]>, seen in
Michael Winter <[email protected]
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.
 
E

Evertjan.

Dr John Stockton wrote on 19 apr 2004 in comp.lang.javascript:
AFAICS, only two of those equality tests are needed.

That would not be very educational.
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
 
M

Michael Winter

JRS: In article <[email protected]>, seen in
Michael Winter


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.
 
C

Csaba Gabor

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.
 
M

Michael Winter

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.
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.
 
D

Dr John Stockton

JRS: In article <[email protected]>, seen in
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.
 
D

Dr John Stockton

JRS: In article <[email protected]>, seen in
Michael Winter <[email protected]
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.
 
D

Dr John Stockton

JRS: In article <[email protected]>, seen in
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.
but said:
From Bit Tiddle City,

Tiddle != Twiddle
 
M

Mick White

Evertjan. said:
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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,175
Latest member
Vinay Kumar_ Nevatia
Top