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

Multiple datepicker

P: n/a
Hi,

I am trying to introduce a multiple datepicker into a webpage and the
problem arises with the second picker. I tried to copy and adapt the code I
employed for the first one, renaming the variables but it is simply unable
to output any date to the database. The code for the first picker (which
works fine) is as follows:

<html>
<head>
<script type="text/javascript">

var numDays = {
'1': 31, '2': 28, '3': 31, '4': 30, '5': 31, '6': 30,
'7': 31, '8': 31, '9': 30, '10': 31, '11': 30, '12': 31
};

function setDays(oMonthSel, oDaysSel, oYearSel)
{
var nDays, oDaysSelLgth, opt, i = 1;
nDays = numDays[oMonthSel[oMonthSel.selectedIndex].value];
if (nDays == 28 && oYearSel[oYearSel.selectedIndex].value % 4 == 0)
++nDays;
oDaysSelLgth = oDaysSel.length;
if (nDays != oDaysSelLgth)
{
if (nDays < oDaysSelLgth)
oDaysSel.length = nDays;
else for (i; i < nDays - oDaysSelLgth + 1; i++)
{
opt = new Option(oDaysSelLgth + i, oDaysSelLgth + i);
oDaysSel.options[oDaysSel.length] = opt;
}
}
var oForm = oMonthSel.form;
var month = oMonthSel.options[oMonthSel.selectedIndex].value;
var day = oDaysSel.options[oDaysSel.selectedIndex].value;
var year = oYearSel.options[oYearSel.selectedIndex].value;
oForm.f_despara.value = month + '/' + day + '/' + year;
}
</head>
<body>
<form>
<table>
<tr>
<td>
<select name="day" class="buscar" id="day"
onChange="setDays(month,this,year)">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
<option value="13">13</option>
<option value="14">14</option>
<option value="15">15</option>
<option value="16">16</option>
<option value="17">17</option>
<option value="18">18</option>
<option value="19">19</option>
<option value="20">20</option>
<option value="21">21</option>
<option value="22">22</option>
<option value="23">23</option>
<option value="24">24</option>
<option value="25">25</option>
<option value="26">26</option>
<option value="27">27</option>
<option value="28">28</option>
<option value="29">29</option>
<option value="30">30</option>
<option value="31">31</option>
<option selected>D&iacute;a</option>
</select></td>
<td><select name="month" class="buscar" id="month"
onchange="setDays(this,day,year)">
<option value="1">Enero</option>
<option value="2">Febrero</option>
<option value="3">Marzo</option>
<option value="4">Abril</option>
<option value="5">Mayo</option>
<option value="6">Junio</option>
<option value="7">Julio</option>
<option value="8">Agosto</option>
<option value="9">Septiembre</option>
<option value="10">Octubre</option>
<option value="11">Noviembre</option>
<option value="12">Diciembre</option>
<option selected>Mes</option>
</select></td>
<td><select name="year" class="buscar" id="year"
onchange="setDays(month,day,this)">
<option value="1995">1995</option>
<option value="1996">1996</option>
<option value="1997">1997</option>
<option value="1998">1998</option>
<option value="1999">1999</option>
<option value="2000">2000</option>
<option value="2001">2001</option>
<option value="2002">2002</option>
<option value="2003">2003</option>
<option value="2004">2004</option>
<option selected>A&ntilde;o</option>
</select>
<input type="hidden" name="f_despara" value="" />
</td>
</tr>
</table>
</form>
</body>
</html>


Then I tried to add a second date picker and never worked. I tried this way:
I added another function to the script:

function setDays2(oMonth2Sel, oDays2Sel, oYear2Sel)
{
var nDays2, oDays2SelLgth, opt2, i2 = 1;
nDays2 = numDays[oMonth2Sel[oMonth2Sel.selectedIndex].value];
if (nDays2 == 28 && oYear2Sel[oYear2Sel.selectedIndex].value % 4 == 0)
++nDays2;
oDays2SelLgth = oDays2Sel.length;
if (nDays2 != oDays2SelLgth)
{
if (nDays2 < oDays2SelLgth)
oDays2Sel.length = nDays2;
else for (i2; i2 < nDays2 - oDays2SelLgth + 1; i2++)
{
opt = new Option(oDays2SelLgth + i2, oDays2SelLgth + i2);
oDays2Sel.options[oDays2Sel.length] = opt2;
}
}
var oForm2 = oMonth2Sel.form;
var month2 = oMonth2Sel.options[oMonth2Sel.selectedIndex].value;
var day2 = oDays2Sel.options[oDays2Sel.selectedIndex].value;
var year2 = oYear2Sel.options[oYear2Sel.selectedIndex].value;
oForm.f_vac1.value = month2 + '/' + day2 + '/' + year2;
}

and then added the date picker fields to the form:

<tr>
<td><select name="day2" class="buscar" id="day2"
onChange="setDays2(month2,this,year2)">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
<option value="11">11</option>
<option value="12">12</option>
<option value="13">13</option>
<option value="14">14</option>
<option value="15">15</option>
<option value="16">16</option>
<option value="17">17</option>
<option value="18">18</option>
<option value="19">19</option>
<option value="20">20</option>
<option value="21">21</option>
<option value="22">22</option>
<option value="23">23</option>
<option value="24">24</option>
<option value="25">25</option>
<option value="26">26</option>
<option value="27">27</option>
<option value="28">28</option>
<option value="29">29</option>
<option value="30">30</option>
<option value="31">31</option>
<option selected>D&iacute;a</option>
</select></td>
<td><select name="month2" class="buscar" id="month2"
onchange="setDays2(this,day2,year2)">
<option value="1">Enero</option>
<option value="2">Febrero</option>
<option value="3">Marzo</option>
<option value="4">Abril</option>
<option value="5">Mayo</option>
<option value="6">Junio</option>
<option value="7">Julio</option>
<option value="8">Agosto</option>
<option value="9">Septiembre</option>
<option value="10">Octubre</option>
<option value="11">Noviembre</option>
<option value="12">Diciembre</option>
<option selected>Mes</option>
</select></td>
<td><select name="year2" class="buscar" id="year2"
onchange="setDays2(month2,day2,this)">
<option value="1995">1995</option>
<option value="1996">1996</option>
<option value="1997">1997</option>
<option value="1998">1998</option>
<option value="1999">1999</option>
<option value="2000">2000</option>
<option value="2001">2001</option>
<option value="2002">2002</option>
<option value="2003">2003</option>
<option value="2004">2004</option>
<option selected>A&ntilde;o</option>
</select>
<input type="hidden" name="f_vac1" value="" />
</td>
</tr>

The script works well avoiding invalid date on the form but never passes the
value to the database.

Could someone help me?

Thanks in advance,

Gustavo
Jul 23 '05 #1
Share this Question
Share on Google+
27 Replies


P: n/a
Simon Templar wrote:
<html>
This is not Valid HTML. <http://validator.w3.org/>
<head>
<script type="text/javascript">

var numDays = {
'1': 31, '2': 28,
In leap years, February has 29 days.

'3': 31, '4': 30, '5': 31, '6': 30, '7': 31, '8': 31, '9': 30, '10': 31, '11': 30, '12': 31
};


The number of days a month has can be determined reliably (including
leap years) using Date objects:

/**
* Returns the number of days of a month.
*
* @author
* (C) 2004 Thomas Lahn <da*****@PointedEars.de>
* @partof
* <http://pointedears.de/scripts/date.js>
* @argument Date d
* Date object to hold the month.
* @return type number
* The number of the days of the month,
* -1 if no Date object has been passed.
*/
function getDaysOfMonth(d)
{
if (d && d.constructor == Date)
{
// make a "copy" of the passed Date object so that it does not change
var y;
if (d.getFullYear)
{
y = d.getFullYear();
}
else
{
y = d.getYear();
if (y < 1900)
{
y += 1900;
}
}

var d2 = new Date(y, d.getMonth() + 1, d.getDate());

// the day before the first day of the next month
// is the last day of the current month
d2.setDate(0);

return d2.getDate();
}

return -1;
}
For the rest of your source code, I suggest you put a testcase in a Valid
HTML document (if it contains server-side scripting, put the source code
of that in an unparsed HTML document [.phps and the like] or a text file)
instead of dumping more than 200 uncommented (and some even unnecessary)
lines of it to a public newsgroup.
PointedEars
Jul 23 '05 #2

P: n/a
Thomas 'PointedEars' Lahn <Po*********@web.de> writes:
function getDaysOfMonth(d)
Might as well pass the year and month number alone, no need for a full
date.
if (d.getFullYear)


While getFullYear is convenient, you are no better off if it turns
out to be missing. Just do:
---
function getDaysOfMonth(year, month) { // month==1 is January
if (year >= 0 && year < 100) {
year += 100;
month -= 1200;
}
return new Date(year, month, 0).getDate();
}
---
The correction for year/month seems to be necessary, otherwise the
function will fail for the year 0, as it (and everything else between
0 and 99) will have 1900 added to the year. However, the year 0 was a
leap year (according to the Javascript the Date object), while 1900
wasn'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 #3

P: n/a
JRS: In article <41**************@PointedEars.de>, dated Mon, 26 Jul
2004 06:28:55, seen in news:comp.lang.javascript, Thomas 'PointedEars'
Lahn <Po*********@web.de> posted :
Simon Templar wrote:
var numDays = {
'1': 31, '2': 28,


In leap years, February has 29 days.


If you had troubled to read the Sainted one's code before responding,
you would have seen that he is aware of that; his code fully complies
with the Julian Calendar, AFAICS.


'3': 31, '4': 30, '5': 31, '6': 30,
'7': 31, '8': 31, '9': 30, '10': 31, '11': 30, '12': 31
};
The number of days a month has can be determined reliably (including
leap years) using Date objects:

/**
* Returns the number of days of a month.


Only for fully-Gregorian months, of course.

*
* @author
* (C) 2004 Thomas Lahn <da*****@PointedEars.de>
YCKI.

y = d.getYear();
if (y < 1900)
{
y += 1900;
}
}
Incorrect in some systems. I have recently posted, and no-one has
refuted, a brief and reliable means of getting the full year from any
plausible getYear().

d2.setDate(0);


Possible failure in Mac NS 4.


Recent discussion in this group should have indicated to you a
considerably quicker, and shorter, method.
Simon : see FAQ; it leads indirectly to
<URL:http://www.merlyn.demon.co.uk/js-date4.htm#MaYl> which has

function TailOfMonth(y, m) {
if (m==1) return 28 + (y%4 == 0) // 1901-2099
return [31,0,31,30,31,30, 31,31,30,31,30,31][m] }

which is rather like what you already have. On my system, it is about 5
times faster than the best I know using a Date Object, and that is
nearly twice as fast as one like what TL gave.

Modification for all Gregorian years should not slow it much.

BOTF.

--
John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v4.00 IE 4
<URL:http://jibbering.com/faq/> JL / RC : 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 #4

P: n/a
Dr John Stockton wrote:
JRS: In article <41**************@PointedEars.de>, dated Mon, 26 Jul
2004 06:28:55, seen in news:comp.lang.javascript, Thomas 'PointedEars'
Lahn <Po*********@web.de> posted :
Simon Templar wrote:
var numDays = {
'1': 31, '2': 28,


In leap years, February has 29 days.

If you had troubled to read the Sainted one's code before responding,
you would have seen that he is aware of that; his code fully complies
with the Julian Calendar, AFAICS.
'3': 31, '4': 30, '5': 31, '6': 30,
'7': 31, '8': 31, '9': 30, '10': 31, '11': 30, '12': 31
};


The number of days a month has can be determined reliably (including
leap years) using Date objects:

/**
* Returns the number of days of a month.

Only for fully-Gregorian months, of course.
*
* @author
* (C) 2004 Thomas Lahn <da*****@PointedEars.de>

YCKI.
y = d.getYear();
if (y < 1900)
{
y += 1900;
}
}

Incorrect in some systems. I have recently posted, and no-one has
refuted, a brief and reliable means of getting the full year from any
plausible getYear().
d2.setDate(0);

Possible failure in Mac NS 4.


Recent discussion in this group should have indicated to you a
considerably quicker, and shorter, method.
Simon : see FAQ; it leads indirectly to
<URL:http://www.merlyn.demon.co.uk/js-date4.htm#MaYl> which has

function TailOfMonth(y, m) {
if (m==1) return 28 + (y%4 == 0) // 1901-2099
return [31,0,31,30,31,30, 31,31,30,31,30,31][m] }

function TailOfMonth(y, m) {
return [31,y%4 == 0?29:28,31,30,31,30, 31,31,30,31,30,31][m] }

Mick

which is rather like what you already have. On my system, it is about 5
times faster than the best I know using a Date Object, and that is
nearly twice as fast as one like what TL gave.

Modification for all Gregorian years should not slow it much.

BOTF.

Jul 23 '05 #5

P: n/a
Dr John Stockton <sp**@merlyn.demon.co.uk> writes:
function TailOfMonth(y, m) {
if (m==1) return 28 + (y%4 == 0) // 1901-2099
return [31,0,31,30,31,30, 31,31,30,31,30,31][m] }

which is rather like what you already have. On my system, it is about 5
times faster than the best I know using a Date Object, and that is
nearly twice as fast as one like what TL gave.


In my versions of IE, Opera, that versions is about as
fast as the Date based version I suggested (not entirely sure for
Mozilla, because it asked me if I wanted to stop the script because it
had run too long .. but it seems the Date object is *very* slow).

If speed is of the essence, not creating an array for each call is a
great saving in both Mozilla and Opera (and is marginally faster in IE
as well). This version:

var months = [31,,31,30,31,30,31,31,30,31,30,31];
function lengthOfMonth(y,m) { // m==0 is January
return arr[m] || ((!(y%4) && (!!(y%25) || !(y%400)))+28);
}

is very fast in both Opera and Mozilla (in a loop, it takes almost no
time over a no-op function), and it isn't slower in IE.

/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 #6

P: n/a
JRS: In article <sm**********@hotpop.com>, dated Mon, 26 Jul 2004
19:02:04, seen in news:comp.lang.javascript, Lasse Reichstein Nielsen
<lr*@hotpop.com> posted :
Thomas 'PointedEars' Lahn <Po*********@web.de> writes:
function getDaysOfMonth(d)


Might as well pass the year and month number alone, no need for a full
date.
if (d.getFullYear)


While getFullYear is convenient, you are no better off if it turns
out to be missing. Just do:
---
function getDaysOfMonth(year, month) { // month==1 is January
if (year >= 0 && year < 100) {
year += 100;
month -= 1200;
}
return new Date(year, month, 0).getDate();
}
---
The correction for year/month seems to be necessary, otherwise the
function will fail for the year 0, as it (and everything else between
0 and 99) will have 1900 added to the year. However, the year 0 was a
leap year (according to the Javascript the Date object), while 1900
wasn't.


The correction is over-complex, since for this purpose it is only
necessary to add 400 years (and only for February; and only for Year 0,
I think). The year only needs to be correct modulo 400.

Or add a multiple thereof; so, since there is probably little interest
in month-lengths before BC 10000 or after AD 250000, the best is just to
add 10000 years unconditionally - assuming that new Date is sensibly
written.

Year 0 (BC 1) was a leap year on the Gregorian & Julian calendars; but
not in actuality, since the Romans had been bad at counting up to 4.
For y >= 0, full Gregorian,

function LastOfMonth(y, m) { // m = 0..11 // new, undertested.
if (m==1) return 29 - ( y & 3 || y & 15 && !(y % 25) ) // ~ CGjrs
return [31,0,31,30,31,30, 31,31,30,31,30,31][m] }

--
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 #7

P: n/a
Dr John Stockton <sp**@merlyn.demon.co.uk> writes:
The correction is over-complex,
Absolutely.
since for this purpose it is only necessary to add 400 years (and
only for February; and only for Year 0, I think). The year only
needs to be correct modulo 400.
Indeed. Only the year 0 fails, because only years between 0 and 99
are affected by the year-rewriting, and of those, only 0 differst
from the year + 1900.

The reason (well, excuse) for doing it this way was to not need to
know how the month lengths are calculated. That is left entirely
up to the Date object. The only rewriting was to avoid the problem
with years 0-99 as arguments to the constructor.
For y >= 0, full Gregorian,

function LastOfMonth(y, m) { // m = 0..11 // new, undertested.
if (m==1) return 29 - ( y & 3 || y & 15 && !(y % 25) ) // ~ CGjrs
return [31,0,31,30,31,30, 31,31,30,31,30,31][m] }


Except
LastOfMonth(2002,1) == 27
and
LastOfMonth(2003,1) == 26
since (y&3) becomes 2 and 3 in those years. If you change it to:

function LastOfMonth(y, m) { // m = 0..11 // new, undertested.
if (m==1) return 29 - ( !!(y & 3) || y & 15 && !(y % 25) ) // ~ CGjrs
return [31,0,31,30,31,30, 31,31,30,31,30,31][m] }

then it seems to work (the bit-fiddling is impressive :).

For efficiency, you only need to do the extra calculation for m == 1.

/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 #8

P: n/a
JRS: In article <br**********@hotpop.com>, dated Tue, 27 Jul 2004
01:01:25, seen in news:comp.lang.javascript, Lasse Reichstein Nielsen
<lr*@hotpop.com> posted :
Dr John Stockton <sp**@merlyn.demon.co.uk> writes:
The correction is over-complex,
Absolutely.
since for this purpose it is only necessary to add 400 years (and
only for February; and only for Year 0, I think). The year only
needs to be correct modulo 400.


Indeed. Only the year 0 fails, because only years between 0 and 99
are affected by the year-rewriting, and of those, only 0 differst
from the year + 1900.

The reason (well, excuse) for doing it this way was to not need to
know how the month lengths are calculated. That is left entirely
up to the Date object. The only rewriting was to avoid the problem
with years 0-99 as arguments to the constructor.
For y >= 0, full Gregorian,

function LastOfMonth(y, m) { // m = 0..11 // new, undertested.
if (m==1) return 29 - ( y & 3 || y & 15 && !(y % 25) ) // ~ CGjrs
return [31,0,31,30,31,30, 31,31,30,31,30,31][m] }


Except
LastOfMonth(2002,1) == 27
and
LastOfMonth(2003,1) == 26
since (y&3) becomes 2 and 3 in those years. If you change it to:

function LastOfMonth(y, m) { // m = 0..11 // new, undertested.
if (m==1) return 29 - ( !!(y & 3) || y & 15 && !(y % 25) ) // ~ CGjrs
return [31,0,31,30,31,30, 31,31,30,31,30,31][m] }

then it seems to work (the bit-fiddling is impressive :).

Yes, the tests that were exhaustive enough for the older methods proved
inadequate. I now test every month in 400 years, for safety.

29 - !! ( y & 3 || y & 15 && !(y % 25) )

looks nicer to me, and tests OK in js-dates4.htm. Thanks.
JRS: In article <is**********@hotpop.com>, dated Mon, 26 Jul 2004
21:56:53, seen in news:comp.lang.javascript, Lasse Reichstein Nielsen
<lr*@hotpop.com> posted :
If speed is of the essence, not creating an array for each call is a
great saving in both Mozilla and Opera (and is marginally faster in IE
as well).


That will take a while to put neatly into page 4; I have several very
similar arrays, and only the unnecessary differences can be ignored in
merging them.

--
John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v4.00 IE 4
<URL:http://jibbering.com/faq/> JL / RC : 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
rh
Dr John Stockton <sp**@merlyn.demon.co.uk> wrote:
JRS: In article <is**********@hotpop.com>, dated Mon, 26 Jul 2004
21:56:53, seen in news:comp.lang.javascript, Lasse Reichstein Nielsen
<lr*@hotpop.com> posted :
If speed is of the essence, not creating an array for each call is a
great saving in both Mozilla and Opera (and is marginally faster in IE
as well).


You may also wish to consider something along the lines of:

function LastOfMonth(y, m) { // m = 0..11
return 29 + (m*31/12 | 0) - ((m-1)*31/12 | 0) + !m
- ( !! (m-1) || 2
+ ( !!((y & 3) || y & 15 && !(y % 25) )) ) ; // ~ CGjrs }

which cadges from Zeller (at the very least, makes use of a function I
came across a couple of years ago in an implementation of Zeller's
congruence). It's considerably more efficient than creating the lookup
array within the js function, but will be slower (although perhaps
still not all that much slower) than your table lookup with the array
created outside.

../rh
Jul 23 '05 #10

P: n/a
JRS: In article <29**************************@posting.google.com >,
dated Tue, 27 Jul 2004 19:42:56, seen in news:comp.lang.javascript, rh
<co********@yahoo.ca> posted :
You may also wish to consider something along the lines of:

function LastOfMonth(y, m) { // m = 0..11
return 29 + (m*31/12 | 0) - ((m-1)*31/12 | 0) + !m
- ( !! (m-1) || 2
+ ( !!((y & 3) || y & 15 && !(y % 25) )) ) ; // ~ CGjrs }

which cadges from Zeller (at the very least, makes use of a function I
came across a couple of years ago in an implementation of Zeller's
congruence). It's considerably more efficient than creating the lookup
array within the js function, but will be slower (although perhaps
still not all that much slower) than your table lookup with the array
created outside.


Moving the final } to before the comment mark helps. Then, assuming the
tests in js-date4.htm are now adequate, it is correct over a full cycle
of 400 years Gregorian and in IE4 is 2-3 times faster than the best of
the others there.

It does not, at first sight, though, look much like Zeller's Congruence.
though it has in common the idea of using arithmetic instead of table
lookup. Have you seen my Zeller pages, via <URL:http://www.merlyn.demon
..co.uk/zeller-c.htm> etc. ?
function MonthLength(y, m) { // m = 0..11
return new Date(y, m+1, 1, -9).getDate() }

is the best I've found for a function which can immediately be seen to
be correct, though; ten times slower.

--
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
rh
Dr John Stockton wrote:
Moving the final } to before the comment mark helps.
Thats well and good. It seems that a newline got dropped in the
posting.
Then, assuming the
tests in js-date4.htm are now adequate, it is correct over a full cycle
of 400 years Gregorian and in IE4 is 2-3 times faster than the best of
the others there.

It does not, at first sight, though, look much like Zeller's Congruence.
though it has in common the idea of using arithmetic instead of table
lookup. Have you seen my Zeller pages, via <URL:http://www.merlyn.demon
.co.uk/zeller-c.htm> etc. ?


I have, and noted there was no direct comparable, which was in part
the reason for some minor, but perhaps not enough, caution in the
wording of the post. The first difference calculation I used is
equivalent to that found at:

<URL: http://users.aol.com/s6sj7gt/mikecal.htm>

which also makes reference to similarity "in spirit" with Zeller's
congruence.

While on the topic of js date calculations, a relatively
straightforward conversion of the C code to JavaScript found there
gives:

function DayOfWeek(d,m,y) { // d = 1..31; m = 1..12
return (d+=m<3? y--:y-2, d+4+ Math.floor(23*m/9)+ Math.floor(y/4)
- Math.floor(y/100)+Math.floor(y/400))%7;
}

which (under very limited testing) appears to give the expected result
in IE.

Aside from the commendable mathematical finesse and compactness of the
code, it provides an interesting look at use of the comma operator
(jslint notwithstanding, of course) -- a construct that seems to be
extremely rare (non-existent? :)) in demonstration js code posts.

../rh
Jul 23 '05 #12

P: n/a
Dr John Stockton wrote:
rh wrote:
You may also wish to consider something along the lines of:

function LastOfMonth(y, m) { // m = 0..11
return 29 + (m*31/12 | 0) - ((m-1)*31/12 | 0) + !m
- ( !! (m-1) || 2
+ ( !!((y & 3) || y & 15 && !(y % 25) )) ) ; // ~ CGjrs
}
<snip>
... , assuming the tests in js-date4.htm are now adequate,
it is correct over a full cycle of 400 years Gregorian and
in IE4 is 2-3 times faster than the best of the others there. <snip> function MonthLength(y, m) { // m = 0..11
return new Date(y, m+1, 1, -9).getDate() }

is the best I've found for a function which can immediately be seen to
be correct, though; ten times slower.


Looking at the - LastOfMonth - function I observer that the
calculation - 31/12 - is done twice. The result must be the same each
time, and could be pre-calculated. Given that the result is truncated by
the OR zero operation and the range of - m - is limited, an
approximation of - 31/12 - should be sufficient, and - 2.58 - (or its
internal IEEE double representation) seems to be close enough to give
identical results for m == [0 to 11].

Next, - (m-1) - is calculated twice. If - +!m - were moved forward the
first occurrence of - (m-1) - could be replaced with - (--m) - and the
second replaced with just - m -, producing:-

function LastOfMonth2(y, m) { // m = 0..11
return 29 + (m*2.58 | 0) + !m - ((--m)*2.58 | 0)
- ( !!(m) || 2
+ ( !!((y & 3) || y & 15 && !(y % 25) )) ) ;
}

However, for February in the year zero - MonthLength - returns 28 days,
while - LastOfMonth - returns 29. The expression - (!!(m-1)|| ... ) -
only moves into the OR clause in February, so a final additional
adjustment by - !y - (only 1 in the year zero, zero otherwise) would
correct the discrepancy at a minimal cost in processing time, producing
(in my version):-

function LastOfMonth3(y, m) { // m = 0..11
return 29 + (m*2.58 | 0) + !m - ((--m)*2.58 | 0)
- ( !!(m) || 2 +
(!!(
(y & 3)||
(
(y & 15 && !(y % 25))||
!y
/* or maybe:-
((y & 15)||!y)&&
!(y % 25)
or:-
((y & 15)?!(y % 25):!y)
*/
)
))
);
}

- and flipping some of the logic in the final expression produced:-

function LastOfMonth2(y, m) { // m = 0..11
return 29 + (m*2.58 | 0) + !m - ((--m)*2.58 | 0)
- ( !!(m) || 2
+ (!( !(y & 3)&&((y & 15)?(y % 25):y) )));
}

- losing some of the logical NOT operations along the way.

Those gives me identical results to - MonthLength - for all months in
years from -1000 to +3200 and is still very fractionally faster than
the original - LastOfMonth -.

Richard.
Jul 23 '05 #13

P: n/a
Richard Cornford wrote:
- and flipping some of the logic in the final expression produced:-

function LastOfMonth2(y, m) { // m = 0..11
return 29 + (m*2.58 | 0) + !m - ((--m)*2.58 | 0)
- ( !!(m) || 2
+ (!( !(y & 3)&&((y & 15)?(y % 25):y) )));
}

- losing some of the logical NOT operations along the way.

Those gives me identical results to - MonthLength - for all months in
years from -1000 to +3200 and is still very fractionally faster than
the original - LastOfMonth -.

Richard.


And any execution time you might have gained was time lost figuring all that
out. The users' time waiting for the number of days in a month is
effectively "free" (since it is so short on a per instance basis) and your
time is not. I get it though, producing the optimal algorithm for a given
problem can be fun, I do it myself sometimes. But in this case, I'd most
likely use some variation of the Date() object solution presented by Thomas.

Why would I use a clunky Date() object driven solution when I have a much
faster algorithm? Because a Date object solution is incredibly clear. If I
need to go back later and modify the code (although I can't imagine why I
would need to unless calendars spontaneously produce a 13th month), code
using a Date object is self-documenting. Even if I can't find the original
code, I could probably re-write it in about 2 minutes.

Again, don't get me wrong, I'm not criticizing at all. I'm just contributing
something to the discussion (I hope), but pointing out that sometimes the
"optimal" solution isn't necessarily the "best" solution (especially if
someone else is paying for the "optimal" solution).

In fact, given the parameter choices (year and month), here is my solution:

function LastOfMonth3(y, m) { // m = 0..11
var d = new Date(y, (m + 1), 1);
if (d && d.constructor == Date) {
d.setDate(0);
return d.getDate();
} else {
return -1;
}
}

Note that Netscape 4.78 does not properly handle constructing a date with a
day of 0, as a result, it is necessary to construct the date for the first
of the next month, then set it to zero.

My solution produces the same results as yours for all months 0..11 for all
years 1000..3199. Now for the fun part. For all months 0..11 for all years
1000..3199 (times in ms);

LastOfMonth -2- -3-
IE: 282 4172
NS4: 12719 30970
FF0.9: 391 25516 (two "slow script" warnings)
O7.53: 531 5094
M1.7.1: 500 25908 (two "slow script" warnings)

Okay, I take it all back. Given these performance figures I'd use Richard's
solution :D.

--
Grant Wagner <gw*****@agricoreunited.com>
comp.lang.javascript FAQ - http://jibbering.com/faq

Jul 23 '05 #14

P: n/a
Richard Cornford wrote:
- and flipping some of the logic in the final expression
produced:-

function LastOfMonth2(y, m) { // m = 0..11
return 29 + (m*2.58 | 0) + !m - ((--m)*2.58 | 0)
- ( !!(m) || 2
+ (!( !(y & 3)&&((y & 15)?(y % 25):y) )));
}

- losing some of the logical NOT operations along the way.

Those gives me identical results to - MonthLength - for all
months in
years from -1000 to +3200 and is still very fractionally faster
than
the original - LastOfMonth -.

Richard.


And any execution time you might have gained was time lost
figuring all that out. The users' time waiting for the number of
days in a month is effectively "free" (since it is so short on a
per instance basis) and your time is not. I get it though,
producing the optimal algorithm for a given problem can be fun, I
do it myself sometimes. But in this case, I'd most likely use
some variation of the Date() object solution presented by Thomas.

Why would I use a clunky Date() object driven solution when I
have a much faster algorithm? Because a Date object solution is
incredibly clear. If I need to go back later and modify the code
(although I can't imagine why I would need to unless calendars
spontaneously produce a 13th month), code using a Date object is
self-documenting. Even if I can't find the original code, I could
probably re-write it in about 2 minutes.

Again, don't get me wrong, I'm not criticizing at all. I'm just
contributing something to the discussion (I hope), but pointing
out that sometimes the "optimal" solution isn't necessarily the
"best" solution (especially if someone else is paying for the
"optimal" solution).

In fact, given the parameter choices (year and month), here is my
solution:

function LastOfMonth3(y, m) { // m = 0..11
var d = new Date(y, (m + 1), 1);
if (d && d.constructor == Date) {
d.setDate(0);
return d.getDate();
} else {
return -1;
}
}

Note that Netscape 4.78 does not properly handle constructing a
date with a day of 0, as a result, it is necessary to construct
the date for the first of the next month, then set it to zero.

My solution produces the same results as yours for all months
0..11 for all years 1000..3199. Now for the fun part. For all
months 0..11 for all years 1000..3199 (times in ms);

LastOfMonth -2- -3-
IE: 282 4172
NS4: 12719 30970
FF0.9: 391 25516 (two "slow script" warnings)
O7.53: 531 5094
M1.7.1: 500 25908 (two "slow script" warnings)

Okay, I take it all back. Given these performance figures I'd use
Richard's solution :D.

--
Grant Wagner <gw*****@agricoreunited.com>
comp.lang.javascript FAQ - http://jibbering.com/faq

Jul 23 '05 #15

P: n/a
Grant Wagner wrote:
Richard Cornford wrote: <snip>
... is still very fractionally faster than
the original - LastOfMonth -.


And any execution time you might have gained was time lost
figuring all that out. The users' time waiting for the number
of days in a month is effectively "free" (since it is so short
on a per instance basis) and your time is not. I get it though,
producing the optimal algorithm for a given problem can be fun,
I do it myself sometimes.

<snip>

There is the (not everyone's idea of) fun aspect of optimum algorithms,
but I find that activity useful anyway because recognising an efficient
formulation in one context may make its applicability more obvious in
another (where it may be more significant).

In most respects the speed of date calculations in form validation is
not significant, but the Date object is not without its limitations.
There are, for example, implementations with a 32 bit milliseconds
representation so they are range limited to between some time in 1901
and 2039 (as I recall). Not a problem in most current (and especially
commercial) contexts but for something like a DHTML animation relating
star positions to date a combination of a large (and known) date range
and fast execution might be useful.

<snip> Again, don't get me wrong, I'm not criticizing at all. I'm just
contributing something to the discussion (I hope), but pointing
out that sometimes the "optimal" solution isn't necessarily the
"best" solution (especially if someone else is paying for the
"optimal" solution).

<snip>

I wouldn't argue with that.

Richard.
Jul 23 '05 #16

P: n/a
rh
"Richard Cornford" wrote:
Looking at the - LastOfMonth - function I observer that the
calculation - 31/12 - is done twice. The result must be the same each
time, and could be pre-calculated. Given that the result is truncated by
the OR zero operation and the range of - m - is limited, an
approximation of - 31/12 - should be sufficient, and - 2.58 - (or its
internal IEEE double representation) seems to be close enough to give
identical results for m == [0 to 11].
I think I was hoping there would be a "compile-time" constant
expression optimization, but I don't know whether such occurs in js
implementations. Probably not.

Next, - (m-1) - is calculated twice. If - +!m - were moved forward the
first occurrence of - (m-1) - could be replaced with - (--m) - and the
second replaced with just - m -, producing:-

function LastOfMonth2(y, m) { // m = 0..11
return 29 + (m*2.58 | 0) + !m - ((--m)*2.58 | 0)
- ( !!(m) || 2
+ ( !!((y & 3) || y & 15 && !(y % 25) )) ) ;
}

That's a good change.

<..>
- and flipping some of the logic in the final expression produced:-

function LastOfMonth2(y, m) { // m = 0..11
return 29 + (m*2.58 | 0) + !m - ((--m)*2.58 | 0)
- ( !!(m) || 2
+ (!( !(y & 3)&&((y & 15)?(y % 25):y) )));
}

- losing some of the logical NOT operations along the way.

Hey, tertiary conditionals aren't allowed!! :)
Those gives me identical results to - MonthLength - for all months in
years from -1000 to +3200 and is still very fractionally faster than
the original - LastOfMonth -.


Here's another version that executes as fast, or marginally faster,
than LastOfMonth2 in IE, Netscape, Mozilla and Opera, and gives the
same results over a similar (wider) range in my tests:
function LastOfMonth3(y, m) { // m = 0..11
return 29 + !m + (m*2.58 | 0) - (--m*2.58 | 0)
- ( !!m || 2 + !y
+ ( !!( (y & 3) || y & 15 && !(y % 25) )) ) ; // ~ CGjrs
}
../rh
Jul 23 '05 #17

P: n/a
rh wrote:
"Richard Cornford" wrote:
Looking at the - LastOfMonth - function I observer
that the calculation - 31/12 - is done twice. ... <snip>
I think I was hoping there would be a "compile-time" constant
expression optimization, but I don't know whether such occurs
in js implementations. Probably not.
That is certainly a possible optimisation, but not something that I
would necessarily expect from a JS implementation.

<snip> - and flipping some of the logic in the final expression
produced:-
function LastOfMonth2(y, m) { // m = 0..11
return 29 + (m*2.58 | 0) + !m - ((--m)*2.58 | 0)
- ( !!(m) || 2
+ (!( !(y & 3)&&((y & 15)?(y % 25):y) )));
}

- losing some of the logical NOT operations along the way.


Hey, tertiary conditionals aren't allowed!! :)


I don't see why not. If the trade of between the less efficient tertiary
conditional and not having to do so many NOT operations were more
significant then it would be a good idea. In this context reducing the
number of NOT operations doesn't provide enough benefit to decide the
matter one way or the other.

<snip> Here's another version that executes as fast, or marginally
faster, than LastOfMonth2 in IE, Netscape, Mozilla and Opera,
and gives the same results over a similar (wider) range in my
tests:

function LastOfMonth3(y, m) { // m = 0..11
return 29 + !m + (m*2.58 | 0) - (--m*2.58 | 0)
- ( !!m || 2 + !y
+ ( !!( (y & 3) || y & 15 && !(y % 25) )) ) ; // ~ CGjrs
}


One of the reasons I was using the tertiary conditional, or one of my
other two proposals:-

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

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

- was to move the - !y - operation to the right of - (y & 3) - so that
in addition to only being done for one month in 12 it would then only be
done for one year in 4 (less, once it is to the right of - (y & 15) -).

My test still suggest that my version is (very fractionally) faster than
your latest, but I had to loop through 90,000 years to get a difference
of < 1% and a minority of tests came out the other way around so I
expect the influence of background tasks is too great to call this one
way or the other.

Richard.
Jul 23 '05 #18

P: n/a
JRS: In article <29*************************@posting.google.com> , dated
Wed, 28 Jul 2004 21:41:15, seen in news:comp.lang.javascript, rh
<co********@yahoo.ca> posted :
The first difference calculation I used is
equivalent to that found at:

<URL: http://users.aol.com/s6sj7gt/mikecal.htm>
Interesting.
which also makes reference to similarity "in spirit" with Zeller's
congruence.

While on the topic of js date calculations, a relatively
straightforward conversion of the C code to JavaScript found there
gives:

function DayOfWeek(d,m,y) { // d = 1..31; m = 1..12
return (d+=m<3? y--:y-2, d+4+ Math.floor(23*m/9)+ Math.floor(y/4)
- Math.floor(y/100)+Math.floor(y/400))%7;
}

which (under very limited testing) appears to give the expected result
in IE.


Now in the foot of zeller-c.htm; unless my testing has blundered, it is
OK for all months in 401 years, and for at least some days in the months
(the dependence on d is obviously correct).

It could be shortened a bit, but not by a line, by using |0 instead of
Math.floor.

--
John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v4.00 MIME.
Web <URL:http://www.merlyn.demon.co.uk/> - FAQqish topics, acronyms & links;
some Astro stuff via astro.htm, gravity0.htm; quotes.htm; pascal.htm; &c, &c.
No Encoding. Quotes before replies. Snip well. Write clearly. Don't Mail News.
Jul 23 '05 #19

P: n/a
JRS: In article <41***************@agricoreunited.com>, dated Thu, 29
Jul 2004 20:36:12, seen in news:comp.lang.javascript, Grant Wagner
<gw*****@agricoreunited.com> posted :
In fact, given the parameter choices (year and month), here is my
solution:

function LastOfMonth3(y, m) { // m = 0..11
var d = new Date(y, (m + 1), 1);
if (d && d.constructor == Date) {
d.setDate(0);
return d.getDate();
} else {
return -1;
}
}

Note that Netscape 4.78 does not properly handle constructing a
date with a day of 0, as a result, it is necessary to construct
the date for the first of the next month, then set it to zero.
Does it handle new Date(y, m+1, 1, -9) ?

(optimisation : 9 is the digit nearest to the - key)

Okay, I take it all back. Given these performance figures I'd use
Richard's solution :D.


The real benefit is not in the result-code, but in what is learned in
getting the that code.

--
John Stockton, Surrey, UK. ?@merlyn.demon.co.uk Turnpike v4.00 MIME.
Web <URL:http://www.merlyn.demon.co.uk/> - FAQqish topics, acronyms & links;
some Astro stuff via astro.htm, gravity0.htm; quotes.htm; pascal.htm; &c, &c.
No Encoding. Quotes before replies. Snip well. Write clearly. Don't Mail News.
Jul 23 '05 #20

P: n/a
JRS: In article <ce*******************@news.demon.co.uk>, dated Fri, 30
Jul 2004 01:14:14, seen in news:comp.lang.javascript, Richard Cornford
<Ri*****@litotes.demon.co.uk> posted :
the Date object is not without its limitations.
There are, for example, implementations with a 32 bit milliseconds
representation so they are range limited to between some time in 1901
and 2039 (as I recall).


Signed 32-bit seconds from 1970-01-01 00:00:00 GMT = 0 has a range of
1901-12-13 20:45:52 GMT to 2038-01-19 03:14:07 GMT inclusive.

The half-way point was 2004-01-10 13:37:04 GMT; failures were reported
in Risks Digest (news:comp.risks).

It would be worth noting such non-ECMA262 implementations; with some
mortgage look-aheads being 30 years, problems may appear by early 2008.

--
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 #21

P: n/a
rh
"Richard Cornford" wrote:

<..>
rh wrote:
Hey, tertiary conditionals aren't allowed!! :)
I don't see why not.


Because part of the fun here was to see the whole thing succinctly and
efficiently accomplished with bit munging and (short-cut) logic (but
you may get your fun in other ways).
If the trade of between the less efficient tertiary
conditional and not having to do so many NOT operations were more
significant then it would be a good idea. In this context reducing the
number of NOT operations doesn't provide enough benefit to decide the
matter one way or the other.

And I agree that primarily is the determinant. Also to be considered
is, if there is an efficiency return, what is the trade-off in
complexity cost, and is it worth it?

This is a case where you're agreeing the tertiary conditional benefit
was not seen to be significant (before even getting to the complexity
question).
<snip>
Here's another version that executes as fast, or marginally
faster, than LastOfMonth2 in IE, Netscape, Mozilla and Opera,
and gives the same results over a similar (wider) range in my
tests:

function LastOfMonth3(y, m) { // m = 0..11
return 29 + !m + (m*2.58 | 0) - (--m*2.58 | 0)
- ( !!m || 2 + !y
+ ( !!( (y & 3) || y & 15 && !(y % 25) )) ) ; // ~ CGjrs
}
One of the reasons I was using the tertiary conditional, or one of my
other two proposals:-

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

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

- was to move the - !y - operation to the right of - (y & 3) - so that
in addition to only being done for one month in 12 it would then only be
done for one year in 4 (less, once it is to the right of - (y & 15) -).


Fully understood and appreciated.
My test still suggest that my version is (very fractionally) faster than
your latest, but I had to loop through 90,000 years to get a difference
of < 1% and a minority of tests came out the other way around so I
expect the influence of background tasks is too great to call this one
way or the other.


My point wasn't to say I can produce a faster version. It was that
your tertiary conditional gambit, in my view, couldn't be shown to pay
off, particularly given considerations I've stated above.

Regards,

../rh
Jul 23 '05 #22

P: n/a
co********@yahoo.ca (rh) writes:
Here's another version that executes as fast, or marginally faster,
than LastOfMonth2 in IE, Netscape, Mozilla and Opera, and gives the
same results over a similar (wider) range in my tests: function LastOfMonth3(y, m) { // m = 0..11
return 29 + !m + (m*2.58 | 0) - (--m*2.58 | 0)
- ( !!m || 2 + !y
+ ( !!( (y & 3) || y & 15 && !(y % 25) )) ) ; // ~ CGjrs
}


It looks almost ok, although it seems to claim that year 0 wasn't
a leap year. That's the only year I can see a difference for.

I though of another version, that used bit operations instead
of arithmetics (if I can't have an array, I can still code one
into an integer :)
---
function LastOfMonthBitArray(y,m) {
return 28 + (((0xeefbb3>>(m<<1))&3) ||
!((y&3)||((y&15)&&!(y%25))) );
}
---
How efficient it is varies between browsers. In IE, it's slower than
the one above, in Opera, it's faster, and in MozFF the fastest method
I have. In IE and Opera, this one is still fastest (even by a lot in
IE - for all months in all years between 0 and 5000, the following
function is almost four times as fast as the above!).

---
var arr = [31,,31,30,31,30,31,31,30,31,30,31];
function LastOfMonthExternalArray(y,m) {
return arr[m] || 28+!((y&3)||((y&15)&&!(y%25)));
}
--

/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 #23

P: n/a
rh
Lasse Reichstein Nielsen wrote:
co********@yahoo.ca (rh) writes:
Here's another version that executes as fast, or marginally faster,
than LastOfMonth2 in IE, Netscape, Mozilla and Opera, and gives the
same results over a similar (wider) range in my tests:
function LastOfMonth3(y, m) { // m = 0..11
return 29 + !m + (m*2.58 | 0) - (--m*2.58 | 0)
- ( !!m || 2 + !y
+ ( !!( (y & 3) || y & 15 && !(y % 25) )) ) ; // ~ CGjrs
}


It looks almost ok, although it seems to claim that year 0 wasn't
a leap year. That's the only year I can see a difference for.


OK, I think I see where we went wrong. Richard used MonthLength to
test, and concluded that the year 0 had 28 days. However, that is
incorrect because MonthLength is really giving a value for 1900, not
the year 0 (as pointed out at the start of this thread, because of the
weird Date object behaviour for year parameters in the range 0-99 :().

So the whole effort to adjust for year 0 was misguided, and
LastOfMonth3 should really read:

function LastOfMonth3(y, m) { // m = 0..11
return 29 + !m + (m*2.58 | 0) - (--m*2.58 | 0)
- ( !!m || 2
+ ( !!( (y & 3) || y & 15 && !(y % 25) )) ) ; // ~ CGjrs
}

I though of another version, that used bit operations instead
of arithmetics (if I can't have an array, I can still code one
into an integer :)
---
function LastOfMonthBitArray(y,m) {
return 28 + (((0xeefbb3>>(m<<1))&3) ||
!((y&3)||((y&15)&&!(y%25))) );
}
---
Neat!!
How efficient it is varies between browsers. In IE, it's slower than
the one above, in Opera, it's faster, and in MozFF the fastest method
I have. In IE and Opera, this one is still fastest (even by a lot in
IE - for all months in all years between 0 and 5000, the following
function is almost four times as fast as the above!).

---
var arr = [31,,31,30,31,30,31,31,30,31,30,31];
function LastOfMonthExternalArray(y,m) {
return arr[m] || 28+!((y&3)||((y&15)&&!(y%25)));
}
--


My timing results (Win98) over all months in years -10,000 to 10,000
seem to be quite different from what you found:

LastOfMonthBitArray LastOfMonthExternalArray LastOfMonth3

IE 1150 1270 1480
NS 1310 1210 3740
Moz 1540 1590 3680
Op 3070 3090 6100

../rh
Jul 23 '05 #24

P: n/a
rh
Lasse Reichstein Nielsen wrote:
I though of another version, that used bit operations instead
of arithmetics (if I can't have an array, I can still code one
into an integer :)
---
function LastOfMonthBitArray(y,m) {
return 28 + (((0xeefbb3>>(m<<1))&3) ||
!((y&3)||((y&15)&&!(y%25))) );
}
---


And with yet another slightly different approach, and beating this
thing to death :), there's also:

function LastOfMonth4(y, m) {
return 31 + (m&8&&m&1||!(m&8||m&1)||!(m-7))
-(!!--m||2+(!!((y&3)||y&15&&!(y%25))));
}

and:

function LastOfMonth5(y, m) {
return 28 + (m&8&&m&1||!(m&8||m&1)||!(m-7))
+ (!!--m<<1||!((y&3)||((y&15)&&!(y%25))));
Not too surprisingly, both are slower than the integer bit-shift
lookup above. While the first of these seems to perform fine across
browsers, the latter is particulaly slow on Netscape/Mozilla.

../rh
Jul 23 '05 #25

P: n/a
rh
Lasse Reichstein Nielsen wrote:
I though of another version, that used bit operations instead
of arithmetics (if I can't have an array, I can still code one
into an integer :)
---
function LastOfMonthBitArray(y,m) {
return 28 + (((0xeefbb3>>(m<<1))&3) ||
!((y&3)||((y&15)&&!(y%25))) );
}
---
Not to be so easily outdone, and after mulling it a bit (yes, of
course that's a pun), I submit the following alternative bit-masher's
dream:

function LastOfMonth6(y, m) {
return 29 +(m!=1||-!!(y&3||y&15&&!(y%25)))+(++m>>3^m&1);
}
How efficient it is varies between browsers.


Similarly, although it appears that LastOfMonthBitArray still edges
out LastOfMonth6, but not by much.

By the way, I did find in doing timings that Opera perfomance degrades
as execution proceeds in a triple test sequence, where the other
broswers don't, and therefore the last in the sequence in Opera always
compares very poorly (as per my earlier performance table).

Regards,

../rh
Jul 23 '05 #26

P: n/a
rh wrote:
<snip>
function LastOfMonth6(y, m) {
return 29 +(m!=1||-!!(y&3||y&15&&!(y%25)))+(++m>>3^m&1);
}
How efficient it is varies between browsers.

<snip>

I like the - (((++mm>>3)^m)&1) - logic. I observe that the number 30 is
binary - 11110 -, so - 30|((++m>>3)^m) - will be correct for all months
except February. Avoiding the - &1 - to mask out all but the low bit, as
the 4 set bits in 30 will negate the higher bits in - m -. Possibly:-

function LastOfMonth6b(y, m) {
return ((m!=1)&&(30|((++m>>3)^m)))||( 28+!((y&3)||((y&15)&&!(y%25))));
}

- not speed tested.

Richard.
Jul 23 '05 #27

P: n/a
rh
"Richard Cornford" wrote:

<..>
I like the - (((++mm>>3)^m)&1) - logic. I observe that the number 30 is
binary - 11110 -, so - 30|((++m>>3)^m) - will be correct for all months
except February. Avoiding the - &1 - to mask out all but the low bit, as
the 4 set bits in 30 will negate the higher bits in - m -. Possibly:-

function LastOfMonth6b(y, m) {
return ((m!=1)&&(30|((++m>>3)^m)))||( 28+!((y&3)||((y&15)&&!(y%25))));
}


And I like the innovation. By virtue of the same, it could also be
written as:

function LastOfMonth6c(y, m) {
return 28|(((m!=1)&&(2|((++m>>3)^m)))||((!((y&3)||((y&15) &&!(y%25))))));
}

While it's consistent, it undoes some of your added advantage on the
speed side. So I tested LastOfMonth6b and:

function LastOfMonth6d(y, m) {
return ((m!=1)&&(++m>>3^m|30))||(!((y&3)||((y&15)&&!(y%25 ))))|28;
}

which I found to be faster than LastOfMonth6b in all but IE.

Alas, that wascally Lasse still has it in all but Netscape, but thanks
to your help I find it's by a barely perceptible amount now in the
others. :)

../rh
Jul 23 '05 #28

This discussion thread is closed

Replies have been disabled for this discussion.