【问题标题】:How to convert time correctly across timezones?如何跨时区正确转换时间?
【发布时间】:2013-08-03 13:45:47
【问题描述】:

假设美国加利福尼亚州的用户选择了日期、时间和时区:

全球啤酒马拉松将于 2013 年 8 月 15 日上午 10:00,UTC-08:00

开始

中欧的另一位用户打开显示此日期和时间的页面。他不想计算时间(啤酒已经很少了)。他只想看看这个日期和时间:

8/15/2013 19:00

鉴于浏览器接收到日期和时间信息,如加利福尼亚用户输入的那样:

有没有办法,在 javascript没有外部网络服务,进行正确的转换?也就是说,要检测到 UTC-08:00 上午 10 点实际上应该是 UTC-07:00 上午 10 点,因为它是夏令时。

也许我从一开始就理解错了,但我不想让进入的用户思考他应该选择UTC-08:00(PST)还是UTC-07:00(PDT)。我假设由于 CA 的标准时区是 PST,因此人们不会在夏季转向思考 PDT。还是他们?!

在中欧,标准日期为 UTC+01:00,夏令时日期为 UTC+02:00。因此,CA 和欧洲之间的差异应该是 9 小时,一年中的两个时段除外,当一个或另一个区域在标准模式和夏令时模式之间切换时。

更新:

经过更多思考和阅读 cmets,我最需要的是:

var utcOffset = f('2013-08-15T10:00', 'America/Los_Angeles');
// utcOffset == "-07:00"
var utcOffset = f('2013-11-15T10:00', 'America/Los_Angeles');
// utcOffset == "-08:00"

到目前为止,Guido Preite 建议的 moment.js/timezone plugin 似乎能够做到这一点(或多或少)。

任何其他方式,使用浏览器 API?

【问题讨论】:

  • 检查Moment.jsMoment Timezonemomentjs.com/timezone
  • 我已经使用了 moment.js。时区扩展看起来很有希望。生成的时区文件包含夏令时转换数据。经过快速测试,它能够正确调整输入的时间。所以这看起来浏览器无法告诉“嘿,对于这个日期,你必须使用这个 UTC 偏移量,因为在那个日期,有夏令时”?

标签: javascript date datetime timezone timezone-offset


【解决方案1】:

有没有办法在没有外部网络服务的情况下在 javascript 中进行正确的转换?也就是说,要检测到 UTC-08:00 上午 10 点实际上应该是 UTC-07:00 上午 10 点,因为它是夏令时。

10:00-8 和 10:00-7 是两个不同的时间点。它们分别等于 18:00Z 和 17:00Z (Z = UTC)。当您根据偏移量进行测量时,夏令时不会进入图片。永远。

我假设由于 CA 的标准时区是 PST,因此人们不会在夏季转而思考 PDT。还是他们?!

一般来说,人们只会想到“太平洋时间”,这意味着冬季的 PST 和夏季的 PDT。但计算机更精确。当您看到 PST 时,它表示 UTC-8。当您看到 PDT 时,它表示 UTC-7。使用一种形式标注同时引用另一种形式的偏移量是无效的。

时区缩写can be ambiguous。理想情况下,以编程方式引用区域时,您应该使用 IANA 区域名称,例如 America/Los_Angeles。但是,目前这在所有没有库的 JavaScript 运行时中是不可能的。 (They are working on this though.)

在中欧,标准日期为 UTC+01:00,夏令时日期为 UTC+02:00。因此,CA 和欧洲之间的差异应该是 9 小时,一年中的两个时段除外,当一个或另一个区域在标准模式和夏令时模式之间切换时。

正确。它们可能相隔 8、9 或 10 小时。不过,它们切换的时间完全不同,所以不要试图自己管理。

到目前为止,Guido Preite 建议的 moment.js/timezone 插件似乎能够做到这一点(或多或少)。

Moment-timezone 是一个很棒的库。但是,从您描述的情况来看,我认为您不需要像您想的那样担心时区转换。看看你能不能遵循这个逻辑:

  1. 加利福尼亚的用户在文本框中输入日期和时间。
  2. 您将该文本框的值读入字符串,然后将其解析为日期:

    var dt = new Date("8/15/2013 10:00");
    

    或使用 moment.js:

    var m = moment("8/15/2013 10:00", "M/D/YYYY HH:mm");
    
  3. 因为这是在用户的计算机上完成的,所以 JavaScript 会自动假定这是一个本地日期和时间。您无需提供任何偏移量或时区信息。

  4. 这确实意味着由于 DST 转换,输入的时间可能无效或不明确。事实上,JavaScript 在处理这个问题方面做得并不好——你会在不同的浏览器上得到不同的结果。如果你想明确,那么你会提供一个偏移量。

    // PST
    var dt = new Date("3/11/2013 1:00 UTC-08:00");
    
    // PDT
    var dt = new Date("3/11/2013 1:00 UTC-07:00");
    
  5. 一旦你有了Date(或moment),你就可以评估它的UTC等效值:

    var s = dt.toISOString();  //  2013-08-15T17:00:00Z
    

    moment.js 也是一样,但是你会有更好的浏览器支持:

    var s = m.toISOString();  //  2013-08-15T17:00:00Z
    
  6. 您将该 UTC 值存储在数据库中。

  7. 中欧的另一个用户来加载数据。

  8. 您将其输入到 JavaScript 中的 Datemoment

    var dt = new Date("2013-08-15T17:00:00Z");
    

    或者使用 moment.js(同样,更好的浏览器支持)

    var m = moment("2013-08-15T17:00:00Z")
    
  9. 因为 JavaScript 知道本地计算机的时区规则,您现在可以显示这个日期,它将与中欧时区一起呈现:

    var s = dt.ToString();  //  browser specific output
    // ex: "Thu Aug 15 2013 19:00:00 GMT+0200 (Central Europe Daylight Time)"
    

    或者配合moment.js,可以更好的控制输出格式

    var s = m.format("DD/MM/YYYY HH:mm"); // "15/08/2013 19:00"
    

    你也可以让 moment.js 决定应该输出什么本地化格式:

    var s = m.format("llll"); // "Thu, 15 Aug 2013 19:00"
    

总而言之 - 如果您只想在本地时区(可能是任何时区)之间进行转换,那么您只需 Date 即可完成所有操作。 Moment.js 将使解析和格式化变得更容易,但这不是绝对必需的。

只有少数场景需要时区库(例如 moment-timezone 或其他)。

  • 您希望与本地时区或 UTC 的区域进行转换。

  • 您正在使用过去的日期,并且从那时起,时区规则或夏令时规则发生了变化,并且 您的日期在新规则下的解释与旧规则不同。这有点技术性,但确实会发生。阅读更多 herehere

【讨论】:

  • 感谢马特,提供详尽的信息、链接和指南。我的场景正是您指出的第一个场景:转换不是来自本地时区。也就是说,输入日期和时间的用户也会输入与该时间相关的时区。这不一定是用户所在的时区。我认为我应该在问题中更清楚地说明这一点。
  • 我会说 javascript,“万维网”的编程语言没有内置时间转换/时区工具,这很荒谬
【解决方案2】:

默认构造函数创建本地时间实例

var localDate = new Date(); 

我现在不能测试它,但你应该能够提供你的日期时间(作为构造函数的参数)..

var eventDate = [SOMEDATE];
var localDate = new Date(eventDate);

..然后你应该能够调用像 getMonth 这样的 Date 对象函数,它返回本地时区的数据。如写于:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date

注1:没有服务器=根本没有服务器|数据库?如果有,日期应在 db 中保存为 UTC,并将其加载为每个用户的本地时间。这样您就不必担心转换。

注意2:这个问题有一些代码显示如何获取时区差异:How to get the exact local time of client?

【讨论】:

  • 是的,这通常可以。问题是当用户输入要用于保存日期的明确时区时。想象一下,您在 2013 年 7 月 20 日 10:00 UTC-08:00 提交,同时认为这是在 CA 的时间。但是这个信息是不正确的,因为在那个给定的日期 -07:00 应该用于 UTC 偏移量。这就是我需要检测和解决的问题。正确保存日期后,存储/检索部分很容易。我想避免在进入阶段期间在标准/夏季时间之间做出决定。
【解决方案3】:

我根据其他示例开发了此解决方案...希望这对您有用!可通过jsfiddle 获取。

/* 
* Author: Mohammad M. AlBanna
* Website: MBanna.me
* Description: Get the current time in different time zone 
*/

//Check daylight saving time prototype
Date.prototype.stdTimezoneOffset = function() {
    var jan = new Date(this.getFullYear(), 0, 1);
    var jul = new Date(this.getFullYear(), 6, 1);
    return Math.max(jan.getTimezoneOffset(), jul.getTimezoneOffset());
}

Date.prototype.dst = function() {
    return this.getTimezoneOffset() < this.stdTimezoneOffset();
}

var today = new Date();
var isDST = today.dst() ? true : false;
var pstOffset = isDST ? 7 : 8;
var cstOffset = isDST ? 5 : 6;
var estOffset = isDST ? 4 : 5;
var gmtOffset = 1;

pstOffset = pstOffset * 60 * 60 * 1000;
cstOffset = cstOffset * 60 * 60 * 1000;
estOffset = estOffset * 60 * 60 * 1000;
gmtOffset = gmtOffset * 60 * 60 * 1000;

var todayMillis = today.getTime();
var timeZoneOffset = (today.getTimezoneOffset() * 60 * 1000);

var curretPST = todayMillis - pstOffset; 
var curretCST = todayMillis - cstOffset; 
var curretEST = todayMillis - estOffset;
var curretGMT = todayMillis - gmtOffset;

addP("PST Time : " + new Date(curretPST).toUTCString());
addP("CST Time : " + new Date(curretCST).toUTCString());
addP("EST Time : " + new Date(curretEST).toUTCString());
addP("GMT Time : " + new Date(curretGMT).toUTCString());
addP("Local Time : " + new Date(today.getTime() - timeZoneOffset ).toUTCString());

function addP(value){
    var p = document.createElement("p");
    p.innerHTML = value;
    document.body.appendChild(p);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-06-02
    • 2011-07-06
    • 1970-01-01
    • 2020-06-08
    • 2017-06-20
    • 2015-10-01
    • 1970-01-01
    • 2015-12-31
    相关资源
    最近更新 更多