Подтвердить что ты не робот

Подтвердить количество дней в данном месяце

Производительность имеет первостепенное значение для этих парней... Эта вещь должна быть молниеносной!





Как бы вы проверили количество дней в данном месяце?

Моя первая мысль заключалась в том, чтобы создать массив, содержащий дни данного месяца, с индексом, представляющим месяц:

var daysInMonth = [
    31, // January
    28, // February
    31, // March
    etc.
];

И затем сделайте что-то по строкам:

function validateDaysInMonth(days, month)
{
    if (days < 1 || days > daysInMonth[month]) throw new Error("Frack!");
}

Но... Как насчет високосных лет? Как я могу реализовать проверку на високосные годы и поддерживать быстродействие функции?





Обновление:. Я бы хотел, чтобы вы, ребята, показали мне код, который выполняет дни проверки на месяц-високосный год.

Здесь блок-схема, описывающая используемую сегодня логику:

http://visualbasic.about.com/library/graphics/dykleapyr1-1.gif

4b9b3361

Ответ 1

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);
}

Ответ 2

Я делаю это с использованием объекта Date (при условии, что он скомпилирован и, следовательно, ослепительно быстрый по сравнению со сценарием).

Фокус в том, что если вы вводите слишком большое число для части даты, объект Date переносится в следующий месяц. Итак:

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");

Это будет означать "Недействительная дата", потому что presumedDate на самом деле 1 марта.

Это оставляет все проблемы високосных годов и т.д. объекту Date, где мне не нужно беспокоиться об этом.

Аккуратный трюк, а? Грязный, но для вас сценарий...

Ответ 3

Если месяц не в феврале, получите номер из массива. В противном случае проверьте, является ли год прыжком, чтобы вернуть 29, или верните 28. Есть ли проблема с этим?

Ответ 4

Это не будет работать так же, как и принятый ответ. Я бросил это здесь, потому что я думаю, что это самый простой код. Большинство людей не нуждаются в оптимизации этой функции.

function validateDaysInMonth(year, month, day)
{
    if (day < 1 || day > 31 || (new Date(year, month, day)).getMonth() != month)
        throw new Error("Frack!");
}

Он использует тот факт, что конструктор даты javascript будет выполнять арифметику даты в датах, которые находятся за пределами допустимого диапазона, например:

var year = 2001; //not a leap year!
var month = 1 //February
var day = 29; //not a valid date for this year
new Date(year, month, day);

объект вернется 1 марта 2001 года в качестве даты.

Ответ 5

Moment.js

Вы пробовали moment.js?

проверка довольно проста в использовании:

var m = moment("2015-11-32");
m.isValid(); // false

Я не знаю о спектаклях, но гул, проект смотрится 11 000 + раз на GitHub (вид гарантии качества).

Источник: http://momentjs.com/docs/#/parsing/is-valid/

Ответ 6

Я в основном соглашаюсь с Moayad. Я бы использовал поиск в таблице, с проверкой на февраль и год.

псевдокод:

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

Обратите внимание, что Leap_Year() не может быть реализован просто как (Year % 4 == 0), потому что правила для високосных годов являются более сложными. Здесь приведен алгоритм из Википедии

bool Leap_Year (int year) {
   return ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0);
}

Ответ 8

Я согласен с Moayad и TED. Придерживайтесь таблицы поиска, если месяц не февраль. Если вам нужен алгоритм проверки високосных лет, wikipedia имеет два:

if year modulo 400 is 0 then leap
 else if year modulo 100 is 0 then no_leap
 else if year modulo 4 is 0 then leap
 else no_leap

A more direct algorithm (terms may be grouped either way):

function isLeapYear (year):
 if ((year modulo 4 is 0) and (year modulo 100 is not 0)) or (year modulo 400 is 0)
  then true
 else false

Ответ 9

вся эта логика уже встроена в механизм javascript... Зачем это перекодировать? Если вы не делаете это как упражнение, вы можете использовать объект Date javascript:

Вот так:

function daysInMonth(aDate) {
      return new Date(aDate.getYear(), aDate.getMonth()+1, 0).getDate();      
   }

Ответ 10

Предполагая, что стандарт объекта JS Date, где месяцы пронумерованы от 0, и у вас есть свой массив daysInMonth:

var days = daysInMonth[month] + ((month === 1) && (year % 4 === 0) && ((year % 100 !== 0) || (year % 400 === 0)));

даст вам количество дней в месяце, при этом 28 увеличатся до 29, если месяц - февраль, а год - високосный год.

Ответ 11

Вы можете использовать DateTime, чтобы решить эту проблему:

new DateTime('20090901')->format('t'); // gives the days of the month

Ответ 12

В компьютерных терминах решения new Date() и regular expression медленны! Если вы хотите супер-быстрый (и супер-критический) однострочный, попробуйте этот (если m находится в формате Jan=1):

Единственная реальная конкуренция за скорость - от @GitaarLab, поэтому я создал JSPerf для головы для тестирования: http://jsperf.com/days-in-month-head-to-head/5

Я продолжаю пробовать разные изменения кода, чтобы получить лучшую производительность.

Текущая версия

Посмотрев на этот связанный вопрос проверку високосного года с помощью побитовых операторов (удивительная скорость) и узнав, что представляет собой 25 и 15 магическое число, я придумал это оптимизированный гибрид ответов:

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: http://jsperf.com/days-in-month-head-to-head/5

По какой-то причине (m+(m>>3)&1) более эффективен, чем (5546>>m&1) почти во всех браузерах.


Он работает на основе моего високосного года здесь: javascript, чтобы найти високосный год этот ответ здесь Високосный год с использованием побитового операторы (удивительная скорость), а также следующая двоичная логика.

Быстрый урок в двоичных месяцах:

Если вы интерпретируете индекс желаемых месяцев (Jan = 1) в двоичном формате, вы заметите, что месяцы с 31 днем ​​либо имеют бит 3, либо бит, либо бит 0, либо бит 3 установлен, а бит 0 очищен.

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

Это означает, что вы можете сдвинуть значение 3 места с помощью >> 3, XOR битов с исходным ^ m и посмотреть, есть ли результат 1 или 0 в позиции бита 0 с помощью & 1. Примечание. Оказывается, + немного быстрее, чем XOR (^), а (m >> 3) + m дает тот же результат в бит 0.

Результаты JSPerf: http://jsperf.com/days-in-month-perf-test/6