JavaScript 中以年、月、日为单位的两个日期之间的差异

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17732897/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 09:25:01  来源:igfitidea点击:

Difference between two dates in years, months, days in JavaScript

javascriptdatedatediff

提问by Chris

I've been searching for 4 hours now, and have not found a solution to get the difference between two dates in years, months, and days in JavaScript, like: 10th of April 2010 was 3 years, x month and y days ago.

我已经搜索了 4 个小时,但没有找到解决方案来获取 JavaScript 中两个日期之间的年、月和日差异,例如:2010 年 4 月 10 日是 3 年 x 月和 y 天前。

There are lots of solutions, but they only offer the difference in the format of either days OR months OR years, or they are not correct (meaning not taking care of actual number of days in a month or leap years, etc). Is it really that difficult to do that?

有很多解决方案,但它们仅提供天数或月数或年格式的差异,或者它们不正确(意味着不考虑一个月或闰年等中的实际天数等)。做到这一点真的有那么难吗?

I've had a look at:

我看过:

In php it is easy, but unfortunately I can only use client-side script on that project. Any library or framework that can do it would be fine, too.

在 php 中很容易,但不幸的是我只能在该项目中使用客户端脚本。任何可以做到这一点的库或框架也很好。

Here are a list of expected outputs for date differences:

以下是日期差异的预期输出列表:

//Expected output should be: "1 year, 5 months".
diffDate(new Date('2014-05-10'), new Date('2015-10-10'));

//Expected output should be: "1 year, 4 months, 29 days".
diffDate(new Date('2014-05-10'), new Date('2015-10-09'));

//Expected output should be: "1 year, 3 months, 30 days".
diffDate(new Date('2014-05-10'), new Date('2015-09-09'));

//Expected output should be: "9 months, 27 days".
diffDate(new Date('2014-05-10'), new Date('2015-03-09'));

//Expected output should be: "1 year, 9 months, 28 days".
diffDate(new Date('2014-05-10'), new Date('2016-03-09'));

//Expected output should be: "1 year, 10 months, 1 days".
diffDate(new Date('2014-05-10'), new Date('2016-03-11'));

回答by Pawel Miech

How precise do you need to be? If you do need to take into account common years and leap years, and the exact difference in days between months then you'll have to write something more advanced but for a basic and rough calculation this should do the trick:

你需要多精确?如果您确实需要考虑普通年份和闰年,以及月份之间天数的确切差异,那么您将不得不编写一些更高级的东西,但对于基本和粗略的计算,这应该可以解决问题:

today = new Date()
past = new Date(2010,05,01) // remember this is equivalent to 06 01 2010
//dates in js are counted from 0, so 05 is june

function calcDate(date1,date2) {
    var diff = Math.floor(date1.getTime() - date2.getTime());
    var day = 1000 * 60 * 60 * 24;

    var days = Math.floor(diff/day);
    var months = Math.floor(days/31);
    var years = Math.floor(months/12);

    var message = date2.toDateString();
    message += " was "
    message += days + " days " 
    message += months + " months "
    message += years + " years ago \n"

    return message
    }


a = calcDate(today,past)
console.log(a) // returns Tue Jun 01 2010 was 1143 days 36 months 3 years ago

Keep in mind that this is imprecise, in order to calculate the date with full precision one would have to have a calendar and know if a year is a leap year or not, also the way I'm calculating the number of months is only approximate.

请记住,这是不精确的,为了完全精确地计算日期,必须有一个日历并知道一年是否是闰年,而且我计算月数的方式也只是近似值.

But you can improve it easily.

但是你可以很容易地改进它。

回答by Inanc Gumus

Actually, there's a solution with a moment.js plugin and it's very easy.

实际上,有一个带有 moment.js 插件的解决方案,而且非常简单。

You might use moment.js

你可能会使用moment.js

Don't reinvent the wheel again.

不要再重新发明轮子了。

Just plug Moment.js Date Range Plugin.

只需插入Moment.js 日期范围插件



Example:

例子:

var starts = moment('2014-02-03 12:53:12');
var ends   = moment();

var duration = moment.duration(ends.diff(starts));

// with ###moment precise date range plugin###
// it will tell you the difference in human terms

var diff = moment.preciseDiff(starts, ends, true); 
// example: { "years": 2, "months": 7, "days": 0, "hours": 6, "minutes": 29, "seconds": 17, "firstDateWasLater":  false }


// or as string:
var diffHuman = moment.preciseDiff(starts, ends);
// example: 2 years 7 months 6 hours 29 minutes 17 seconds

document.getElementById('output1').innerHTML = JSON.stringify(diff)
document.getElementById('output2').innerHTML = diffHuman
<html>
<head>

  <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.14.1/moment.min.js"></script>

  <script src="https://raw.githubusercontent.com/codebox/moment-precise-range/master/moment-precise-range.js"></script>

</head>
<body>
  
  <h2>Difference between "NOW and 2014-02-03 12:53:12"</h2>
  <span id="output1"></span>
  <br />
  <span id="output2"></span>
  
</body>
</html>

回答by Rajeev P Nadig

I used this simple code to get difference in Years, Months, days with current date.

我使用这个简单的代码来获得年、月、日与当前日期的差异。

var sdt = new Date('1972-11-30');
var difdt = new Date(new Date() - sdt);
alert((difdt.toISOString().slice(0, 4) - 1970) + "Y " + (difdt.getMonth()+1) + "M " + difdt.getDate() + "D");

回答by Mordred

Modified this to be a lot more accurate. It will convert dates to a 'YYYY-MM-DD' format, ignoring HH:MM:SS, and takes an optional endDate or uses the current date, and doesn't care about the order of the values.

对此进行了修改,使其更加准确。它将日期转换为 'YYYY-MM-DD' 格式,忽略 HH:MM:SS,并采用可选的 endDate 或使用当前日期,并且不关心值的顺序。

function dateDiff(startingDate, endingDate) {
    var startDate = new Date(new Date(startingDate).toISOString().substr(0, 10));
    if (!endingDate) {
        endingDate = new Date().toISOString().substr(0, 10);    // need date in YYYY-MM-DD format
    }
    var endDate = new Date(endingDate);
    if (startDate > endDate) {
        var swap = startDate;
        startDate = endDate;
        endDate = swap;
    }
    var startYear = startDate.getFullYear();
    var february = (startYear % 4 === 0 && startYear % 100 !== 0) || startYear % 400 === 0 ? 29 : 28;
    var daysInMonth = [31, february, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];

    var yearDiff = endDate.getFullYear() - startYear;
    var monthDiff = endDate.getMonth() - startDate.getMonth();
    if (monthDiff < 0) {
        yearDiff--;
        monthDiff += 12;
    }
    var dayDiff = endDate.getDate() - startDate.getDate();
    if (dayDiff < 0) {
        if (monthDiff > 0) {
            monthDiff--;
        } else {
            yearDiff--;
            monthDiff = 11;
        }
        dayDiff += daysInMonth[startDate.getMonth()];
    }

    return yearDiff + 'Y ' + monthDiff + 'M ' + dayDiff + 'D';
}

Then you can use it like this:

然后你可以像这样使用它:

// based on a current date of 2019-05-10
dateDiff('2019-05-10'); // 0Y 0M 0D
dateDiff('2019-05-09'); // 0Y 0M 1D
dateDiff('2018-05-09'); // 1Y 0M 1D
dateDiff('2018-05-18'); // 0Y 11M 23D
dateDiff('2019-01-09'); // 0Y 4M 1D
dateDiff('2019-02-10'); // 0Y 3M 0D
dateDiff('2019-02-11'); // 0Y 2M 27D
dateDiff('2016-02-11'); // 3Y 2M 28D - leap year
dateDiff('1972-11-30'); // 46Y 5M 10D
dateDiff('2016-02-11', '2017-02-11'); // 1Y 0M 0D
dateDiff('2016-02-11', '2016-03-10'); // 0Y 0M 28D - leap year
dateDiff('2100-02-11', '2100-03-10'); // 0Y 0M 27D - not a leap year
dateDiff('2017-02-11', '2016-02-11'); // 1Y 0M 0D - swapped dates to return correct result
dateDiff(new Date() - 1000 * 60 * 60 * 24); // 0Y 0M 1D


Older less accurate but simpler version

较旧的不太准确但更简单的版本

@RajeevPNadig's answer was what I was looking for, but his code returns incorrect values as written. This is not very accurate because it assumes that the sequence of dates from 1 January 1970 is the same as any other sequence of the same number of days. E.g. it calculates the difference from 1 July to 1 September (62 days) as 0Y 2M 3D and not 0Y 2M 0D because 1 Jan 1970 plus 62 days is 3 March.

@RajeevPNadig 的回答正是我要找的,但他的代码返回的值不正确。这不是很准确,因为它假设从 1970 年 1 月 1 日开始的日期序列与具有相同天数的任何其他序列相同。例如,它将 7 月 1 日到 9 月 1 日(62 天)的差计算为 0Y 2M 3D 而不是 0Y 2M 0D,因为 1970 年 1 月 1 日加上 62 天是 3 月 3 日。

// startDate must be a date string
function dateAgo(date) {
    var startDate = new Date(date);
    var diffDate = new Date(new Date() - startDate);
    return ((diffDate.toISOString().slice(0, 4) - 1970) + "Y " +
        diffDate.getMonth() + "M " + (diffDate.getDate()-1) + "D");
}

Then you can use it like this:

然后你可以像这样使用它:

// based on a current date of 2018-03-09
dateAgo('1972-11-30'); // "45Y 3M 9D"
dateAgo('2017-03-09'); // "1Y 0M 0D"
dateAgo('2018-01-09'); // "0Y 2M 0D"
dateAgo('2018-02-09'); // "0Y 0M 28D" -- a little odd, but not wrong
dateAgo('2018-02-01'); // "0Y 1M 5D" -- definitely "feels" wrong
dateAgo('2018-03-09'); // "0Y 0M 0D"

If your use case is just date strings, then this works okay if you just want a quick and dirty 4 liner.

如果您的用例只是日期字符串,那么如果您只想要一个快速而肮脏的 4 班轮,这可以正常工作。

回答by Murray

I think you are looking for the same thing that I wanted. I tried to do this using the difference in milliseconds that javascript provides, but those results do not work in the real world of dates. If you want the difference between Feb 1, 2016 and January 31, 2017 the result I would want is 1 year, 0 months, and 0 days. Exactly one year (assuming you count the last day as a full day, like in a lease for an apartment). However, the millisecond approach would give you 1 year 0 months and 1 day, since the date range includes a leap year. So here is the code I used in javascript for my adobe form (you can name the fields): (edited, there was an error that I corrected)

我认为您正在寻找与我想要的相同的东西。我尝试使用 javascript 提供的毫秒差异来做到这一点,但这些结果在日期的现实世界中不起作用。如果您想要 2016 年 2 月 1 日和 2017 年 1 月 31 日之间的差异,我想要的结果是 1 年 0 个月和 0 天。整整一年(假设您将最后一天算作一整天,就像在公寓租约中一样)。但是,毫秒方法将为您提供 1 年 0 个月和 1 天,因为日期范围包括闰年。所以这是我在 javascript 中为我的 adobe 表单使用的代码(您可以命名字段):(已编辑,我更正了一个错误)

var f1 = this.getField("LeaseExpiration");
var g1 = this.getField("LeaseStart");


var end = f1.value
var begin = g1.value
var e = new Date(end);
var b = new Date(begin);
var bMonth = b.getMonth();
var bYear = b.getFullYear();
var eYear = e.getFullYear();
var eMonth = e.getMonth();
var bDay = b.getDate();
var eDay = e.getDate() + 1;

if ((eMonth == 0)||(eMonth == 2)||(eMonth == 4)|| (eMonth == 6) || (eMonth == 7) ||(eMonth == 9)||(eMonth == 11))

{
var eDays =  31;
}

if ((eMonth == 3)||(eMonth == 5)||(eMonth == 8)|| (eMonth == 10))

{
var eDays = 30;
}

if (eMonth == 1&&((eYear % 4 == 0) && (eYear % 100 != 0)) || (eYear % 400 == 0))
{
var eDays = 29;
}

if (eMonth == 1&&((eYear % 4 != 0) || (eYear % 100 == 0)))
{
var eDays = 28;
}


if ((bMonth == 0)||(bMonth == 2)||(bMonth == 4)|| (bMonth == 6) || (bMonth == 7) ||(bMonth == 9)||(bMonth == 11))

{
var bDays =  31;
}

if ((bMonth == 3)||(bMonth == 5)||(bMonth == 8)|| (bMonth == 10))

{
var bDays = 30;
}

if (bMonth == 1&&((bYear % 4 == 0) && (bYear % 100 != 0)) || (bYear % 400 == 0))
{
var bDays = 29;
}

if (bMonth == 1&&((bYear % 4 != 0) || (bYear % 100 == 0)))
{
var bDays = 28;
}


var FirstMonthDiff = bDays - bDay + 1;


if (eDay - bDay < 0)
{

eMonth = eMonth - 1;
eDay = eDay + eDays;

}

var daysDiff = eDay - bDay;

if(eMonth - bMonth < 0)
{
eYear = eYear - 1;
eMonth = eMonth + 12;
}

var monthDiff = eMonth - bMonth;

var yearDiff = eYear - bYear;

if (daysDiff == eDays)
{
daysDiff = 0;
monthDiff = monthDiff + 1;

if (monthDiff == 12)
{
monthDiff = 0;
yearDiff = yearDiff + 1;
}

}

if ((FirstMonthDiff != bDays)&&(eDay - 1 == eDays))

{
daysDiff = FirstMonthDiff;

}
event.value = yearDiff + " Year(s)" + " " + monthDiff + " month(s) " + daysDiff + " days(s)"

回答by Chris

For quick and easy use I wrote this function some time ago. It returns the diff between two dates in a nice format. Feel free to use it (tested on webkit).

为了快速方便地使用,我前段时间写了这个函数。它以一种很好的格式返回两个日期之间的差异。随意使用它(在 webkit 上测试)。

/**
 * Function to print date diffs.
 * 
 * @param {Date} fromDate: The valid start date
 * @param {Date} toDate: The end date. Can be null (if so the function uses "now").
 * @param {Number} levels: The number of details you want to get out (1="in 2 Months",2="in 2 Months, 20 Days",...)
 * @param {Boolean} prefix: adds "in" or "ago" to the return string
 * @return {String} Diffrence between the two dates.
 */
function getNiceTime(fromDate, toDate, levels, prefix){
    var lang = {
            "date.past": "{0} ago",
            "date.future": "in {0}",
            "date.now": "now",
            "date.year": "{0} year",
            "date.years": "{0} years",
            "date.years.prefixed": "{0} years",
            "date.month": "{0} month",
            "date.months": "{0} months",
            "date.months.prefixed": "{0} months",
            "date.day": "{0} day",
            "date.days": "{0} days",
            "date.days.prefixed": "{0} days",
            "date.hour": "{0} hour",
            "date.hours": "{0} hours",
            "date.hours.prefixed": "{0} hours",
            "date.minute": "{0} minute",
            "date.minutes": "{0} minutes",
            "date.minutes.prefixed": "{0} minutes",
            "date.second": "{0} second",
            "date.seconds": "{0} seconds",
            "date.seconds.prefixed": "{0} seconds",
        },
        langFn = function(id,params){
            var returnValue = lang[id] || "";
            if(params){
                for(var i=0;i<params.length;i++){
                    returnValue = returnValue.replace("{"+i+"}",params[i]);
                }
            }
            return returnValue;
        },
        toDate = toDate ? toDate : new Date(),
        diff = fromDate - toDate,
        past = diff < 0 ? true : false,
        diff = diff < 0 ? diff * -1 : diff,
        date = new Date(new Date(1970,0,1,0).getTime()+diff),
        returnString = '',
        count = 0,
        years = (date.getFullYear() - 1970);
    if(years > 0){
        var langSingle = "date.year" + (prefix ? "" : ""),
            langMultiple = "date.years" + (prefix ? ".prefixed" : "");
        returnString += (count > 0 ?  ', ' : '') + (years > 1 ? langFn(langMultiple,[years]) : langFn(langSingle,[years]));
        count ++;
    }
    var months = date.getMonth();
    if(count < levels && months > 0){
        var langSingle = "date.month" + (prefix ? "" : ""),
            langMultiple = "date.months" + (prefix ? ".prefixed" : "");
        returnString += (count > 0 ?  ', ' : '') + (months > 1 ? langFn(langMultiple,[months]) : langFn(langSingle,[months]));
        count ++;
    } else {
        if(count > 0)
            count = 99;
    }
    var days = date.getDate() - 1;
    if(count < levels && days > 0){
        var langSingle = "date.day" + (prefix ? "" : ""),
            langMultiple = "date.days" + (prefix ? ".prefixed" : "");
        returnString += (count > 0 ?  ', ' : '') + (days > 1 ? langFn(langMultiple,[days]) : langFn(langSingle,[days]));
        count ++;
    } else {
        if(count > 0)
            count = 99;
    }
    var hours = date.getHours();
    if(count < levels && hours > 0){
        var langSingle = "date.hour" + (prefix ? "" : ""),
            langMultiple = "date.hours" + (prefix ? ".prefixed" : "");
        returnString += (count > 0 ?  ', ' : '') + (hours > 1 ? langFn(langMultiple,[hours]) : langFn(langSingle,[hours]));
        count ++;
    } else {
        if(count > 0)
            count = 99;
    }
    var minutes = date.getMinutes();
    if(count < levels && minutes > 0){
        var langSingle = "date.minute" + (prefix ? "" : ""),
            langMultiple = "date.minutes" + (prefix ? ".prefixed" : "");
        returnString += (count > 0 ?  ', ' : '') + (minutes > 1 ? langFn(langMultiple,[minutes]) : langFn(langSingle,[minutes]));
        count ++;
    } else {
        if(count > 0)
            count = 99;
    }
    var seconds = date.getSeconds();
    if(count < levels && seconds > 0){
        var langSingle = "date.second" + (prefix ? "" : ""),
            langMultiple = "date.seconds" + (prefix ? ".prefixed" : "");
        returnString += (count > 0 ?  ', ' : '') + (seconds > 1 ? langFn(langMultiple,[seconds]) : langFn(langSingle,[seconds]));
        count ++;
    } else {
        if(count > 0)
            count = 99;
    }
    if(prefix){
        if(returnString == ""){
            returnString = langFn("date.now");
        } else if(past)
            returnString = langFn("date.past",[returnString]);
        else
            returnString = langFn("date.future",[returnString]);
    }
    return returnString;
}

回答by Renan

Some math is in order.

一些数学是有序的。

You can subtract one Date object from another in Javascript, and you'll get the difference between them in milisseconds. From this result you can extract the other parts you want (days, months etc.)

您可以在 Javascript 中从另一个 Date 对象中减去一个 Date 对象,您将获得它们之间的差异(以毫秒为单位)。从这个结果中你可以提取你想要的其他部分(天、月等)

For example:

例如:

var a = new Date(2010, 10, 1);
var b = new Date(2010, 9, 1);

var c = a - b; // c equals 2674800000,
               // the amount of milisseconds between September 1, 2010
               // and August 1, 2010.

Now you can get any part you want. For example, how many days have elapsed between the two dates:

现在你可以得到任何你想要的部分。例如,两个日期之间过去了多少天:

var days = (a - b) / (60 * 60 * 24 * 1000);
// 60 * 60 * 24 * 1000 is the amount of milisseconds in a day.
// the variable days now equals 30.958333333333332.

That's almost 31 days. You can then round down for 30 days, and use whatever remained to get the amounts of hours, minutes etc.

差不多31天了。然后,您可以向下取整 30 天,并使用剩余的任何内容来获取小时数、分钟数等。

回答by Jakub Pelák

I have created, yet another one, function for this purpose:

为此,我创建了另一个函数:

function dateDiff(date) {
    date = date.split('-');
    var today = new Date();
    var year = today.getFullYear();
    var month = today.getMonth() + 1;
    var day = today.getDate();
    var yy = parseInt(date[0]);
    var mm = parseInt(date[1]);
    var dd = parseInt(date[2]);
    var years, months, days;
    // months
    months = month - mm;
    if (day < dd) {
        months = months - 1;
    }
    // years
    years = year - yy;
    if (month * 100 + day < mm * 100 + dd) {
        years = years - 1;
        months = months + 12;
    }
    // days
    days = Math.floor((today.getTime() - (new Date(yy + years, mm + months - 1, dd)).getTime()) / (24 * 60 * 60 * 1000));
    //
    return {years: years, months: months, days: days};
}

Doesn't require any 3rd party libraries. Takes one argument -- date in YYYY-MM-DD format.

不需要任何 3rd 方库。采用一个参数——YYYY-MM-DD 格式的日期。

https://gist.github.com/lemmon/d27c2d4a783b1cf72d1d1cc243458d56

https://gist.github.com/lemmon/d27c2d4a783b1cf72d1d1cc243458d56

回答by Nilesh Patel

   let startDate = moment(new Date('2017-05-12')); // yyyy-MM-dd
   let endDate = moment(new Date('2018-09-14')); // yyyy-MM-dd

   let Years = newDate.diff(date, 'years');
   let months = newDate.diff(date, 'months');
   let days = newDate.diff(date, 'days');

console.log("Year: " + Years, ", Month: " months-(Years*12), ", Days: " days-(Years*365.25)-((365.25*(days- (Years*12)))/12));

Above snippet will print: Year: 1, Month: 4, Days: 2

上面的代码片段将打印:年:1,月:4,天:2

回答by webtweakers

Yet another solution, based on some PHP code. The strtotime function, also based on PHP, can be found here: http://phpjs.org/functions/strtotime/.

另一个解决方案,基于一些 PHP 代码。strtotime 函数也基于 PHP,可以在这里找到:http: //phpjs.org/functions/strtotime/

Date.dateDiff = function(d1, d2) {
    d1 /= 1000;
    d2 /= 1000;
    if (d1 > d2) d2 = [d1, d1 = d2][0];

    var diffs = {
        year: 0,
        month: 0,
        day: 0,
        hour: 0,
        minute: 0,
        second: 0
    }

    $.each(diffs, function(interval) {
        while (d2 >= (d3 = Date.strtotime('+1 '+interval, d1))) {
            d1 = d3;
            ++diffs[interval];
        }
    });

    return diffs;
};

Usage:

用法:

> d1 = new Date(2000, 0, 1)
Sat Jan 01 2000 00:00:00 GMT+0100 (CET)

> d2 = new Date(2013, 9, 6)
Sun Oct 06 2013 00:00:00 GMT+0200 (CEST)

> Date.dateDiff(d1, d2)
Object {
  day: 5
  hour: 0
  minute: 0
  month: 9
  second: 0
  year: 13
}