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

IT技术 javascript date comparison mootools
2021-01-18 05:15:18

下面的代码有什么问题?

也许只比较日期而不是时间会更简单。我也不知道该怎么做,我进行了搜索,但找不到我的确切问题。

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

我的代码:

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

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

6个回答

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

例如,

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

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

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

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

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

当心时区

使用日期对象立即表示刚好日期会让您陷入一个巨大的过度精度问题。您需要管理时间和时区以将它们拒之门外,而且它们可以在任何步骤潜入。这个问题的公认答案落入了陷阱。

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

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

这个怎么样?

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
向原型添加自定义功能并不是一个好主意。
2021-03-11 05:15:18
这是迄今为止对原帖最优雅的回答。我没有为我的目的创建一个单独的函数,只是包含了两行代码。
2021-03-17 05:15:18

使用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

@2c2c 有趣。知道性能影响绝对是件好事。您在基准测试中使用了多少个操作?
2021-03-16 05:15:18
从 momentjs 解决方案到 Date() + sethours 解决方案的速度提高了 100 倍。细心的朋友:-)
2021-03-18 05:15:18
Moment 处于维护模式,如果您尚未使用它,则不应再使用它。有替代方案,日期对象比以前更好。
2021-03-25 05:15:18
我在大约 100 万次比较中。没有设置实际的基准
2021-03-29 05:15:18

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

new Date().toDateString();

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

“2017 年 2 月 3 日星期五”

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

这是一个好的开始,但它不允许比较,因为它现在是一个字符串。要进行比较,请执行以下操作将其更改回 Date 对象 new Date(new Date().toDateString());
2021-03-18 05:15:18
@GridTrekkor 是的,但如果您只想快速进行相等性测试,这是最简单的解决方案。
2021-04-01 05:15:18