Разница дат в Javascript (игнорирование времени суток)
Я пишу заявку на аренду оборудования, где клиенты взимают плату за аренду оборудования в зависимости от продолжительности (в днях) аренды. Итак, в основном, (ежедневная плата * количество дней) = общая плата.
для мгновенной обратной связи на стороне клиента я пытаюсь использовать 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 ответов:
Если вы хотите целые дни для вашего примера аренды камеры студента ...
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); }
У меня просто была эта проблема, и я решил ее после нахождения этого вопроса, поэтому я вернулся, чтобы опубликовать это. Это позволит получить общее количество дней, независимо от времени. И 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, которая даже не знает о времени исходных дат.
то, что я бы сделал, это установить два раза даты в одно и то же время. Например, установить время конца дня до 12:00 часов времени и StartDate до 12:00 утра также. Тогда получите разницу между ними.
на стороне Примечание, так как я тоже в индустрии аренды оборудования программного обеспечения, кажется, что вы теряете доход от аренды, не считая часов. В вашем примере, если кто-то взял оборудование 6 июля в 6 утра и вернул его 7 июля в 10 вечера. У них было два дня, чтобы использовать оборудование и, возможно, несут избыточную плату за метр тоже...
в данных решениях есть ошибка!
Это относится к различиям дат, где время игнорируется, и вы хотите получить целочисленный результат, то есть целое число дней.
во многих примерах выше мы видим математику.пол других экземпляров я видел математику.подшить других местах. Это делается для округления результата до целого числа дней. Проблема в том, что летнее время даст неправильный результат осенью, используя математику.Сэл-ваш результат будет один день слишком большой или весной, если вы используете математику.пол у вас будет на один день слишком мало. Просто используйте математику.круглый, потому что 1 час в любом случае не будет искажать результат.
function dateDiff(dateEarlier, dateLater) { var one_day=1000*60*60*24 return ( Math.round((dateLater.getTime()-dateEarlier.getTime())/one_day) ); }
Я бы также предложил взглянуть на невероятное момент.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()
для преобразования в нормализованный часовой пояс.
поскольку Юлианский день фактически является числом дней (а в некоторых случаях и долей числа дней) с определенной даты, он практически совпадает с меткой времени UNIX, представленной по-разному. Вы можете получить количество целых дней с 1970 года вот так:
Date.prototype.getWholeDays = function () { return Math.floor(new Date() / 1000*60*60*24); }; function dateDiff(startDate, endDate) { return endDate.getWholeDays() - startDate.getWholeDays(); }
Если вы хотите только разницу в днях, обязательно используйте UTC (GMT) или вычитание не будет производить целое число дней в секундах, если летнее время начинается или заканчивается в течение интервала.
я использовал для проверки результата функции 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; }
вы можете настроить дату начала до полуночи того же дня, а затем рассчитать количество 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); }
используйте метод 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; }
чтобы получить полные дни интервал дат в течение летнего времени меняет пол (дни) должны быть заменены на круглые. В противном случае это очень полезная функция.
+в приведенном выше примере, который использует конструкторы UTC. Не делая этого, вы будете забиты летними / летними часами.
Если вы возьмете различия в некоторых из них, он может оказаться на час короче при пересечении линии DST для вашего часового пояса в одном направлении (spring-forward, то есть в феврале, например, в апреле). Когда вы этаж N+23/24, вы будете в конечном итоге с N.
другое направление (в октябре просят за декабрь) должно быть хорошо, вы будете в конечном итоге на час вперед, который пол () будет иметь дело с правильно.
просто из любопытства:
Если вы можете утверждать, что результат будет всегда быть
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.
дата нужна.js,http://code.google.com/p/datejs/
функция 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); }
Я знаю, что это частичное решение, но вы можете быть в состоянии получить дней между датами (пока времени не было времени установить). Тогда вы можете работать оттуда.
я основываю это решение с проблемой, которую вы представили ((ежедневная плата * количество дней) = общая плата); не фактический вопрос о разнице дат. Это должно помочь вам.
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))); };