在Javascript中使用不同的时区

时间:2018-12-10 14:38:46

标签: javascript date datetime timezone

我正在开发一个基于云的应用程序,该应用程序为世界各地的用户广泛处理日期和时间值。

考虑一个使用JavaScript的场景,我的机器在印度(格林尼治标准时间+05:30),并且我必须显示一个在加利福尼亚时区(GMT-08:00)运行的时钟。

在这种情况下,我必须获得一个新的日期对象,

let india_date = new Date()

添加时区偏移值,

let uts_ms = india_date.getTime() + india_date.getTimezoneOffset()

添加加利福尼亚的时区偏移值,

let california_ms = utc_ms + getCaliforniaTimezoneOffsetMS()

最后是日期对象。

let california_date: Date = new Date(california_ms)

有什么方法可以直接处理这些时区,而不必一次又一次地转换值?

4 个答案:

答案 0 :(得分:3)

好吧,您确实确实需要在任何时间更改显示,但都没有您想像的那么糟。

首先,将所有时间存储为UTC。可能使用milliseconds format,例如Date.UTC()

第二,使用存储的信息进行所有操作/比较。

第三,如果您的基于云的应用程序具有一个API,那么该API也应该只使用UTC进行通信,尽管您可以提供ISO字符串,而不是MS,或者希望客户更好地处理该字符串。 。

第四,最后,只有在用户界面中,才应使用您描述的方法或使用momentjs

之类的库将最终转换为本地日期/时间字符串。

答案 1 :(得分:2)

JavaScript Date objects以UTC存储日期和时间,但是当日期表示为文本值时会自动调用toString()方法,该文本值在浏览器的本地时区中显示日期和时间。因此,当您要将日期时间转换为本地时间以外的其他时区时,您实际上是在从UTC转换到该时区(而不是从本地时区转换到另一个时区)。

如果您的用例仅限于特定的浏览器并且格式化灵活(由于浏览器显示日期字符串格式的方式可能有所不同),则可以使用toLocaleString(),但是Edge等浏览器, Android Webview等不完全支持localesoptions参数。

下面的示例将区域设置和时区设置为以本地格式输出日期,该格式可能因浏览器而异。

let dt = new Date();

let kolkata = dt.toLocaleString('en-IN', { timeZone: 'Asia/Kolkata' });
let la = dt.toLocaleString('en-US', { timeZone: 'America/Los_Angeles' });

console.log('Kolkata:', kolkata);
// Kolkata: 19/3/2019, 7:36:26 pm
console.log('Los Angeles:', la);
// Los Angeles: 3/19/2019, 7:06:26 AM

您还可以使用Moment.jsMoment Timezone将日期和时间转换为本地时区以外的时区。例如:

let dt = moment();

let kolkata = dt.tz('Asia/Kolkata').format()
let la = dt.tz('America/Los_Angeles').format()

console.log(kolkata);
// 2019-03-19T19:37:11+05:30
console.log(la);
// 2019-03-19T07:07:11-07:00
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.23/moment-timezone-with-data.min.js"></script>

答案 2 :(得分:2)

首先,让我们谈谈您的问题中的代码。

let india_date = new Date()

您已将此变量命名为india_date,但是如果代码在设置为印度时区的计算机上运行,​​则Date对象将仅反映印度。如果它在具有不同时区的计算机上运行,​​它将反映该时区。请记住,在内部,Date对象仅跟踪基于UTC的时间戳。本地时区是在调用需要本地时间的函数和属性时应用的,而不是在创建Date对象时应用。

  

添加时区偏移值

let uts_ms = india_date.getTime() + india_date.getTimezoneOffset()

此方法不正确。 getTime()已返回基于UTC的时间戳。您无需添加本地偏移量。 (而且,缩写是UTC,而不是UTS。)

  

现在添加加利福尼亚的时区偏移值

let california_ms = utc_ms + getCaliforniaTimezoneOffsetMS()

同样,添加偏移量是不正确的。此外,与印度不同,加利福尼亚州实行夏令时,因此一年中的偏移量为480(UTC-8),一年中的偏移量为420(UTC-7) 。任何功能(例如getCaliforniatimezoneOffsetMS)都需要将时间戳记作为参数传递才能生效。

  

最后是日期对象

let california_date: Date = new Date(california_ms)

Date构造函数传递数字时间戳记时,必须使用UTC。传递此california_ms时间戳实际上只是在选择其他时间点。您不能仅通过添加或减去偏移量来更改Date对象的行为以使其使用不同的时区。对于需要本地时间的任何功能,例如.toString()和其他功能,它仍将使用其运行时所在的本地时区。

在只有一种情况下,这种调整才有意义,这是一种称为“时代转移”的技术。调整时间戳以使基本纪元偏离正常的1970-01-01T00:00:00Z,从而允许一个人利用Date对象的UTC函数(例如getUTCHours等)。问题是:一旦转移,您将永远无法在该Date对象上使用任何本地时间函数,或将其传递给其他任何希望Date对象为正常对象的地方。正确完成时移是Moment.js之类的库的强大力量。 Here是正确完成纪元移位的另一个示例。

但是在您的示例中,您正在移动(错误两次),然后使用Date对象,就好像它是正常的并且没有移动一样。这只会导致错误,在toString输出中显示的时区很明显,并且在数学上会在本地时区和预期目标时区的任何DST转换附近出现。通常,您不想采用这种方法。

相反,请阅读我对How to initialize a JavaScript Date to a particular time zone.的回答,那里列出了您的选择。谢谢。

答案 3 :(得分:0)

新日期创建一个Date对象,其时间值为UTC。如果可以保证支持 toLocaleString timeZone 选项(例如,具有受控SOE的公司环境),则可以使用它来构造任何时区和任何格式的时间戳,但可能有点乏味。通用网络上可能缺乏支持。在这种情况下,如果需要可靠地工作,则首选库。

例如要获取加利福尼亚的值,可以对 timeZone 选项使用 toLocaleString 和“ America / Los_Angeles”:

var d = new Date();

// Use the default implementation format
console.log(d.toLocaleString(undefined, {timeZone:'America/Los_Angeles'}));

// Customised format
var weekday = d.toLocaleString(undefined, {weekday:'long', timeZone:'America/Los_Angeles'});
var day = d.toLocaleString(undefined, {day:'numeric', timeZone:'America/Los_Angeles'});
var month = d.toLocaleString(undefined, {month:'long', timeZone:'America/Los_Angeles'});
var year = d.toLocaleString(undefined, {year:'numeric', timeZone:'America/Los_Angeles'});
var hour = d.toLocaleString(undefined, {hour:'numeric',hour12: false, timeZone:'America/Los_Angeles'});
var minute = d.toLocaleString(undefined, {minute:'2-digit', timeZone:'America/Los_Angeles'});
var ap = hour > 11? 'pm' : 'am';
hour = ('0' + (hour % 12 || 12)).slice(-2);

console.log(`The time in Los Angeles is ${hour}:${minute} ${ap} on ${weekday}, ${day} ${month}, ${year}`);

获取时区名称要困难一些,没有其他信息就很难获取。