如何在 Javascript 中查找特定时区中给定日历日期和时间的 Unix 时间戳?

How to find Unix timestamp of a given calendar date and time in a specific time zone in Javascript?

提问人:user22476690 提问时间:11/1/2023 最后编辑:user22476690 更新时间:11/1/2023 访问量:86

问:

使用 Intl 等 API,我可以获取任何时区中任何 Unix 时间戳的日期和时间。我怎样才能反其道而行之?

我希望能够将 (YYYY-MM-DD)、(HH:MM:SS) 和 (IANA 时区) 的任何特定三元组(不一定与固定时区偏移量相对应)转换为 Unix 时间戳。我不是只想转换当前时间戳(这是微不足道的)或寻找以我有一个 Javascript Date 对象为前提的解决方案;我们只有日历日期、当地时间和时区。<calendar-date><local-time><time-zone>

诸如添加时区偏移量之类的解决方案不能可靠地工作(例如,在夏令时的情况下)。我曾希望 Intl 能够轻松计算这个问题。

JavaScript 日期

评论

0赞 deceze 11/1/2023
new Date('1983-04-23T12:34:56+06:00').getTime()...?!如果你能创建一个对象,那么你就只需要这样了。你的输入是什么样的,你到底卡在哪里?DategetTime
0赞 user22476690 11/1/2023
我无法创建 Date 对象,因为我不是从特定的 Unix 时间戳开始的;我正在尝试获取时间戳。由于我没有时间戳,因此无法创建日期。我无法以这种方式构造时间戳字符串,因为给定 IANA 时区,由于 DST 之类的原因,我无法先验地知道任何日期的时区偏移量。
0赞 deceze 11/1/2023
构造函数采用各种输入来构造 from,例如如上所示的 ISO 字符串,或年份的单个值等。再说一遍,你的输入到底是什么样子的?一旦你有了对象,从中获取 UNIX 时间戳就是单个函数调用。您的实际问题是如何将特定输入解析为对象吗?DateDateDateDate
1赞 deceze 11/1/2023
还行。我不相信标准 JS API 根本不支持命名时区来实例化对象。为此,您几乎需要求助于第三方库。DateDate
1赞 Matt Johnson-Pint 11/2/2023
不幸的是,不支持此用例。Luxon 和其他库一样。最终,它将通过 TC39 的 Temporal 内置。另请参阅 stackoverflow.com/a/15171030/634824Intl

答:

0赞 mplungjan 11/1/2023 #1

这对你有用吗?

这不是微不足道的

/**
 * Converts a calendar date and local time to a Unix timestamp.
 *
 * @param {string} calendarDate - The calendar date in the format 'YYYY-MM-DD'.
 * @param {string} localTime - The local time in the format 'HH:mm:ss'.
 * @param {string} timeZone - The IANA time zone identifier.
 * @returns {number} The Unix timestamp in seconds.
 */
const convertToUnixTimestamp = (calendarDate, localTime, timeZone) => {
  const [hourStr, minuteStr, secondStr] = localTime.split(':');
  let hour = parseInt(hourStr, 10);
  const minute = parseInt(minuteStr, 10);
  const second = parseInt(secondStr, 10);

  const dateTimeString = `${calendarDate}T00:00:00`;

  // Set the locale to 'en-US' for consistent formatting
  const dtf = new Intl.DateTimeFormat('en-US', {
    year: 'numeric',
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    timeZoneName: 'short',
    timeZone
  });

  // Format the date portion of the datetime string
  const formattedDate = dtf.format(new Date(dateTimeString));

  // Determine if it's in the afternoon based on the hour
  const isAfternoon = hour >= 12;

  // Replace "AM" or "PM" without appending when needed
  const formattedDateTime = formattedDate.replace(
    /(AM|PM)/,
    isAfternoon ? 'PM' : 'AM'
  );

  // Subtract 12 from the hour if it's in the afternoon (PM)
  if (isAfternoon) {
    hour -= 12;
  }

  // Combine the formatted date with the provided local time
  const formattedDateTimeWithTime = formattedDateTime.replace(
    /\d{2}:\d{2}:\d{2}/,
    `${hour.toString().padStart(2, '0')}:${minuteStr}:${secondStr}`
  );
  
  // Create a Date object with the formatted datetime string
  const date = new Date(formattedDateTimeWithTime);
  console.log(formattedDateTimeWithTime, "->", date);

  // Get the Unix timestamp in seconds
  const unixTimestamp = Math.floor(date.getTime() / 1000);
  return unixTimestamp;
};

// Example usages:
const calendarDate = '2023-04-15';

let timeZone = 'America/New_York'; 
let localTime = '00:30:00'; // Example with '00'
let unixTimestamp = convertToUnixTimestamp(calendarDate, localTime, timeZone);
console.log(unixTimestamp);

localTime = '15:30:00'; // Example with military time
unixTimestamp = convertToUnixTimestamp(calendarDate, localTime, timeZone);
console.log(unixTimestamp);

timeZone = 'Europe/Amsterdam'; // another IANA timezone
localTime = '15:30:00';
unixTimestamp = convertToUnixTimestamp(calendarDate, localTime, timeZone);
console.log(unixTimestamp);

评论

2赞 user22476690 11/1/2023
感谢您努力尝试实际回答这个问题!不幸的是,这个答案存在以下问题:1)重新解析日期字符串;这种格式不适用于所有 Date 实现,例如在 Hermes (React Native) 中;也许可以通过进一步修改以使格式适合ISO8601来补救,但更重要的是,2) 我不明白这如何在边缘情况下正确处理 DST,IIUC 这假设连续的日子具有相同的偏移量,这几乎总是正确的。
1赞 mplungjan 11/1/2023 #2

Luxon版本适合您吗?

// const { DateTime } = require('luxon');

// Define your input values
const calendarDate = '2023-04-15';
const localTime = '12:30:00';
const timeZone = 'America/New_York'; // Example timezone, replace with your desired IANA timezone

// Combine calendar date and local time
const dateTimeString = `${calendarDate}T${localTime}`;

// Create a Luxon DateTime object in the specified timezone
const luxonObj = luxon.DateTime.fromISO(dateTimeString, { zone: timeZone }); // remove luxon. if you have required DateTime
console.log(luxonObj)
// Get the Unix timestamp
const unixTimestamp = luxonObj.toSeconds();

console.log(unixTimestamp);
<script src="https://cdnjs.cloudflare.com/ajax/libs/luxon/3.4.3/luxon.min.js"></script>