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

时间:2013-08-02 10:10:20

标签: javascript date datetime timezone timezone-offset

让我们说美国加州的用户选择日期,时间和时区:

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

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

2013年8月15日19:00

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

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

也许我从一开始就错误地理解了这一点,但我不想让进入的用户考虑是否应该选择UTC-08:00(太平洋标准时间)或UTC-07:00(PDT) 。我认为,由于CA中的标准时区是PST,人们不会在夏天转向思考PDT。或者他们?!

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

更新

经过一番思考和阅读评论之后,理想情况下我需要的是:

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的其他任何方式?

3 个答案:

答案 0 :(得分:22)

  

有没有办法在javascript中,没有外部网络服务,才能进行正确的转换?也就是说,要检测UTC上午10点UTC应该实际上是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"
    
  10. 总结一下 - 如果您只想转换到本地时区(无论可能是哪个区域),那么您只需Date即可完成所有操作。 Moment.js将使解析和格式化变得更容易,但并不是绝对必需的。

    只有少数情况需要时区库(例如时刻时区或其他)。

    • 您希望转换为本地时区或UTC的区域。

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

答案 1 :(得分:1)

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

var localDate = new Date(); 

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

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

..然后你应该能够调用Date对象函数,比如getMonth,它以本地时区返回数据。如下所示:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date

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

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

答案 2 :(得分:1)

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