Validate number of days in a given month

前端 未结 13 2132
独厮守ぢ
独厮守ぢ 2021-01-31 18:14

Performance is of the utmost importance on this one guys... This thing needs to be lightning fast!


How would you validate the number of days in a given mont

相关标签:
13条回答
  • 2021-01-31 18:38

    I'm mostly agreeing w/ Moayad. I'd use a table lookup, with an if check on February and the year.

    pseudocode:

    Last_Day = Last_Day_Of_Month[Month];
    Last_Day += (Month == February && Leap_Year(Year)) ? 1 : 0;
    

    Note that Leap_Year() can't be implemented simply as (Year % 4 == 0), because the rules for leap years are way more complex than that. Here's an algorithm cribbed from Wikipedia

    bool Leap_Year (int year) {
       return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
    }
    
    0 讨论(0)
  • 2021-01-31 18:39
    function daysInMonth(m, y) { // m is 0 indexed: 0-11
        switch (m) {
            case 1 :
                return (y % 4 == 0 && y % 100) || y % 400 == 0 ? 29 : 28;
            case 8 : case 3 : case 5 : case 10 :
                return 30;
            default :
                return 31
        }
    }
    
    function isValid(d, m, y) {
        return m >= 0 && m < 12 && d > 0 && d <= daysInMonth(m, y);
    }
    
    0 讨论(0)
  • 2021-01-31 18:40

    The days of each month are known easily by exception of February for detail of leap years:

    I leave an implementation based on the algorithm that solves this problem:

    Algorithm

    if (year is not divisible by 4) then (it is a common year)
    else if (year is not divisible by 100) then (it is a leap year)
    else if (year is not divisible by 400) then (it is a common year)
    else (it is a leap year)
    
    • More info: https://en.wikipedia.org/wiki/Leap_year#Algorithm

    Implementation in Javascript

    /**
     * Doc: https://en.wikipedia.org/wiki/Leap_year#Algorithm
     * param : month is indexed: 1-12
     * param: year
     **/
    		function daysInMonth(month, year) {
    			switch (month) {
    				case 2 : //Febrary
    					if (year % 4) {
    						return 28; //common year
    					}
    					if (year % 100) {
    						return 29; //  leap year
    					}
    					
    					if (year % 400) {
    						return 28; //common year
    					}
    					return 29; //  leap year
    				case 9 : case 4 : case 6 : case 11 :
    					return 30;
    				default :
    					return 31
    			}
    		}
        
        /** Testing daysInMonth Function **/
        $('#month').change(function() {
            var mVal = parseInt($(this).val());
            var yVal = parseInt($('#year').val());
            $('#result').text(daysInMonth(mVal, yVal));
        });
        
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    
    <label>Year</label>
    <input type='number' id='year' min='1000' max='2500'>
    
    <label>month</label>
    <input type='number' id='month' min='1' max='12'>
    <h1>
       days: <span id='result' style='color:#E650A0'></span>
    </h1>

    0 讨论(0)
  • 2021-01-31 18:43

    I've been doing this using the Date object (assuming it's compiled, and hence blindingly fast compared to scripting).

    The trick is that if you enter a too high number for the date part, the Date object wraps over into the next month. So:

    var year = 2009;
    var month = 1;
    var date = 29;
    
    var presumedDate = new Date(year, month, date);
    
    if (presumedDate.getDate() != date)
        WScript.Echo("Invalid date");
    else
        WScript.Echo("Valid date");
    

    This will echo "Invalid date" because presumedDate is actually March 1st.

    This leaves all the trouble of leap years etc to the Date object, where I don't have to worry about it.

    Neat trick, eh? Dirty, but that's scripting for you...

    0 讨论(0)
  • 2021-01-31 18:47

    If the month isn't February, get the number from the array. Otherwise, check if the year is leap to return 29, or return 28. Is there a problem with that?

    0 讨论(0)
  • 2021-01-31 18:47

    In computer terms, new Date() and regular expression solutions are slow! If you want a super-fast (and super-cryptic) one-liner, try this one (assuming m is in Jan=1 format):

    The only real competition for speed is from @GitaarLab, so I have created a head-to-head JSPerf for us to test on: http://jsperf.com/days-in-month-head-to-head/5

    I keep trying different code changes to get the best performance.

    Current version

    After looking at this related question Leap year check using bitwise operators (amazing speed) and discovering what the 25 & 15 magic number represented, I have come up with this optimized hybrid of answers:

    function getDaysInMonth(m, y) {
        return m===2 ? y & 3 || !(y%25) && y & 15 ? 28 : 29 : 30 + (m+(m>>3)&1);
    }
    

    JSFiddle: http://jsfiddle.net/TrueBlueAussie/H89X3/22/

    JSPerf results: http://jsperf.com/days-in-month-head-to-head/5

    For some reason, (m+(m>>3)&1) is more efficient than (5546>>m&1) on almost all browsers.


    It works based on my leap year answer here: javascript to find leap year this answer here Leap year check using bitwise operators (amazing speed) as well as the following binary logic.

    A quick lesson in binary months:

    If you interpret the index of the desired months (Jan = 1) in binary you will notice that months with 31 days either have bit 3 clear and bit 0 set, or bit 3 set and bit 0 clear.

    Jan = 1  = 0001 : 31 days
    Feb = 2  = 0010
    Mar = 3  = 0011 : 31 days
    Apr = 4  = 0100
    May = 5  = 0101 : 31 days
    Jun = 6  = 0110
    Jul = 7  = 0111 : 31 days
    Aug = 8  = 1000 : 31 days
    Sep = 9  = 1001
    Oct = 10 = 1010 : 31 days
    Nov = 11 = 1011
    Dec = 12 = 1100 : 31 days
    

    That means you can shift the value 3 places with >> 3, XOR the bits with the original ^ m and see if the result is 1 or 0 in bit position 0 using & 1. Note: It turns out + is slightly faster than XOR (^) and (m >> 3) + m gives the same result in bit 0.

    JSPerf results: http://jsperf.com/days-in-month-perf-test/6

    0 讨论(0)
提交回复
热议问题