如何跨时区正确转换时间?

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

Let's say user in CA, US picks up a date, time and timezone:

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

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

Another user, in Central Europe opens the page where this date and time is displayed. He doesn't want to do time calculations (had few beers already). He just wants to see this date and time:

8/15/2013 19:00

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

Given the browser receives the date and time information, as entered by user in California:

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

Is there a way, in javascript, without external web services, to do a correct conversion? That is, to detect that 10am UTC-08:00 should actually be 10am UTC-07:00, since it is Daylight Saving.

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

Maybe I got wrong understanding of this from the beginning, but I don't want to let the entering user to think whether he should choose UTC-08:00 (PST) or UTC-07:00 (PDT). I assume that since the standard timezone in CA is PST, people don't switch to thinking in PDT in summer time. Or do they?!

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

In central Europe, standard date is UTC+01:00, Daylight Saving date is UTC+02:00. So that difference between CA and Europe should be 9 hours, except for two periods in a year, when one or the other area switches between Standard and Daylight Saving modes.

更新:

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

After some more thinking and reading the comments, what I would ideally need is this:

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 插件似乎能够做到这一点(更多或少).

So far, it looks like the moment.js/timezone plugin, suggested by Guido Preite is capable of doing this (more or less).

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

Any other way, using browser APIs?

推荐答案

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

Is there a way, in javascript, without external web services, to do a correct conversion? That is, to detect that 10am UTC-08:00 should actually be 10am UTC-07:00, since it is Daylight Saving.

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

10:00-8 and 10:00-7 are two different moments in time. They are equal to 18:00Z and 17:00Z respectively (Z = UTC). When you are measuring in terms of an offset, daylight saving time does not enter the picture. Ever.

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

I assume that since the standard timezone in CA is PST, people don't switch to thinking in PDT in summer time. Or do they?!

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

In general, people just think in "Pacific Time", and that means both PST in the winter, and PDT in the summer. But computers are more precise. When you see PST, it means UTC-8. When you see PDT, it means UTC-7. It would be invalid to label using one form while simultaneously referring to the offset of the other.

时区缩写可能不明确.理想情况下,以编程方式引用区域时,您应该使用 IANA 区域名称,例如 America/Los_Angeles.但是,目前这在所有没有库的 JavaScript 运行时中是不可能的.(他们正在为此努力.)

Time zone abbreviations can be ambiguous. Ideally, when referencing the zone programmatically, you should use the IANA zone name, such as America/Los_Angeles. However, this is not currently possible in all JavaScript runtimes without a library. (They are working on this though.)

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

In central Europe, standard date is UTC+01:00, Daylight Saving date is UTC+02:00. So that difference between CA and Europe should be 9 hours, except for two periods in a year, when one or the other area switches between Standard and Daylight Saving modes.

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

Correct. They could be either 8, 9, or 10 hours apart. They switch at completely different times though, so don't try to manage this yourself.

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

So far, it looks like the moment.js/timezone plugin, suggested by Guido Preite is capable of doing this (more or less).

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

Moment-timezone is a great library. However, from the scenario you described, I don't think you need to worry about time zone conversion as much as you are thinking. See if you can follow this logic:

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

  1. The user in California enters a date and time into a textbox.
  2. You read that textbox value into a string, and parse it into a date:

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

或使用 moment.js:

or using moment.js:

var m = moment("8/15/2013 10:00", "M/D/YYYY HH:mm");

  • 因为这是在用户的计算机上完成的,所以 JavaScript 会自动假定这是一个本地日期和时间.您无需提供任何偏移量或时区信息.

  • Because this is being done on the user's computer, JavaScript will automatically assume that this is a local date and time. You do not need to provide any offset or time zone information.

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

    This does mean that because of the DST transitions that the time entered might be invalid or ambiguous. JavaScript doesn't do such a great job at handling that, in fact - you will get different results on different browsers. If you want to be unambiguous, then you would provide an offset.

    // 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");
    

  • 一旦你有了一个 Date(或一个 moment),你就可以评估它的 UTC 等效值:

  • Once you have a Date (or a moment), then you can evaluate its UTC equivalent:

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

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

    it's the same with moment.js, but you will have better browser support:

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

  • 您将该 UTC 值存储在数据库中.

  • You store that UTC value in your database.

    另一个中欧用户过来加载数据.

    The other user in Central Europe comes along and loads the data.

    您将其输入到 JavaScript 中的 Datemoment:

    You feed it in to a Date or moment in JavaScript:

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

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

    or with moment.js (again, better browser support)

    var m = moment("2013-08-15T17:00:00Z")
    

  • 由于 JavaScript 知道本地计算机的时区规则,您现在可以显示此日期,它将与中欧时区一起呈现:

  • Because JavaScript knows the time zone rules of the local computer, you can now display this date and it will be presented with the Central Europe time zone:

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

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

    or with moment.js, you can control the output format better

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

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

    you could also let moment.js decide what localized format should be output:

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

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

    To summarize - if you are only interested in converting to and from the local time zone (whatever zone that may be), then you can do it all with just Date. Moment.js will make things easier for parsing and formatting, but it isn't absolutely required.

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

    There are only a few scenarios that require a time zone library (such as moment-timezone or others).

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

    • You want to convert to or from a zone that is not the local time zone or UTC.

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

    You are working with dates that are in the past, and there has been a change to the time zone rules or daylight saving time rules since then, and you have dates that would be interpreted differently under the new rules than with the old ones. This is a bit technical, but it does happen. Read more here and here.

    相关文章