确定用户访问网页时的当前本地时间和 UTC 时间 (JavaScript)

Determine current local and UTC time when user visits webpage (JavaScript)

我编写了一个基本函数,旨在获取时间戳,用于记录每个访问者何时点击页面。我其实想用两种方式记录时间;本地时间(这样我就可以看到基于用户时间的访问分布)以及 UTC 时间(这样我就可以从全球标准化的角度看到访问分布)

var currentTime = new Date();
var timestamp = splitTimestamp(currentTime);

function splitTimestamp(timestamp) {
    var splitTimestamp = {};
    splitTimestamp.local = new Date(timestamp.getFullYear(), timestamp.getMonth(), timestamp.getDate(), timestamp.getHours(), timestamp.getMinutes(), timestamp.getSeconds()).toISOString();
    splitTimestamp.UTC = new Date(timestamp.getUTCFullYear(), timestamp.getUTCMonth(), timestamp.getUTCDate(), timestamp.getUTCHours(), timestamp.getUTCMinutes(), timestamp.getUTCSeconds()).toISOString();
    return splitTimestamp;
}

我的想法是,我可以根据需要通过 timestamp.localtimestamp.UTC 来引用每个。

我曾假设通过 new Date() 导出的本地时间只是浏览器的本地时间,即根据用户的本地系统/OS。然而,我看到一些记录似乎与此相矛盾。例如,我从纽约 (UTC+4) 的一位用户那里找到了一条记录,该记录的时间尚未出现(即当我看到该记录时是美国东部标准时间上午 11 点/世界标准时间下午 3 点,但它显示为美国东部标准时间下午 2 点/世界标准时间下午 6 点)日志)

现在 - 最初,我通过说用户可能只是使用不一定与其实际位置一致的系统设置来解释这一点(即他们在纽约,但由于只有他们自己知道的原因,他们将他们的系统/OS 保持在 UTC 时间)对此我无能为力,我对此很满意。

但是...如果是这样的话,那么本地时间和 UTC 时间会相同?而且……他们不是。所以...这不可能是正在发生的事情?

我在这里忽略了什么明显的东西吗?

如果您只想要该格式的时间字符串,您可以使用 new Date(date) 复制日期对象(无需放置年、月、日等),然后减去偏移量并获取 ISO 格式的字符串。然后,您应该删除字符串末尾的 'z' 以指示它是本地时区而不是 UTC 时区。

var date = new Date();
var utc_time = date.toISOString();

var offset_date = new Date(date);
offset_date.setMinutes(date.getMinutes()-date.getTimezoneOffset());
var local_time = offset_date.toISOString().slice(0, -1);

console.log(utc_time);
console.log(local_time);

您可能也有兴趣查看我的 ProtoDate 图书馆。我构建它来处理这样的事情。

Date.prototype.toString生成的时间戳包含您需要的所有信息。它具有本地*日期和时间加上 UTC 偏移量,该格式可由内置解析器解析,并且可以通过一些重新格式化转换为符合 ISO 8601 的格式(也可由内置解析器解析),例如

// Return UTC timestamp in ISO 8601 format
// @param {string} timestamp - in format per ECMA-262 Date.prototype.toString
// @returns {string} equivalent timestamp in ISO 8601 format UTC
// e.g. Fri Sep 10 2021 08:08:32 GMT+1000 (ChST) -> 2021-09-09T22:41:11.000Z
function toUTC(timestamp){
  return new Date(timestamp).toISOString();
}

// Return offset from ECMA-262 timestamp from Date.prototype.toString
// @param {string} timestamp - in format per ECMA-262 Date.prototype.toString 
// @return {string} offset in same format as toUTC
// e.g. Fri Sep 10 2021 08:08:32 GMT+1000 (ChST) -> +10:00
function getOffset(timestamp) {
  let offset = (timestamp.match(/[+-]\d{4}/) || [])[0];
  return offset? `${offset.slice(0,3)}:${offset.slice(-2)}` : '';
}

// Reformat ECMA-262 default timestamp as ISO 8601 UTC,
// @param {string} timestamp - in format per ECMA-262 Date.prototype.toString 
// @return {string} equivalent timestamp in ISO 8601 format with local date
//                  and time with local offset
// e.g. Fri Sep 10 2021 08:08:32 GMT+1000 (ChST) -> 2021-09-09T08:08:32.000+10:00
function toISOLocal(timestamp) {
  let months = [,'Jan','Feb','Mar','Apr','May','Jun',
                 'Jul','Aug','Sep','Oct','Nov','Dec'];
  let pad = n => ('0'+n).slice(-2);
  let [dayName, monthName, day, year, hour, min, sec, g, offset] = timestamp.split(/\W/);
  let sign = /\+/.test(timestamp)? '+' : '-';
  
  return `${year}-${pad(months.indexOf(monthName))}-${pad(day)}` +
    `T${hour}:${min}:${sec}.000${getOffset(timestamp)}`; 
}

// Examples
// In ECMAScript format, e.g. Fri Sep 10 2021 08:08:32 GMT+1000 (ChST)
let timestamp = new Date().toString();

console.log('Input : ' + timestamp +
          '\nUTC   : ' + toUTC(timestamp) +
          '\nLocal : ' + toISOLocal(timestamp) +
          '\nOffset: ' + getOffset(timestamp)
);

唯一的问题是 toString (±HHmm) 返回的偏移量格式与 toISOString ( ±HH:毫米)。 getOffset 函数 returns 后一种格式,如果您需要其他格式,可以轻松更改。

关于内置解析器,阅读Why does Date.parse give incorrect results?

很有帮助

* 其中“本地”表示基于主机系统设置,可能与系统的地理位置值匹配也可能不匹配。