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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18014341/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-27 10:27:08  来源:igfitidea点击:

How to convert time correctly across timezones?

javascriptdatedatetimetimezonetimezone-offset

提问by rdamborsky

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

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

Worldwide beer marathon starts on 8/15/2013 10:00 am, UTC-08:00

全球啤酒马拉松于2013 年 815 日上午 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

2013/8/15 19:00

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

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

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.

有没有一种方法,在JavaScript中没有外部Web服务,做正确的转换?也就是说,要检测 10am UTC-08:00 实际上应该是 10am UTC-07:00,因为它是夏令时。

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-08:00(PST)还是UTC-07:00(PDT)。我认为由于 CA 的标准时区是 PST,人们不会在夏季转而使用 PDT。还是他们?!

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.

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

Update:

更新:

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"

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

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

Any other way, using browser APIs?

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

回答by Matt Johnson-Pint

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.

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

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.

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

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?!

我认为由于 CA 的标准时区是 PST,人们不会在夏季转而使用 PDT。还是他们?!

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.

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

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.)

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

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.

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

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.

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

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

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

Moment-timezoneis 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:

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

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

    or using moment.js:

    var m = moment("8/15/2013 10:00", "M/D/YYYY HH:mm");
    
  3. Because this is being done on the user's computer, JavaScript will automatically assume that this is a localdate and time. You do not need to provide any offset or time zone information.

  4. 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");
    
  5. Once you have a Date(or a moment), then you can evaluate its UTC equivalent:

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

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

    var s = m.toISOString();  //  2013-08-15T17:00:00Z
    
  6. You store that UTC value in your database.

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

  8. You feed it in to a Dateor momentin JavaScript:

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

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

    var m = moment("2013-08-15T17:00:00Z")
    
  9. 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)"
    

    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"
    

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

    var s = m.format("llll"); // "Thu, 15 Aug 2013 19:00"
    
  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. 你将它输入到 aDatemomentJavaScript 中:

    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"
    

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.

总而言之 - 如果您只对与本地时区(无论可能是哪个区域)之间的转换感兴趣,那么您只需使用Date. Moment.js 将使解析和格式化变得更容易,但这并不是绝对必需的。

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

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

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

  • You are working with dates that are in the past, andthere has been a change to the time zone rules or daylight saving time rules since then, andyou 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 hereand here.

  • 您想要在本地时区或 UTC的区域之间进行转换。

  • 您正在使用日期是在过去的工作,出现了变化,因为随后的时区规则和夏令时规则,并且你有不同的会根据新的规则来解释比旧的日期。这有点技术性,但确实发生了。在这里这里阅读更多。

回答by Damb

Default constructor creates instance of local time

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

var localDate = new Date(); 

I can't test it right now, but you should be able to provide your datetime (as a parameter to the constructor)..

我现在无法对其进行测试,但是您应该能够提供您的日期时间(作为构造函数的参数)。

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

..and then you should be able to call Date object functions like getMonth, which returns data in local timezone. As written at: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date

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

Note1: Without server = there is no server|db at all? If there is, the date should be saved as UTC in db and load it as local time for every user.. that way you don't have to worry conversions.

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

Note2: This question has some code showing how to get timezone difference: How to get the exact local time of client?

注2:这个问题有一些代码显示了如何获取时区差异:如何获取客户端的确切本地时间?

回答by Mohammad AlBanna

I developed this solution based on other examples...hope this works for you! Available on jsfiddle.

我根据其他示例开发了这个解决方案......希望这对你有用!在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);
}