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

2022-08-29 23:07:19

下面的代码有什么问题?

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

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

我的代码:

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

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


答案 1

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

例如

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

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

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

现在,您只能将两个日期作为日期进行比较,而不必担心时间元素。


答案 2

当心时区

使用 date 对象直接表示“只是一个日期”会让您陷入一个巨大的过度精度问题。您需要管理时间和时区以将其拒之门外,并且他们可以在任何步骤中偷偷溜回去。这个问题的公认答案落入了陷阱。

JavaScript日期没有时区的概念。这是一个时刻(自纪元以来的刻度),具有方便的(静态)函数,用于与字符串之间来回转换,默认情况下使用设备的“本地”时区,或者,如果指定,使用UTC或其他时区。要使用日期™对象表示正好日期,您希望日期在相关日期的开头表示 UTC 午夜。这是一个常见且必要的约定,允许您使用日期,而不管其创建的季节或时区如何。因此,您需要非常警惕地管理时区的概念,无论是在创建午夜 UTC 日期对象时,还是在序列化它时。

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

反序列化(或创建午夜 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>

看到它正在运行...

更新 2022...免费的东西与测试...

下面的代码现在是一个npm包,Epoq。代码在github上。不客气:-)

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

鉴于这个答案的流行,我把它全部放在代码中。以下函数返回一个包装的日期对象,并且仅公开那些可安全用于仅日期™的函数。

使用 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\d|(\+|-)\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())
// Test case from @prototype's comment
console.log("@prototype's issue fixed... " + JustADate('1963-11-22').toLocaleDateString())