【问题标题】:Determine current local and UTC time when user visits webpage (JavaScript)确定用户访问网页时的当前本地时间和 UTC 时间 (JavaScript)
【发布时间】:2021-11-05 08:41:38
【问题描述】:

我编写了一个基本函数,用于获取时间戳,用于记录每个访问者点击页面的时间。我实际上想以两种方式记录时间;本地时间(这样我可以看到基于用户时间的访问分布)以及 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() 得出的本地时间只是浏览器的本地时间,即根据用户的本地系统/操作系统。然而,我看到了一些似乎与此相矛盾的记录。例如,我从纽约 (UTC+4) 的用户那里找到了一条时间尚未出现的记录(即,当我看到该记录时,它是美国东部标准时间上午 11 点/世界标准时间下午 3 点,但它显示为美国东部标准时间下午 2 点/世界标准时间下午 6 点日志)

现在 - 最初,我解释说用户可能只是在使用不一定与他们的实际位置一致的系统设置(即他们在纽约,但出于只有他们自己知道的原因,他们保留了他们的UTC时间的系统/操作系统)我对此无能为力,我对此感到满意。

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

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

【问题讨论】:

  • 是的,用户的时钟已关闭。用户可能在纽约,但他们的本地区域设置设置为另一个区域。您可以将用户的区域保存在存储中并根据他们分配给自己的位置进行计算吗?
  • toISOString 是 总是 在 UTC 中。字符串末尾的 z 表示 UTC 时间。你到底想做什么?
  • 时间戳通常总是 UTC...为什么不保存时间戳然后也保存 UTC 偏移量,这样您就可以从另一个计算一个..
  • 我正在尝试填充两个日期变量。一个代表本地时区。一个代表 UTC 时区。我没有意识到 toISOString 本质上是 UTC - 但是,查看代码,它真的重要吗?我只是使用它,以便我以日志可以识别的格式(SharePoint)获得时间戳
  • @Iwrestledabearonce.—timestamps 不是“一般......总是UTC”。时间戳是任何字符序列,用于标识某个时刻并在 UTC 之前存在。

标签: javascript datetime utc


【解决方案1】:

如果您只想要该格式的时间字符串,您可以使用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 库。我构建它是为了处理这样的事情。

【讨论】:

  • 这太棒了 - 谢谢!我认为它极大地帮助了我理解我的“真正”问题。日志(记录时间戳的)是一个 SharePoint 列表。保存时间戳的字段本身被格式化为 DateTime 字段。因此,当 JS 发送时间戳时,SP 必须接受 ISO 格式(即包含时区组件)然后根据查看列表的人的设置显示该时间戳(即,它将时间转换为他们的本地时区通过 UTC 偏移量)
  • 这当然不是我想要的;我只想查看本地时间(当然会有很多不同的“本地人”)和UTC。所以 - 我认为我需要做的是将这些字段更改为纯文本,并将值作为字符串从 JS 传递。我失去了使用日期特征(即在 X 之前、Y 之前或之后等)进行过滤的能力,但我认为我可以忍受。
【解决方案2】:

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:mm) 产生的偏移量不同。 getOffset 函数返回后一种格式,如果您需要其他格式,可以轻松更改。

关于内置解析器,阅读Why does Date.parse give incorrect results?会有所帮助

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

【讨论】:

    猜你喜欢
    • 2016-02-15
    • 2021-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-15
    • 2014-03-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多