将日期转换为 UTC 时间戳

Posted

技术标签:

【中文标题】将日期转换为 UTC 时间戳【英文标题】:Convert Date to UTC timestamp 【发布时间】:2021-10-06 00:46:00 【问题描述】:

我有一个有时间的约会,像这样

const date = year: 2020, month: 12, day: 31;
const time = hours: 16, minutes: 2;

如何根据时区获取该时间的 UTC 表示? (不使用任何库)

convetToUTC(date, time, "Europe/Moscow") // => <UTC timestamp>
convetToUTC(date, time, "America/New_York") // => <UTC timestamp>

例子

convetToUTC(
  year: 2021, month: 7, day: 30, 
  hours: 16, minutes: 15, 
  "Europe/Moscow"
) // => 1627650900

convetToUTC(
  year: 2021, month: 7, day: 30, 
  hours: 16, minutes: 15, 
  "America/New_York"
) // => 1627676100

【问题讨论】:

请查看https://***.com/questions/9756120/how-do-i-get-a-utc-timestamp-in-javascript 检查,看不到任何提示如何进行任意时区转换 “我如何根据时区获得该时间的 UTC 表示。”这是否意味着您要获取指定的日期和时间,将其视为指定时区的日期和时间,然后获取该时刻的 UTC 时间戳 x = new Date() var UTCseconds = (x.getTime() + x.getTimezoneOffset()*60*1000)/1000; console.log("UTCseconds", UTCseconds) @Forest1 这不适用于本地时区以外的任何地方。 OP 希望为任意时区做到这一点。 【参考方案1】:
const dateWithTimeZone = (timeZone, year, month, day, hour, minute, second) => 
  let date = new Date(Date.UTC(year, month, day, hour, minute, second));

  let utcDate = new Date(date.toLocaleString('en-US',  timeZone: "UTC" ));
  let tzDate = new Date(date.toLocaleString('en-US',  timeZone: timeZone ));
  let offset = utcDate.getTime() - tzDate.getTime();

  date.setTime( date.getTime() + offset );

  return date;
;

dateWithTimeZone("America/New_York", 2021, 7 - 1, 30, 16, 15, 0).getTime() / 1000)
// => 1627676100

dateWithTimeZone("Europe/Moscow", 2021, 7 - 1, 30, 16, 15, 0).getTime() / 1000)
// => 1627650900

7 - 1 用于说明该函数接受月份的索引,而不是月份的数字

【讨论】:

在 2021 年 11 月 7 日星期日凌晨 3:30 对纽约进行测试,然后获取结果并为纽约创建时间戳:new Date(value*1e3).toLocaleString('default',timeZone:'America/New_York')。一个小时后就出来了。【参考方案2】:

借助 Achempion 的响应,我修复了时区偏移计算。应从 UTC 日期中减去时区日期。这种差异的结果应该以分钟为单位。

您需要将分钟偏移量转换回毫秒并从日期中减去。

/**
* Calculates the timezone offset of a particular time zone.
* @param String timeZone - a database time zone name
* @param Date date - a date for determining if DST is accounted for
* @return Number returns an offset in minutes
* @see https://***.com/a/68593283/1762224
*/
const getTimeZoneOffset = (timeZone = 'UTC', date = new Date()) => 
  const utcDate = new Date(date.toLocaleString('en-US',  timeZone: 'UTC' ));
  const tzDate = new Date(date.toLocaleString('en-US',  timeZone ));
  return (tzDate.getTime() - utcDate.getTime()) / 6e4;


const defaultDateConfig =  year: 0, month: 0, date: 0 ;
const defaultTimeConfig =  hours: 0, minutes: 0, seconds: 0 ;

const convetToUTC = (dateConfig, timeConfig, timeZone) => 
  const  year, month, date  =  ...defaultDateConfig, ...dateConfig ;
  const  hours, minutes, seconds  =  ...defaultTimeConfig, ...timeConfig ;
  const d = new Date(Date.UTC(year, month - 1, date, hours, minutes, seconds));
  const offsetMs = getTimeZoneOffset(timeZone, d) * 6e4;
  return (d.getTime() - offsetMs) / 1e3;
;

// Main
const date =  year: 2021, month: 7, date: 30 ;
const time =  hours: 16, minutes: 15 ;

console.log(convetToUTC(date, time, 'America/New_York')); // 1627676100
console.log(convetToUTC(date, time, 'Europe/Moscow'));    // 1627650900

【讨论】:

我认为使用 10**3 甚至 1000 会使功能比使用 1e3 更简单 @achemion 1e3其实和1000一样,只是科学记数法;而10**3 是功率计算。后者是Math.pow(10, 3) 的有效语法糖。 实际上没有必要在 getTimeZoneOffset 中对 6e4 进行除法然后将其相乘,因为您仍将秒数保留在偏移量中,因为 devision 会产生浮点数并且您不会对其进行舍入 @achemion getTimeZoneOffset 函数独立于 convetToUTC 中的逻辑。如果您查看MDN: Date.prototype.getTimezoneOffset()。它指出结果以分钟为单位。作为经验法则,我坚持这一点。我更新了我的代码以包含一些 JS 文档以获取更多信息。 我同意你在这里采用了正确的方法,我们应该在 getTimeZoneOffset 函数中返回分钟。问题是它返回像这样的值 1627661700.24,其中最后的“.24”部分意味着它仍然存在秒部分。通过“它声明结果以分钟为单位”。我认为您的意思是整分钟,但您的函数可以返回 1min 30m 秒作为示例。

以上是关于将日期转换为 UTC 时间戳的主要内容,如果未能解决你的问题,请参考以下文章

在 VBA 中,如何以简单的方式将 UTC UNIX 时间戳转换为本地时区日期?

将 unix 时间转换为 UTC 日期时间

Ruby:将unix时间戳转换为日期[重复]

将UTC时间戳转换为熊猫中的本地时区问题

在 Ruby 中将 UTC 时间戳转换为 ISO 8601

Spring boot + Jackson - 始终将日期转换为 UTC