【问题标题】:Timezone sensitive date comparisons in JavascriptJavascript中的时区敏感日期比较
【发布时间】:2021-03-06 15:49:52
【问题描述】:

我正在确定 Ember 应用中 Javascript 中两个日历日期之间的差异。我目前正在使用 date-fns 的 differenceInCalendarDays。

现在大部分都提供了所需的结果,唯一的问题是我需要处理计算对时区(而不是浏览器的本地时区)敏感的 2 个日期之间的差异。

据我所知,JS 日期被跟踪为 UTC,日期对象本身没有存储时区。我在 JS 中所做的任何时区本地化都在输出一个字符串。 在考虑时区的情况下,是否有一个好的库或方法来完成 differenceInCalendarDays?

const daysAgo = this.intl.formatRelative(-differenceInCalendarDays(new Date(), someOtherDay), {
    unit: 'day', 
    numeric: 'auto', 
    timeZone: 'this.intl.timeZone
});

这是我正在做的一个小样本,显然 differenceInCalendarDays 将解析为一个不会考虑任何时区的数字。 differenceInDays 的文档对浏览器的本地时间是时区敏感的(这在此处没有帮助),但 differenceInCalendarDays 没有提及。 任何帮助将不胜感激!

【问题讨论】:

  • 在您的情况下,当您说“日历日期”时,您的意思是 只是 一个日期,例如 "2020-11-23" 还是您的输入也有时间组件?请举一个someOtherDay的例子——包括它的类型(字符串、数字、Date对象等)
  • 是的,只是日期没有时间组件。有关上下文,请参阅下面的链接。 somOtherDay 只是一个从同一天到几天的日期对象。 date-fns.org/v2.16.1/docs/differenceInDaysdate-fns.org/v2.16.1/docs/differenceInCalendarDays
  • 您应该提供示例数据和输出。例如。假设 2020-01-01 Europe/London 和 2020-01-02 Australia/Sydney,差异应该是 1 天 11 小时吗?还是1天?还是 1.4583 天?

标签: javascript date datetime ember.js timezone


【解决方案1】:

从逻辑上讲,2020-01-012020-01-02 等两个日历日期之间的差异与时区无关,也不涉及时间。正好是一天。在这种情况下,一天不是 24 小时,而是一年的逻辑划分。把它想象成纸质日历上的一个正方形。

但是 - 在任何给定时刻,两个不同的时区可能位于同一日历日期,或者它们可能位于两个不同的日历日期。因此,在确定“现在”(或“今天”、“昨天”、“明天”等)的日期时,时区很重要

为了说明这两点并希望回答您的问题,以下代码可用于获取给定时区自“今天”以来经过的天数:

function daysSince(year, month, day, timeZone) {

  // Create a DateTimeFormat object for the given time zone.
  // Force 'en' for English to prevent issues with languages that don't use Arabic numerals.
  const formatter = new Intl.DateTimeFormat('en', { timeZone });
  
  // Format "now" to a parts array, then pull out each part.
  const todayParts = formatter.formatToParts();  // now is the default when no Date object is passed.
  const todayYear = todayParts.find(x=> x.type === 'year').value;
  const todayMonth = todayParts.find(x=> x.type === 'month').value;
  const todayDay = todayParts.find(x=> x.type === 'day').value;
  
  // Make a pseudo-timestamp from those parts, abusing Date.UTC.
  // Note we are intentionally lying - this is not actually UTC or a Unix/Epoch timestamp.
  const todayTimestamp = Date.UTC(+todayYear, todayMonth-1, +todayDay);

  // Make another timestamp from the function input values using the same approach.
  const otherTimestamp = Date.UTC(+year, month-1, +day);

  // Since the context is the same, we can subtract and divide to get number of days.
  return (todayTimestamp - otherTimestamp) / 864e5;
}

// example usage:
console.log("US Pacific: " + daysSince(2020, 1, 1, 'America/Los_Angeles'));
console.log("Japan: " + daysSince(2020, 1, 1, 'Asia/Tokyo'));

这种方法之所以有效,是因为 UTC 没有转换(例如 DST 或标准时间偏移的变化)。

还要注意我在这里没有使用Date 对象,因为我们必须非常小心这些对象是如何构造的。如果您只有一个来自日期选择器 UI 的 Date 对象,则该对象可能是在假定当地时间而不是特定时区的时间的情况下创建的。因此,在继续之前,您需要从该对象中提取年、月和日。例如:

daysSince(dt.getFullYear(), dt.getMonth() + 1, dt.getDate(), 'America/New_York');

密切关注 +1 和 -1。 Date 对象使用从 0 开始的月份,但我更喜欢从 1 开始。

【讨论】:

    猜你喜欢
    • 2014-12-19
    • 1970-01-01
    • 1970-01-01
    • 2012-01-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-08
    • 1970-01-01
    相关资源
    最近更新 更多