仅比较日期部分,而不比较JavaScript中的时间


397

以下代码有什么问题?

也许只比较日期而不是时间会更简单。我也不确定如何执行此操作,因此我进行了搜索,但找不到确切的问题。

顺便说一句,当我在警报中显示两个日期时,它们显示为完全相同。

我的代码:

window.addEvent('domready', function() {
    var now = new Date();
    var input = $('datum').getValue();
    var dateArray = input.split('/');
    var userMonth = parseInt(dateArray[1])-1;
    var userDate = new Date();
    userDate.setFullYear(dateArray[2], userMonth, dateArray[0], now.getHours(), now.getMinutes(), now.getSeconds(), now.getMilliseconds());

    if (userDate > now)
    {
        alert(now + '\n' + userDate);
    }
});

有没有更简单的方法来比较日期而不包括时间?

Answers:


781

我仍在学习JavaScript,而我发现唯一可以比较两个没有时间setHours的日期的方法是使用Date对象的方法,并将小时,分钟,秒和毫秒设置为零。然后比较两个日期。

例如,

date1 = new Date()
date2 = new Date(2011,8,20)

date2会将小时,分钟,秒和毫秒设置为零,但date1会将其设置为创建date1的时间。要摆脱date1上的小时,分​​钟,秒和毫秒,请执行以下操作:

date1.setHours(0,0,0,0)

现在,您可以仅将两个日期作为“日期”进行比较,而不必担心时间元素。


63
请注意,测试by date1 === date2似乎并不能提供一致的行为。这是好做date1.valueOf() === b.valueOf(),甚至date1.getTime() === date2.getTime()。奇怪
欧文·韦塞尔斯

4
请注意:如果date1和date2在冬季和夏季,并且您打算使用addDays(1)从一个迭代到另一个,则问题是由于夏令时它们不会具有相同的时区,因此最后一个比较应该给出相等日期的比较将不起作用,因为两个日期并非真正在00:00:00:0处。
奥利弗

9
我知道这是一个老问题,但是在搜索时首先出现在Google中。小心此答案。如果用户与日期对象的创建者不在同一时区,则将给出错误的答案。例如,将计算机操作系统上的时区更改为美国东海岸时间。打开浏览器的控制台,然后键入var date2 = new Date(2011,8,20)。现在,将操作系统的时区更改为太平洋时间(美国)。在相同的浏览器控制台类型中date2.toDateString(),您将返回,Mon Sep 19 2011而不是20日星期二!
亚当

9
另请注意,该setHours()设置基于浏览器自动检测到的当前时区设置时间。尝试:t = new Date("2016-02-29T01:45:49.098Z"); t.setHours(0,0,0,0); console.log(t.toJSON());将打印"2016-02-28T15:00:00.000Z"日期28,而不是29我当前的时区是Asia/Tokyo
transang '16

8
确实应将此答案更新为使用setUTCxxx方法,而不要使用支持本地/时区的变体。
Stijn de Witt

136

当心时区

使用日期对象立即表示刚刚的日期会使您陷入巨大的超精度问题。您需要管理时间和时区以将其保留,它们可以在任何步骤潜入。这个问题的公认答案就落入了陷阱。

javascript日期没有时区的概念。这是一个时刻(自历元开始滴答作响),带有方便的(静态)函数,用于在字符串之间进行转换,默认情况下使用设备的“本地”时区,如果使用,则使用UTC或其他时区。为了用日期对象表示just-a-date™,您希望您的日期在相关日期的开始时代表UTC午夜。这是一项常见且必要的约定,可让您使用日期,而不考虑其创建的季节或时区。因此,在创建午夜UTC日期对象以及对其进行序列化时,都需要非常警惕地管理时区的概念。

控制台的默认行为使很多人感到困惑。如果您在控制台上喷一个日期,您看到的输出将包括您的时区。这仅仅是因为控制台会要求toString()您约会,并toString()为您提供本地代表。基础日期没有时区!(只要时间与时区偏移量匹配,您仍然会有一个午夜UTC日期对象)

反序列化(或创建午夜UTC日期对象)

这是舍入步骤,有两个“正确”答案的窍门。大多数时候,您希望日期反映用户的时区。如果今天是你的生日,请单击。新西兰和美国的用户同时点击并获得不同的日期。在这种情况下,请执行此操作...

// create a date (utc midnight) reflecting the value of myDate and the environment's timezone offset.
new Date(Date.UTC(myDate.getFullYear(),myDate.getMonth(), myDate.getDate()));

有时,国际可比性胜于本地准确性。在这种情况下,请执行此操作...

// the date in London of a moment in time. Device timezone is ignored.
new Date(Date.UTC(myDate.getUTCFullYear(), myDate.getUTCMonth(), myDate.getUTCDate()));

反序列化日期

网上的日期通常采用YYYY-MM-DD格式。要反序列化它们,请执行此操作...

var midnightUTCDate = new Date( dateString + 'T00:00:00Z');

序列化

创建时已注意管理时区,现在需要确保在转换回字符串表示形式时将时区排除在外。这样您就可以安全使用...

  • toISOString()
  • getUTCxxx()
  • getTime() //returns a number with no time or timezone.
  • .toLocaleDateString("fr",{timezone:"UTC"}) // whatever locale you want, but ALWAYS UTC.

并完全避免其他一切,尤其是...

  • getYear()getMonth()getDate()

因此,回答您的问题,已经晚了7年...

<input type="date" onchange="isInPast(event)">
<script>
var isInPast = function(event){
  var userEntered = new Date(event.target.valueAsNumber); // valueAsNumber has no time or timezone!
  var now = new Date();
  var today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate() ));
  if(userEntered.getTime() < today.getTime())
    alert("date is past");
  else if(userEntered.getTime() == today.getTime())
    alert("date is today");
  else
    alert("date is future");

}
</script>

看到它正在运行...

更新2019 ...免费的东西...

鉴于此答案的受欢迎程度,我将其全部放入代码中。以下函数返回一个包装的日期对象,并且仅公开那些可以与just-a-date™一起安全使用的函数。

用Date对象调用它,它将解析为JustADate,反映用户的时区。用一个字符串来调用它:如果该字符串是指定了时区的ISO 8601,我们将舍入时间部分。如果未指定时区,则将其转换为反映本地时区的日期,就像日期对象一样。

function JustADate(initDate){
  var utcMidnightDateObj = null
  // if no date supplied, use Now.
  if(!initDate)
    initDate = new Date();

  // if initDate specifies a timezone offset, or is already UTC, just keep the date part, reflecting the date _in that timezone_
  if(typeof initDate === "string" && initDate.match(/((\+|-)\d{2}:\d{2}|Z)$/gm)){  
     utcMidnightDateObj = new Date( initDate.substring(0,10) + 'T00:00:00Z');
  } else {
    // if init date is not already a date object, feed it to the date constructor.
    if(!(initDate instanceof Date))
      initDate = new Date(initDate);
      // Vital Step! Strip time part. Create UTC midnight dateObj according to local timezone.
      utcMidnightDateObj = new Date(Date.UTC(initDate.getFullYear(),initDate.getMonth(), initDate.getDate()));
  }

  return {
    toISOString:()=>utcMidnightDateObj.toISOString(),
    getUTCDate:()=>utcMidnightDateObj.getUTCDate(),
    getUTCDay:()=>utcMidnightDateObj.getUTCDay(),
    getUTCFullYear:()=>utcMidnightDateObj.getUTCFullYear(),
    getUTCMonth:()=>utcMidnightDateObj.getUTCMonth(),
    setUTCDate:(arg)=>utcMidnightDateObj.setUTCDate(arg),
    setUTCFullYear:(arg)=>utcMidnightDateObj.setUTCFullYear(arg),
    setUTCMonth:(arg)=>utcMidnightDateObj.setUTCMonth(arg),
    addDays:(days)=>{
      utcMidnightDateObj.setUTCDate(utcMidnightDateObj.getUTCDate + days)
    },
    toString:()=>utcMidnightDateObj.toString(),
    toLocaleDateString:(locale,options)=>{
      options = options || {};
      options.timezone = "UTC";
      locale = locale || "en-EN";
      return utcMidnightDateObj.toLocaleDateString(locale,options)
    }
  }
}


// if initDate already has a timezone, we'll just use the date part directly
console.log(JustADate('1963-11-22T12:30:00-06:00').toLocaleDateString())


3
您的答案包含非常有价值的信息!不幸的是,您实际上并没有将答案添加到OP的实际问题中,从而阻止了我对此提出质疑。尝试添加一个回答OP问题的小代码段。
Stijn de Witt

哈哈哈@'7年为时已晚'!我喜欢您的样式user1585345!你得到我的投票!
Stijn de Witt

我发现这很有帮助。请注意,“国际可比性”代码段中有一个错字。我认为应该是:new Date(Date.UTC(myDate.getUTCFullYear(),myDate.getUTCMonth(),myDate.getUTCDate()));
RikRak

1
希望我能对此答案投票100次!!!
–Sнаđошƒаӽ

77

这个怎么样?

Date.prototype.withoutTime = function () {
    var d = new Date(this);
    d.setHours(0, 0, 0, 0);
    return d;
}

它使您可以像这样比较日期的日期部分,而不影响变量的值:

var date1 = new Date(2014,1,1);
new Date().withoutTime() > date1.withoutTime(); // true

到目前为止,这是对原始帖子的最优雅的回答。我没有为我的目的创建一个单独的函数,只是包含了两行代码。
20:27

25

使用Moment.js

如果您可以选择包含第三方库,那么绝对值得一看Moment.js。它使与DateDateTime非常非常容易。

例如,查看一个日期是否在另一个日期之后但不包括它们的时间,您将执行以下操作:

var date1 = new Date(2016,9,20,12,0,0); // October 20, 2016 12:00:00
var date2 = new Date(2016,9,20,12,1,0); // October 20, 2016 12:01:00

// Comparison including time.
moment(date2).isAfter(date1); // => true

// Comparison excluding time.
moment(date2).isAfter(date1, 'day'); // => false

你传递到第二个参数isAfter是精度做比较,可以是任意的yearmonthweekdayhourminutesecond


4
从moment.js解决方案到Date()+ sethours解决方案,加速了100倍。细心的朋友:-)
2c2c

@ 2c2c有趣。绝对很想知道性能影响。您为基准测试使用了多少次操作?
Joshua Pinter

1
我的比较值约为100万。没有设置实际基准测试
2c2c

17

只需使用.toDateString进行比较,如下所示:

new Date().toDateString();

这只会返回日期部分,而不是时间或时区,如下所示:

“ 2017年2月3日星期五”

因此,两个日期都可以以这种格式进行比较,而没有时间部分。


2
这是一个好的开始,但是由于它现在是一个字符串,因此不允许进行比较。为了进行比较,可以将其更改回Date对象,方法是 new Date(new Date().toDateString());
Grid Trekkor

@GridTrekkor是的,但是如果您只想进行快速的相等性测试,这是最简单的解决方案。
CM

8

这可能是一个更简洁的版本,还请注意,在使用parseInt时应始终使用基数。

window.addEvent('domready', function() {
    // Create a Date object set to midnight on today's date
    var today = new Date((new Date()).setHours(0, 0, 0, 0)),
    input = $('datum').getValue(),
    dateArray = input.split('/'),
    // Always specify a radix with parseInt(), setting the radix to 10 ensures that
    // the number is interpreted as a decimal.  It is particularly important with
    // dates, if the user had entered '09' for the month and you don't use a
    // radix '09' is interpreted as an octal number and parseInt would return 0, not 9!
    userMonth = parseInt(dateArray[1], 10) - 1,
    // Create a Date object set to midnight on the day the user specified
    userDate = new Date(dateArray[2], userMonth, dateArray[0], 0, 0, 0, 0);

    // Convert date objects to milliseconds and compare
    if(userDate.getTime() > today.getTime())
    {
            alert(today+'\n'+userDate);
    }
});

检出MDC parseInt页面以获取有关基数的更多信息。

JSLint是捕获诸如缺少基数之类的东西以及许多其他可能导致模糊和难以调试错误的东西的好工具。它迫使您使用更好的编码标准,从而避免将来出现麻烦。我在我编写的每个JavaScript项目中使用它。


@EmKay现在这不应该成为大问题,因为ES5在大多数浏览器中都是相当标准的,并且它禁止八进制解释,但是出于向后兼容的原因,某些浏览器可能仍在使用旧的八进制解释,因此我将继续使用基数在可预见的未来。
无用的代码

如果使用严格模式,则八进制解释会引发错误,这是一件好事,因为它可以帮助您发现可能会被错误解释的错误。
无用的代码


4

如果您真正只比较没有时间成分的日期,那么另一种可能会感觉错误但可以解决并且避免所有Date()时间和时区困扰的解决方案是使用字符串比较直接比较ISO字符串日期:

> "2019-04-22" <= "2019-04-23"
true
> "2019-04-22" <= "2019-04-22"
true
> "2019-04-22" <= "2019-04-21"
false
> "2019-04-22" === "2019-04-22"
true

您可以使用以下方法获取当前日期(UTC日期,不一定是用户的本地日期):

> new Date().toISOString().split("T")[0]
"2019-04-22"

我支持它的观点是程序员的简单性-与尝试正确处理日期时间和偏移量相比,您更容易搞砸了这一点,这可能是以速度为代价的(我没有比较性能)


您也可以new Date().toISOString().substr(0, 10) // "2019-04-22"
造口

对于本地日期(非UTC日期),您可以使用new Date().toLocaleDateString() // "8/26/2019"。但是,然后比较文本将是不准确的(就像"8/26/2019" >= "9/29/2001"是错误的)。因此,您需要将其转换new Date(new Date().toLocaleDateString())为与另一个日期进行准确比较。
造口

4

只需在两个日期上使用toDateString()。toDateString不包含时间,因此在同一日期2次,值将相等,如下所示。

var d1 = new Date(2019,01,01,1,20)
var d2 = new Date(2019,01,01,2,20)
console.log(d1==d2) // false
console.log(d1.toDateString() == d2.toDateString()) // true

显然,在其他地方对此问题表示的某些时区问题是有效的,但在许多情况下,这些问题并不相关。


1
就我而言,此解决方案比选定的答案和投票最多的答案要好得多。标题为“无比较时间”中明确指出,此解决方案可以做到这一点,从而节省了设置时间来操作比较的需要。要回答“事件X和事件Y是否在同一天发生”,比较只比较日期更有意义,而不是回答“事件X的日期是00:00:00.00 AM与00:00完全相同: Y事件的日期是00.00?” 这是很多其他应答者在做
Mr.K

3

这是我的方法:

var myDate  = new Date($('input[name=frequency_start]').val()).setHours(0,0,0,0);
var today   = new Date().setHours(0,0,0,0);
if(today>myDate){
    jAlert('Please Enter a date in the future','Date Start Error', function(){
        $('input[name=frequency_start]').focus().select();
    });
}

我目前在生产环境中使用此功能,没有任何问题或浏览器不兼容等问题getTime()
Fabrizio

5
请注意,它将setHours()修改调用它的对象,并以毫秒为单位返回日期(等同于调用getTime())。因此,您的today变量不是一个Date像某些人期望的那样的对象,但实际上是整数的毫秒数。作为副作用,这就是为什么您不需要getTime()在比较之前进行调用的原因,因为您已经以一种晦涩的方式进行通话。
蒂莫西·沃尔特斯

3

因为我在这里看不到类似的方法,而且我不喜欢将h / m / s / ms设置为0,因为它可能会导致在date对象更改后准确地转换到本地时区(我想是这样),因此,这里介绍一下刚才写的lil函数:

+:易于使用,完成了基本的比较操作(无需时间即可比较日,月和年。)
-:似乎与“开箱即用”的想法完全相反。

function datecompare(date1, sign, date2) {
    var day1 = date1.getDate();
    var mon1 = date1.getMonth();
    var year1 = date1.getFullYear();
    var day2 = date2.getDate();
    var mon2 = date2.getMonth();
    var year2 = date2.getFullYear();
    if (sign === '===') {
        if (day1 === day2 && mon1 === mon2 && year1 === year2) return true;
        else return false;
    }
    else if (sign === '>') {
        if (year1 > year2) return true;
        else if (year1 === year2 && mon1 > mon2) return true;
        else if (year1 === year2 && mon1 === mon2 && day1 > day2) return true;
        else return false;
    }    
}

用法:

datecompare(date1, '===', date2)为了平等检查,
datecompare(date1, '>', date2)为了更大的检查,
!datecompare(date1, '>', date2)较小或相等检查

此外,很明显,你可以切换date1,并date2在地方实现任何其他简单的比较。


好的,再加上,帮助了我,现在希望iso转换不会咬人,哈哈,谢谢。
edencorbin

3

一种有效且正确的日期比较方法是:

Math.floor(date1.getTime() / 86400000) > Math.floor(date2.getTime() / 86400000);

它会忽略时间部分,它适用于不同的时区,您也可以比较是否相等==。86400000是一天中的毫秒数(= 24*60*60*1000)。

要注意的是平等的经营者==应该永远不会被用于当你所期望的平等的测试工作,因为它是在比较两个Date对象,因为它没有比较Date对象(且不两个日期比较),例如:

> date1;
outputs: Thu Mar 08 2018 00:00:00 GMT+1300

> date2;
outputs: Thu Mar 08 2018 00:00:00 GMT+1300

> date1 == date2;
outputs: false

> Math.floor(date1.getTime() / 86400000) == Math.floor(date2.getTime() / 86400000);
outputs: true

注意:如果比较的是将时间部分设置为零的Date对象,则可以使用date1.getTime() == date2.getTime()它,但是值得进行优化。直接比较Date对象时,可以使用<,,或,因为这些运算符首先通过调用转换Date对象><=>=.valueOf()的操作确实比较前。


2

在发布此问题后的同一时间阅读了该问题之后,我决定发布另一种解决方案,因为我发现它至少并不能满足我的需求:

我用过这样的东西:

var currentDate= new Date().setHours(0,0,0,0);

var startDay = new Date(currentDate - 86400000 * 2);
var finalDay = new Date(currentDate + 86400000 * 2);

这样,我本可以使用以后要处理的格式使用日期。但这仅是我的需要,但我还是决定将其发布,也许会对某人有所帮助


1
请注意,您的currentDate变量不是日期,是自1970-01-01以来的毫秒数。该setHours()方法修改它被调用的日期对象,并返回等效于getTime()(自1970-01-01开始的日期值,以毫秒为单位)。
蒂莫西·沃尔特斯

1

确保userDate使用4位数字的年份作为setFullYear(10, ...) !== setFullYear(2010, ...)


1

您可以对总的ms使用一些算术。

var date = new Date(date1);
date.setHours(0, 0, 0, 0);

var diff = date2.getTime() - date.getTime();
return diff >= 0 && diff < 86400000;

我之所以这样,是因为没有对原始日期进行任何更新,并且执行性能比字符串拆分和比较快。

希望有帮助!


1

这个JS将在设置日期之后更改内容,这 是相同的,但在w3schools上

date1 = new Date()
date2 = new Date(2019,5,2) //the date you are comparing

date1.setHours(0,0,0,0)

var stockcnt = document.getElementById('demo').innerHTML;
if (date1 > date2){
document.getElementById('demo').innerHTML="yes"; //change if date is > set date (date2)
}else{
document.getElementById('demo').innerHTML="hello"; //change if date is < set date (date2)
}
<p id="demo">hello</p> <!--What will be changed-->
<!--if you check back in tomorrow, it will say yes instead of hello... or you could change the date... or change > to <-->


1

这对我有用:

 export default (chosenDate) => {
  const now = new Date();
  const today = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
  const splitChosenDate = chosenDate.split('/');

  today.setHours(0, 0, 0, 0);
  const fromDate = today.getTime();
  const toDate = new Date(splitChosenDate[2], splitChosenDate[1] - 1, splitChosenDate[0]).getTime();

  return toDate < fromDate;
};

在接受的答案中,存在时区问题,而其他时间不是00:00:00


0

我知道这个问题已经被回答了,这可能不是最好的方法,但是在我的情况下,它可以正常工作,所以我认为这可能会对像我这样的人有所帮助。

如果你有date string作为

String dateString="2018-01-01T18:19:12.543";

并且您只想将日期部分与JS中的另一个Date对象进行比较,

var anotherDate=new Date(); //some date

那么你必须convertstringDate使用对象new Date("2018-01-01T18:19:12.543");

这是窍门:-

var valueDate =new Date(new Date(dateString).toDateString());

            return valueDate.valueOf() == anotherDate.valueOf(); //here is the final result

我使用toDateString()Date objectJS,它仅返回Date字符串。

注意:.valueOf()在比较日期时不要忘记使用该功能。

有关更多信息,请参见.valeOf()此处

快乐的外衣。


0

这会有所帮助。我设法做到了。

var currentDate = new Date(new Date().getFullYear(), new Date().getMonth() , new Date().getDate())

0

与之比较setHours()将是一个解决方案。样品:

var d1 = new Date();
var d2 = new Date("2019-2-23");
if(d1.setHours(0,0,0,0) == d2.setHours(0,0,0,0)){
    console.log(true)
}else{
    console.log(false)
}

0
var fromdate = new Date(MM/DD/YYYY);
var todate = new Date(MM/DD/YYYY);
if (fromdate > todate){
    console.log('False');
}else{
    console.log('True');
}

如果您的日期格式不同,请使用moment.js库转换日期格式,然后使用上述代码比较两个日期

范例:

如果您的日期在“ DD / MM / YYYY”中,并且想要将其转换为“ MM / DD / YYYY”,那么请参见以下代码示例

var newfromdate = new Date(moment(fromdate, "DD/MM/YYYY").format("MM/DD/YYYY"));
console.log(newfromdate);
var newtodate = new Date(moment(todate, "DD/MM/YYYY").format("MM/DD/YYYY"));
console.log(newtodate);

0

您可以使用fp_incr(0)。它将时区部分设置为午夜并返回日期对象。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.