Multiple datepicker

Discussion in 'Javascript' started by Simon Templar, Jul 22, 2004.

  1. 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
    Simon Templar, Jul 22, 2004
    #1
    1. Advertising

  2. 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 <>
    * @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
    Thomas 'PointedEars' Lahn, Jul 26, 2004
    #2
    1. Advertising

  3. JRS: In article <>, dated Mon, 26 Jul
    2004 06:28:55, seen in news:comp.lang.javascript, Thomas 'PointedEars'
    Lahn <> 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 <>


    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.
    Dr John Stockton, Jul 26, 2004
    #3
  4. Thomas 'PointedEars' Lahn <> 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 -
    DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
    'Faith without judgement merely degrades the spirit divine.'
    Lasse Reichstein Nielsen, Jul 26, 2004
    #4
  5. Simon Templar

    Mick White Guest

    Dr John Stockton wrote:

    > JRS: In article <>, dated Mon, 26 Jul
    > 2004 06:28:55, seen in news:comp.lang.javascript, Thomas 'PointedEars'
    > Lahn <> 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 <>

    >
    >
    > 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.
    >
    Mick White, Jul 26, 2004
    #5
  6. Dr John Stockton <> 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 -
    DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
    'Faith without judgement merely degrades the spirit divine.'
    Lasse Reichstein Nielsen, Jul 26, 2004
    #6
  7. JRS: In article <>, dated Mon, 26 Jul 2004
    19:02:04, seen in news:comp.lang.javascript, Lasse Reichstein Nielsen
    <> posted :
    >Thomas 'PointedEars' Lahn <> 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.
    Dr John Stockton, Jul 26, 2004
    #7
  8. Dr John Stockton <> 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 -
    DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html>
    'Faith without judgement merely degrades the spirit divine.'
    Lasse Reichstein Nielsen, Jul 27, 2004
    #8
  9. JRS: In article <>, dated Tue, 27 Jul 2004
    01:01:25, seen in news:comp.lang.javascript, Lasse Reichstein Nielsen
    <> posted :
    >Dr John Stockton <> 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 <>, dated Mon, 26 Jul 2004
    21:56:53, seen in news:comp.lang.javascript, Lasse Reichstein Nielsen
    <> 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.
    Dr John Stockton, Jul 27, 2004
    #9
  10. Simon Templar

    rh Guest

    Dr John Stockton <> wrote:

    > JRS: In article <>, dated Mon, 26 Jul 2004
    > 21:56:53, seen in news:comp.lang.javascript, Lasse Reichstein Nielsen
    > <> 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
    rh, Jul 28, 2004
    #10
  11. JRS: In article <>,
    dated Tue, 27 Jul 2004 19:42:56, seen in news:comp.lang.javascript, rh
    <> 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.
    Dr John Stockton, Jul 28, 2004
    #11
  12. Simon Templar

    rh Guest

    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
    rh, Jul 29, 2004
    #12
  13. 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.
    Richard Cornford, Jul 29, 2004
    #13
  14. Simon Templar

    Grant Wagner Guest

    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 <>
    comp.lang.javascript FAQ - http://jibbering.com/faq
    Grant Wagner, Jul 29, 2004
    #14
  15. Simon Templar

    Grant Wagner Guest

    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 <>
    comp.lang.javascript FAQ - http://jibbering.com/faq
    Grant Wagner, Jul 29, 2004
    #15
  16. 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.
    Richard Cornford, Jul 30, 2004
    #16
  17. Simon Templar

    rh Guest

    "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
    rh, Jul 30, 2004
    #17
  18. JRS: In article <>, dated
    Wed, 28 Jul 2004 21:41:15, seen in news:comp.lang.javascript, rh
    <> 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.
    Dr John Stockton, Jul 30, 2004
    #18
  19. 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.
    Richard Cornford, Jul 30, 2004
    #19
  20. JRS: In article <>, dated Thu, 29
    Jul 2004 20:36:12, seen in news:comp.lang.javascript, Grant Wagner
    <> 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.
    Dr John Stockton, Jul 30, 2004
    #20
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. TJS

    datepicker help needed

    TJS, Oct 29, 2003, in forum: ASP .Net
    Replies:
    2
    Views:
    522
  2. WJ
    Replies:
    2
    Views:
    1,551
    Ken Cox [Microsoft MVP]
    Nov 21, 2004
  3. flipdoubt

    DatePicker?

    flipdoubt, Aug 27, 2005, in forum: ASP .Net
    Replies:
    2
    Views:
    568
    John Rivers
    Aug 27, 2005
  4. Luqman
    Replies:
    1
    Views:
    1,120
    =?Utf-8?B?VEg=?=
    Feb 7, 2006
  5. Sunwest Technologies

    [ANN]Web DatePicker for JSP/Servlet 1.0 Released.

    Sunwest Technologies, Jun 7, 2004, in forum: Java
    Replies:
    0
    Views:
    2,080
    Sunwest Technologies
    Jun 7, 2004
Loading...

Share This Page