Вопрос по javascript, date – Разница в дате в Javascript (без учета времени суток)

52

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

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

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

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

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

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

<code>function dateDiff2(startDate, endDate) {
    return endDate.getDate() - startDate.getDate();
}
</code>

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

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

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

Каждое одно из этих решений неверно, если оборудование выписано и возвращено в тот же день. Вы, вероятно, хотитеdiff = Math.max(1, diff) где-то в вашем коде, если вы не предлагаете бесплатную аренду в тот же день! :] Noyo

Ваш Ответ

15   ответов
1

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

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

.

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);
}
Для учета / разрешения отрицательных чисел, поменяйте местамиMath.floor() для условного утверждения:return second > first ? Math.floor(days) : Math.ceil(days); garromark
Решением является использование Math.round вместо ceil / floor. spekdrum
Не забывайте вызывать Math.abs () перед Math.floor (), если может случиться, что «первое» произойдет раньше, чем «второе». Maarten
не забудь это: En.wikipedia.org / вики / Daylight_saving_time Daniel
Согласитесь, используяMath.floor вызовет ошибку, если вы находитесь в часовом поясе, например Бразилиа, где DST заканчивается в полночь. Есть два возможных решения: 1) ИспользованиеMath.roundместо @ или 2) всегда используйтеDate.UTC непосредственно для расчета, как это сделано в шерифпониирешени. Noyo
3

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

18

и я решил ее после того, как нашел этот вопрос, поэтому я вернулся, чтобы опубликовать это. Это получит общее количество дней независимо от времени. И 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, которая даже не знает о времени исходных дат.

Использовал и этот подход - нужно было определить количество дней между двумя датами. Это был самый простой вариант без питания для времени и пола / потолка. Vlad
10

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

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

Почему этот ответ помечен правильно, когда он не решает вторую часть вопроса, т.е. когда даты в отдельных месяцах? Mark Simpson
Неплохо подмечено. Мы - студенческая телестанция, поэтому арендные платы больше поощряют разумную продолжительность аренды, чем получение прибыли. Мы берем за камеру около 5 долларов в ден Alan
10

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

Во многих приведенных выше примерах мы видим 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)  );
}
Я думаю, что ОП хочет, чтобы 1 января 23:59 и 2 января 00:01 имели разницу в 1 день. Maarten
7

Я бы также посоветовал взглянуть на невероятное 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() для преобразования в нормализованный часовой пояс.

@ SalmanHasratKhan Хороший вопрос - если вы не используете.clone тогда библиотека момента изменит базовый объект даты. Brian M. Hunt
Почему вы использовали clone () перед вызовом startOf ()? Salman Hasrat Khan
6

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

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

function dateDiff(startDate, endDate) {
    return endDate.getWholeDays() - startDate.getWholeDays();
}
Я не думаю, что это сработало бы, если бы startDate и endDate были в течение 24 часов друг от друга. Например. если startDate - 11:30 вечера 6 июля, а endDate - 12:30 утра 7 июля, разве это не округляется до 0? (крайний пример, конечно, но все еще актуальная проблема). Alan
Ты прав, я изменил это сейчас. Blixt
2

чтобы проверить результат функции 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

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

function dateDiff(startDate, endDate) {
    // set startDate to the beginning of the day
    startDate = new Date(
        startDate.getFullYear(),
        startDate.getMonth(),
        startDate.getDate());

    return Math.floor((endDate - startDate) / 1000*60*60*24);
}
1

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

0

+ вверх пример выше, который использует конструкторы UTC..

Если вы возьмете различия в некоторых из них, это может привести к сокращению на час при пересечении линии DST для вашего часового пояса в одном направлении (весной вперед, то есть, например, в феврале с запросом на апрель). Когда вы наберете N + 23/24, вы получите N.

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

0

Если ты можешь утверждать, что результат будетВСЕГД быть <31 дней, то решение также следующее:

var deltaDays = new Date(endDate - startDate).getDate()-1

Зачем

Разложим предыдущую строку:

var msecs = endDate - startDate; // difference in milliseconds
var dt = new Date(msecs); // will give us a date object pointing to a time 
                          // somewhere in Jan 1970 (given the precondition above)
var days = dt.getDate();  // Take the day part of it
var deltaDays = days - 1; // since the numbering starts from 1, we have to 
                          // substract 1 (Ex. if the diff in msecs is 0. The
                          // Date will point to 1st of Jan 1970)

Но, очевидно, ты долженН используйте его, если ваши результаты могут быть> 31.

0

http: //code.google.com/p/datejs

function CalculateDuration (startDate, endDate)

var sdt = Date.parse(startDate);
var edt = Date.parse(endDate);

var sdtYear = sdt.getYear();
var edtYear = edt.getYear();
var sdtMonth = sdt.getMonth();
var edtMonth = edt.getMonth();
var sdtDay = sdt.getDate();
var edtDay = edt.getDate();

var StartDateMonthDays = Date.getDaysInMonth(sdtYear, sdtMonth);
var EndDateMonthDays = Date.getDaysInMonth(edtYear, edtMonth);

if (edtMonth < sdtMonth) { //Means the ending month is earlier, which invalidates the operation

    alert("Ending month cannot be earlier than the starting month")

}

//Months are equal, if month is the next month of the start date month, 
//the operation fails, thus we need to calculate month difference first
else if (edtMonth > sdtMonth) {

    //Need to count how many days are left to finish the month
    var daysToMonthFinish = StartDateMonthDays - sdtDay;
    var calculatedDuration = daysToMonthFinish + edtDay;
    $("#hdn_duration").val(calculatedDuration);

}
//If months are the same, it is safe to just calculate the end day minus the start day
else {

    var calcDuration = edtDay - sdtDay;
    $("#hdn_duration").val(calcDuration);
}
0

что это частичное решение, но вы можете получить дни между датами (если даты не установлены). Тогда вы можете работать оттуда.

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

var Main = function() {
    var startDate = new Date('08/20/2014');
    var endDate = new Date('08/22/2014');
    var totalCharge = monthlyFee * daysBetween(startDate, endDate);
}

var daysBetween = function(startDate, endDate) {
    return Math.round(Math.abs((startDate.getTime() - endDate.getTime())/(24*60*60*1000)));
};

Похожие вопросы