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

Posted

技术标签:

【中文标题】仅比较日期部分而不比较 JavaScript 中的时间【英文标题】:Comparing date part only without comparing time in JavaScript 【发布时间】:2011-02-11 12:38:25 【问题描述】:

下面的代码有什么问题?

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

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

我的代码:

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);
    
);

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

【问题讨论】:

date1.toDateString() === date2.toDateString() 从死里复活:当我使用 toSting 时,我得到了来自 date.setFullYear(yyyy,mm,dd) 的错误结果,在我得到月份的日期增加了 1。在此页面上测试 link 在 FireFox 和 Edge 中。 【参考方案1】:

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

例如,

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

date2 会将小时、分钟、秒和毫秒设置为零,但 date1 会将它们设置为 date1 创建的时间。要去掉 date1 上的小时、分钟、秒和毫秒,请执行以下操作:

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

现在您可以仅将两个日期作为 DATES 进行比较,而无需担心时间元素。

【讨论】:

请注意date1 === date2 的测试似乎没有提供一致的行为;最好使用date1.valueOf() === b.valueOf() 甚至date1.getTime() === date2.getTime()。奇怪。 注意:如果 date1 和 date2 在冬季和夏季,并且您计划使用 addDays(1) 从一个迭代到另一个,问题是它们不会有相同的时区,因为夏令时,所以最后一个应该给出相同日期的比较将不起作用,因为这两个日期并不是真正的 00:00:00:0。 我知道这是一个老问题,但在搜索时它首先出现在谷歌中。小心这个答案。如果用户与日期对象的创建者不在同一时区,这将给出错误的答案。例如,将计算机操作系统上的时区更改为东海岸(美国)时间。打开浏览器的控制台并输入var date2 = new Date(2011,8,20)。现在将操作系统的时区更改为太平洋时间(美国)。在同一浏览器控制台中输入date2.toDateString(),您将返回Mon Sep 19 2011,而不是20 号星期二! 还要注意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 这个答案真的应该更新为使用setUTCxxx 方法而不是本地/时区感知变体。【参考方案2】:

注意时区

直接使用日期对象来表示只是一个日期会让您陷入巨大的精度过高问题。您需要管理时间和时区以将它们拒之门外,并且它们可以随时潜入。 这个问题的公认答案落入了陷阱。

javascript 日期没有时区的概念。这是一个时间点(自纪元以来的滴答声),具有方便的(静态)函数来转换字符串和从字符串转换,默认情况下使用设备的“本地”时区,或者,如果指定,则使用 UTC 或其他时区。要使用日期对象表示 just-a-date™,您希望您的日期在相关日期开始时表示 UTC 午夜。这是一个常见且必要的约定,可让您使用日期无论他们创作的季节或时区如何。因此,无论是在创建午夜 UTC Date 对象时,还是在序列化它时,都需要非常警惕地管理时区的概念。

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

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

这是四舍五入的步骤,诀窍是有两个“正确”答案。大多数情况下,您会希望您的日期反映用户的本地时区。 我在这里的日期是什么时候。。新西兰和美国的用户可以同时点击,通常会得到不同的日期。在这种情况下,这样做...

// 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>

See it running...

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(/((\+|-)\d2:\d2|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())

【讨论】:

您的回答包含非常有价值的信息!不幸的是,您实际上并没有将答案添加到 OP 的实际问题中,这使我无法对其进行投票。尝试添加一个小代码 sn-p 来回答 OP 的问题。 哈哈哈@'晚了7年'!我喜欢你的风格user1585345!你得到了我的投票! 我发现这很有帮助。请注意,“国际可比性”sn-p 中有一个错字。我认为应该是:new Date(Date.UTC(myDate.getUTCFullYear(), myDate.getUTCMonth(), myDate.getUTCDate())); 请注意,这包含一个日期+时间,该时间设置为刚刚超过 UTC 午夜的时间,并且该日期+时间可以通过语言环境进行不同的解释。例如,JustADate('1963-11-22').toLocaleDateString() 返回"11/21/1963",这是大西洋以西时区中的前一个日期。因此,如果目标是解释日期字符串以另一种格式显示相同的日历日期,而不是将 Date 设置为 UTC,最好将 sstMidnightDateObj 设置为 SST(美属萨摩亚时间)相反,因此在(几乎)所有语言环境中返回相同的日历日期。【参考方案3】:

这个怎么样?

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

【讨论】:

这是迄今为止对原帖最优雅的回答。我没有为我的目的创建一个单独的函数,只是包含了两行代码。 向原型中添加自定义功能并不是一个好主意。【参考方案4】:

使用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 的第二个参数是进行比较的精度,可以是yearmonthweekdayhourminute 或@987654334 中的任何一个@。

【讨论】:

从 momentjs 解决方案到 Date() + sethours 解决方案的速度提高了 100 倍。细心的朋友:-) @2c2c 很有趣。很高兴知道性能影响。您在基准测试中使用了多少操作? 我进行了大约 100 万次比较。没有设置实际的基准 Moment is in maintenance mode 如果您还没有使用它,则不应再使用它。有替代方案,日期对象比以前更好。【参考方案5】:

使用 .toDateString 进行简单比较,如下所示:

new Date().toDateString();

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

“2017 年 2 月 3 日星期五”

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

【讨论】:

这是一个好的开始,但它不允许比较,因为它现在是一个字符串。要进行比较,请通过执行 new Date(new Date().toDateString()); 将其更改回 Date 对象 @GridTrekkor 是的,但如果您只想快速进行相等性测试,这是最简单的解决方案。【参考方案6】:

只需在两个日期使用 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

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

【讨论】:

在我的情况下,这个解决方案比选择的答案和更多投票的答案要好得多。标题中明确表示“不比较时间”,这个解决方案正是这样做的,节省了设置时间来操作比较的需要。要回答“事件 X 和事件 Y 是否在同一天发生”,只比较日期更有意义,而不是回答“事件 X 的日期的上午 00:00:00.00 是否与 00:00 完全相同:事件 Y 日期的 00.00?”这是许多其他回答者正在做的事情【参考方案7】:

如果您真的只比较没有时间组件的日期,另一种可能感觉错误但有效并避免所有 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" &gt;= "9/29/2001" 是错误的)。因此,您需要将其转换为 new Date(new Date().toLocaleDateString()) 以准确地与另一个日期进行比较。【参考方案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 在大多数浏览器中都是相当标准的,而且它 forbids the octal interpretation 但出于向后兼容性的原因,一些浏览器可能仍在使用旧的八进制解释,所以在可预见的未来我会继续使用基数。 如果你使用strict mode八进制解释会抛出错误,这是一件好事,因为它可以帮助你找到可能被误解的错误。【参考方案9】:

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

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 对象时可以使用&lt;&gt;&lt;=&gt;=,因为这些运算符首先通过调用.valueOf() 转换Date 对象,然后再进行比较。

【讨论】:

【参考方案10】:

date.js 库可以方便地处理这些事情。它使所有与 JS 日期相关的脚本变得更加容易。

【讨论】:

你能补充更多关于这个库如何使这更容易的信息吗?【参考方案11】:

因为我在这里没有看到类似的方法,而且我不喜欢将 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, '&gt;', date2) 用于更大检查,!datecompare(date1, '&gt;', date2) 用于小于或等于检查

另外,很明显,您可以切换date1date2 以实现任何其他简单的比较。

【讨论】:

不错的一个,加上,帮助了我,现在希望 iso 转换不会咬人,哈哈,谢谢。【参考方案12】:

这个JS会在设定的日期之后改变内容 here's the same thing but on 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 <-->

【讨论】:

【参考方案13】:

这就是我的做法:

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()的任何原因? 请注意setHours() 修改了它被调用的对象,并以毫秒为单位返回日期(相当于调用getTime())。因此,您的 today 变量不像某些人所期望的那样是 Date 对象,而是实际上是毫秒的整数。作为副作用,这就是为什么您在比较之前不需要调用getTime(),因为您已经以一种模糊的方式进行了比较。【参考方案14】:

在发布后的同一时间阅读此问题后,我决定发布另一个解决方案,因为我觉得它不太令人满意,至少满足我的需求:

我用过这样的东西:

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

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

这样我就可以使用我想要的格式来处理日期。但这只是我的需要,但我还是决定发布它,也许它会对某人有所帮助

【讨论】:

请注意您的 currentDate 变量不是日期,它是自 1970-01-01 以来的毫秒数。 setHours() 方法修改它被调用的日期对象,并返回 getTime() 的等效值(自 1970-01-01 以来的日期值,以毫秒为单位)。【参考方案15】:

这对我有用:

 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

【讨论】:

【参考方案16】:

确保您构造 userDate 的 4 位数年份为 setFullYear(10, ...) !== setFullYear(2010, ...)

【讨论】:

【参考方案17】:

您可以对总毫秒数进行一些算术运算。

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

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

我喜欢这样,因为不会对原始日期进行更新,并且执行速度比字符串拆分和比较快。

希望对您有所帮助!

【讨论】:

【参考方案18】:

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)

【讨论】:

【参考方案19】:

我知道这个问题已经得到解答,这可能不是最好的方法,但在我的场景中它工作得很好,所以我认为它可以帮助像我这样的人。

如果你有date string

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

而你只是想将日期部分与 JS 中的另一个 Date 对象进行比较,

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

那么你必须使用new Date("2018-01-01T18:19:12.543");stringDate 对象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 object 的JS,它只返回日期字符串。

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

更多关于.valeOf()的信息在这里reference

编码愉快。

【讨论】:

【参考方案20】:

这会有所帮助。我设法得到它。

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

【讨论】:

【参考方案21】:
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);

【讨论】:

【参考方案22】:

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

【讨论】:

以上是关于仅比较日期部分而不比较 JavaScript 中的时间的主要内容,如果未能解决你的问题,请参考以下文章

如何在 C# 应用程序范围内更改仅日期部分将用于日期时间比较

如何仅比较 EF 中 DateTime 中的日期组件?

Django 仅基于日期过滤日期时间

Nullable-如何在 C# 中的 DateTime 类型中仅比较没有时间的日期?

以原子方式比较-交换 Django 中的模型字段

比较数组数组中的 ID,并在 PHP 中以 desc 顺序仅取一行与日期