Разница в дате в Javascript (без учета времени суток) - PullRequest
53 голосов
/ 24 июня 2009

Я пишу заявку на аренду оборудования, в которой с клиентов взимается плата за аренду оборудования в зависимости от срока аренды (в днях). Таким образом, в основном, (ежедневная плата * количество дней) = общая стоимость.

Для мгновенной обратной связи на стороне клиента я пытаюсь использовать Javascript, чтобы выяснить разницу в двух календарных датах. Я искал вокруг, но ничего, что я нашел, не совсем то, что я ищу. Большинство решений, которые я видел, имеют вид:

function dateDiff1(startDate, endDate) {
    return ((endDate.getTime() - startDate.getTime()) / 1000*60*60*24);
}

Моя проблема в том, что оборудование можно проверить и вернуть в в любое время суток в течение этих двух дат без дополнительной оплаты. Приведенный выше код рассчитывает количество 24-часовых периодов между двумя датами, когда меня действительно интересует количество календарных дней.

Например, если кто-то проверил оборудование в 6 часов утра 6 июля и вернул его в 10 часов вечера 7 июля, приведенный выше код вычислит, что прошло более одного 24-часового периода, и вернет 2. Желаемый результат равен 1 , поскольку истекла только одна календарная дата (т.е. с 6-го по 7-е).

Наиболее близким решением, которое я нашел, является эта функция:

function dateDiff2(startDate, endDate) {
    return endDate.getDate() - startDate.getDate();
}

, который делает именно то, что я хочу, если эти две даты находятся в одном месяце. Однако, поскольку getDate () возвращает только день месяца (т. Е. 1-31), он не работает, если даты охватывают несколько месяцев (например, с 31 июля по 1 августа - 1 день, а в приведенном выше примере 1 - 31 или -29).

В бэкэнде в PHP я использую gregoriantojd (), который, кажется, работает нормально (см. этот пост для примера). Я просто не могу найти эквивалентное решение в Javascript.

У кого-нибудь есть идеи?

Ответы [ 15 ]

46 голосов
/ 20 марта 2010

Если вы хотите целые дни для примера проката камеры вашего студента ...

function daysBetween(first, second) {

    // Copy date parts of the timestamps, discarding the time parts.
    var one = new Date(first.getFullYear(), first.getMonth(), first.getDate());
    var two = new Date(second.getFullYear(), second.getMonth(), second.getDate());

    // Do the math.
    var millisecondsPerDay = 1000 * 60 * 60 * 24;
    var millisBetween = two.getTime() - one.getTime();
    var days = millisBetween / millisecondsPerDay;

    // Round down.
    return Math.floor(days);
}
19 голосов
/ 31 мая 2012

У меня была эта проблема, и я решил ее после того, как нашел этот вопрос, поэтому я вернулся, чтобы опубликовать это. Это получит общее количество дней независимо от времени. И DST не испортил это:

date1 = Date.UTC(date1.getFullYear(), date1.getMonth(), date1.getDate());
date2 = Date.UTC(date2.getFullYear(), date2.getMonth(), date2.getDate());
var ms = Math.abs(date1-date2);
return Math.floor(ms/1000/60/60/24); //floor should be unnecessary, but just in case

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

10 голосов
/ 31 октября 2011

В данных решениях есть ошибка!

Это относится к разнице дат, когда время не учитывается И вы хотите получить целочисленный результат, то есть целое число дней.

Во многих приведенных выше примерах мы видим Math.floor в других случаях, где я видел Math.ceil и в других местах. Это делается для округления результата до целого числа дней. Проблема в том, что летнее время даст неверный результат осенью при использовании Math.ceil - ваш результат будет на один день больше или весной, если вы будете использовать Math.floor, вы будете на один день меньше. Просто используйте Math.round, потому что 1 час в любом случае не повлияет на результат.

function dateDiff(dateEarlier, dateLater) {
    var one_day=1000*60*60*24
    return (  Math.round((dateLater.getTime()-dateEarlier.getTime())/one_day)  );
}
10 голосов
/ 24 июня 2009

То, что я хотел бы сделать, это установить для двух дат одинаковое время. Например, установите время endDate на 12:00 и время startDate на 12:00. Тогда получите разницу между ними.

Кстати, поскольку я тоже занимаюсь производством программного обеспечения для аренды, кажется, что вы теряете доход от аренды, не считая часов. По вашему примеру, если кто-то забрал оборудование 6 июля в 6 утра и вернул его 7 июля в 10 вечера. У них было два полных дня, чтобы использовать оборудование и, возможно, получить дополнительную плату за счет счетчика ...

7 голосов
/ 20 марта 2013

Я бы также посоветовал взглянуть на невероятную библиотеку moment.js . Он имеет универсальную функцию diff, которую можно использовать для решения приведенного выше примера следующим образом:

function is_same_date(startDate, endDate) {
   var startMoment = moment(startDate).clone().startOf('day'),
       endMoment = moment(endDate).clone().startOf('day');
   return startMoment.diff(endMoment, 'days') == 0;
}

Вот несколько примеров использования moment.js diff:

> d1 = new Date(2012,04,04,0,0)
Fri May 04 2012 00:00:00 GMT-0400 (EDT)

> d2 = new Date(2012,04,03,23,0)
Thu May 03 2012 23:00:00 GMT-0400 (EDT)

> d3 = new Date(2012,04,05,23,0)
Sat May 05 2012 23:00:00 GMT-0400 (EDT)

> moment(d2).diff(d1, 'days')
0

> moment(d1).diff(d2, 'days')
0

> moment(d1).diff(d3, 'days') // uh oh. this is why we use `startOf`
-2

> moment(d2).diff(d3, 'days')
-2

> moment(d3).startOf('day') // this modified d3, sets the time to 00:00:00.0000
> d3
Sat May 05 2012 00:00:00 GMT-0400 (EDT)

Если часовые пояса имеют значение, вы также можете использовать moment.utc() для преобразования в нормализованный часовой пояс.

6 голосов
/ 24 июня 2009

Поскольку юлианский день - это фактически количество дней (а в некоторых случаях и доля числа дней) с определенной даты, он практически совпадает с меткой времени UNIX, представленной по-другому. Вы можете получить количество целых дней с 1970 года примерно так:

Date.prototype.getWholeDays = function () {
    return Math.floor(new Date() / 1000*60*60*24);
};

function dateDiff(startDate, endDate) {
    return endDate.getWholeDays() - startDate.getWholeDays();
}
3 голосов
/ 01 марта 2011

Если вам нужна разница только в днях, обязательно используйте UTC (GMT), иначе вычитание не даст целое число дней в секундах, если летнее время начинается или заканчивается в течение интервала.

2 голосов
/ 04 октября 2012

Я использовал для проверки результата функцию datediff, которая использует .getTime () с Excel для 18-го века. Результат возвращается правильно. У меня есть другой метод для расчета разных дней:

    function DaysOfYear(nYear) {
        if ((nYear % 4) == 0) {
            return 366;
        }
        else {
            return 365;
        }
    }


    function DiffDays(fDate, tDate) {
        var fYear = fDate.getFullYear();
        var tYear = tDate.getFullYear();
        var fMonth = fDate.getMonth();
        var tMonth = tDate.getMonth();
        var fDay = fDate.getDate();
        var tDay = tDate.getDate();
        var nDays = 0;

        if (tYear > fYear) {   // different year
            // remain days of from year
            nDays = DaysOfYear(fYear) - YTD_Days(fDate);
            // days of between fYear to tYear
            for (y = (fYear + 1); y < tYear; y++) {
                nDays = nDays + DaysOfYear(y);
            }
            // days from the beginning of tYear
            nDays = nDays + YTD_Days(tDate);
        }
        else {   // in the same year
            nDays = YTD_Days(tDate) - YTD_Days(fDate);
        };
        return nDays;
    }

    function YTD_Days(dDate) {
        var y = dDate.getFullYear();
        var m = dDate.getMonth();
        var nDays = 0

        for (i = 0; i < m; i++) {
            switch (i) {
                case 0:     // January
                    nDays = nDays + 31;
                    break;
                case 1:     // February
                    if ((y % 4) == 0) {
                        nDays = nDays + 29;
                    }
                    else {
                        nDays = nDays + 28;
                    };
                    break;
                case 2:     // March
                    nDays = nDays + 31;
                    break;
                case 3:     // April
                    nDays = nDays + 30;
                    break;
                case 4:     // May
                    nDays = nDays + 31;
                    break;
                case 5:     // June
                    nDays = nDays + 30;
                    break;
                case 6:     // July
                    nDays = nDays + 31;
                    break;
                case 7:     // August
                    nDays = nDays + 31;
                    break;
                case 8:     // September
                    nDays = nDays + 30;
                    break;
                case 9:     // October
                    nDays = nDays + 31;
                    break;
                case 10:     // November
                    nDays = nDays + 30;
                    break;
                case 11:     // December
                    nDays = nDays + 31;
                    break;
            }
        }
        nDays = nDays + dDate.getDate();
        return nDays;
    }
1 голос
/ 08 июня 2012

Чтобы получить полные дни, интервал дат по летнему времени меняется, этаж (дни) должен быть заменен на раунд. В противном случае это очень полезная функция.

1 голос
/ 24 июня 2009

используйте метод setHours (), предполагая, что количество дней не может быть нулем:)

function dateDiff1(startDate, endDate) {
    endDate.setHours(0);
    startDate.setHours(0);
    //assuming days cannt be 0.

    var x = ((endDate.getTime() - startDate.getTime()) / 1000*60*60*24);
    if (x <1 && x>=0) {
        return 1;
    }
    return x;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...