【问题标题】:setDate(latest.getDate() - 1) skips 2021-11-07, but only when run for some peoplesetDate(latest.getDate() - 1) 跳过 2021-11-07,但仅适用于某些人
【发布时间】:2022-01-11 20:47:40
【问题描述】:

我在这里遇到了一个奇怪的问题。在我正在制作的应用程序中,需要生成一个连续日期字符串数组,其中每个日期字符串都是“YYYY-MM-DD”。它运行了很长时间,但在 11 月,我的一位用户告诉我,应用程序中缺少一个日期,即 2021 年 11 月 7 日。

但是,其他人并没有错过它。所以我和他一起把问题缩小到下面的代码。如果我或他在我们的 Chrome 控制台中运行它,它的行为会有所不同。

// Creates an array of 14 consecutive date strings
function datesInclGaps(date, hour) {
    const latest = toUTCDate(date, hour)
    const result = []
    for (let i = 0; i < 14; i++) {
        result.push(fromUTCDate(latest))
        latest.setDate(latest.getDate() - 1)
    }
    return result
}

// Creates a Date object with the given UTC date and the give hour.
const toUTCDate = (date, hour) => {
    const match = /(\d\d\d\d)-(\d\d)-(\d\d)/.exec(date)
    if (!match) throw new Error('Illegal date format: ' + date)
    const utc = new Date()
    utc.setUTCFullYear(+match[1], +match[2] - 1, +match[3])
    utc.setUTCHours(hour, 0, 0, 0)
    return utc
}

// Returns a date string YYYY-MM-DD from a Date obj.
// Date assumed to be in UTC.
const fromUTCDate = date => {
    const y = date.getUTCFullYear()
    const m = pad(date.getUTCMonth() + 1)
    const d = pad(date.getUTCDate())
    return `${y}-${m}-${d}`
}

const pad = (t, p = 2) => t.toString().padStart(p, '0')

console.log('0-hour')
console.log(datesInclGaps('2021-11-14', 0).join(', '))
console.log('12-hour')
console.log(datesInclGaps('2021-11-14', 12).join(', '))

日期列表都应该是 11 月的前 14 天。 “小时”参数是我最终“修复”错误的方式,因为如果我将它设置为 0,那么这一天对他来说就消失了,但如果它设置为 12,它就可以正常工作。请参阅下面的屏幕截图。亮模式是他的输出,有错误,暗模式是我运行它时,没有错误。在 chrome 控制台中运行完全相同的简单纯 Javascript。

我使用 UTC 版本的原因是确保时区无关紧要。但是……这是我能想到的唯一一件事,这可能是我们之间的区别。我已经为这个问题绞尽脑汁,但我想不出一个很好的理由来解释代码为什么会这样!任何见解都会很有用!

【问题讨论】:

  • 夏令时?

标签: javascript date


【解决方案1】:

发生这种情况是因为您使用了getDate:这是一种适用于本地日期的方法。如果时区差异使得 UTC 午夜时间仍然在前一天,则 getDate 将返回前一天的日期。但是在夏令时更改的第一天,将当地时间向后移动一小时,以当地时区的形式减去 1 天,对应于以 UTC 的形式减去 25 小时!

所以我们在某个时刻有这个日期:

 8 November 2021, 0:00 UTC

在执行getDate() 时,日期被解释为本地日期,在时区 GMT+00 中,没有夏令时。所以我们得到:

 8 November 2021, 0:00 Local Time Zone

然后我们做 setDate 减去 1 天:

 7 November 2021, 0:00 Local Time Zone

但是这个日期恰好在夏令时期间,所以它转换回这个 UTC 日期:

 6 November 2021, 23:00 UTC

所以当这个日期被输出时,它是 11 月 6 日,而不是 11 月 7 日,它被跳过了。

当您看到它时,解决方案非常明显:您应该使用 getUTCDatesetUTCDate 并远离这些方法的非 UTC 变体,因为您使用 UTC 时间初始化日期。

【讨论】:

  • 感谢您提供的非常好的答案!是的,这就解释了,当我特别试图不这样做时,我不敢相信我竟然如此愚蠢地混合使用 UTC 和非 UTC 方法!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-26
  • 2020-10-24
相关资源
最近更新 更多