如何将 JavaScript 日期初始化为特定时区
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15141762/
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
How to initialize a JavaScript Date to a particular time zone
提问by pavanred
I have date time in a particular timezone as a string and I want to convert this to the local time. But, I don't know how to set the timezone in the Date object.
我将特定时区中的日期时间作为字符串,我想将其转换为本地时间。但是,我不知道如何在 Date 对象中设置时区。
For example, I have Feb 28 2013 7:00 PM ET,
then I can
例如,我有Feb 28 2013 7:00 PM ET,
那么我可以
var mydate = new Date();
mydate.setFullYear(2013);
mydate.setMonth(02);
mydate.setDate(28);
mydate.setHours(7);
mydate.setMinutes(00);
As far as I know, I can either set the UTC time or local time. But, how do I set time in another timezone?
据我所知,我可以设置 UTC 时间或本地时间。但是,如何在另一个时区设置时间?
I tried to use the add/subtract the offset from UTC but I don't know how to counter daylight savings. Am not sure if I am heading the right direction.
我尝试使用从 UTC 中添加/减去偏移量,但我不知道如何应对夏令时。不确定我是否朝着正确的方向前进。
How can I go about converting time from a different timezone to local time in javascript?
如何在javascript中将时间从不同的时区转换为本地时间?
回答by Matt Johnson-Pint
Background
背景
JavaScript's Date
object tracks time in UTC internally, but typically accepts input and produces output in the local time of the computer it's running on. It has very few facilities for working with time in other time zones.
JavaScript 的Date
对象在内部以 UTC 时间跟踪时间,但通常接受输入并在运行它的计算机的本地时间生成输出。它很少有用于处理其他时区时间的设施。
The internal representation of a Date
object is a single number, representing the number of milliseconds that have elapsed since 1970-01-01 00:00:00 UTC
, without regard to leap seconds. There is no time zone or string format stored in the Date object itself.When various functions of the Date
object are used, the computer's local time zone is applied to the internal representation. If the function produces a string, then the computer's locale information may be taken into consideration to determine how to produce that string. The details vary per function, and some are implementation-specific.
Date
对象的内部表示是单个数字,表示自 以来经过的毫秒数1970-01-01 00:00:00 UTC
,不考虑闰秒。 Date 对象本身中没有存储时区或字符串格式。当Date
使用对象的各种功能时,将计算机的本地时区应用于内部表示。如果该函数生成一个字符串,则可以考虑计算机的区域设置信息来确定如何生成该字符串。细节因函数而异,有些是特定于实现的。
The only operations the Date
object can do with non-local time zones are:
Date
对象可以对非本地时区执行的唯一操作是:
It can parse a string containing a numeric UTC offset from any time zone. It uses this to adjust the value being parsed, and stores the UTC equivalent. The original local time and offset are not retained in the resulting
Date
object. For example:var d = new Date("2020-04-13T00:00:00.000+08:00"); d.toISOString() //=> "2020-04-12T16:00:00.000Z" d.valueOf() //=> 1586707200000 (this is what is actually stored in the object)
In environments that have implemented the ECMASCript Internationalization API(aka "Intl"), a
Date
object can produce a locale-specific string adjusted to a given time zone identifier. This is accomplished via thetimeZone
option totoLocaleString
and its variations. Most implementations will support IANA time zone identifiers, such as'America/New_York'
. For example:var d = new Date("2020-04-13T00:00:00.000+08:00"); d.toLocaleString('en-US', { timeZone: 'America/New_York' }) //=> "4/12/2020, 12:00:00 PM" // (midnight in China on Apring 13th is noon in New York on April 12th)
Most modern environments support the full set of IANA time zone identifiers (see the compatibility table here). However, keep in mind that the only identifier requiredto be supported by Intl is
'UTC'
, thus you should check carefully if you need to support older browsers or atypical environments (for example, lightweight IoT devices).
它可以解析包含来自任何时区的数字 UTC 偏移量的字符串。它使用它来调整正在解析的值,并存储 UTC 等效值。原始本地时间和偏移量不会保留在结果
Date
对象中。例如:var d = new Date("2020-04-13T00:00:00.000+08:00"); d.toISOString() //=> "2020-04-12T16:00:00.000Z" d.valueOf() //=> 1586707200000 (this is what is actually stored in the object)
在已实现ECMASCRipt 国际化 API(又名“Intl”)的环境中,
Date
对象可以生成调整为给定时区标识符的特定于区域设置的字符串。这是通过timeZone
选项 totoLocaleString
及其变体来实现的。大多数实现将支持 IANA 时区标识符,例如'America/New_York'
. 例如:var d = new Date("2020-04-13T00:00:00.000+08:00"); d.toLocaleString('en-US', { timeZone: 'America/New_York' }) //=> "4/12/2020, 12:00:00 PM" // (midnight in China on Apring 13th is noon in New York on April 12th)
大多数现代环境都支持全套 IANA 时区标识符(请参阅此处的兼容性表)。但是,请记住Intl需要支持的唯一标识符是
'UTC'
,因此您应该仔细检查是否需要支持旧浏览器或非典型环境(例如,轻量级 IoT 设备)。
Libraries
图书馆
There are several libraries that can be used to work with time zones. Though they still cannot make the Date
object behave any differently, they typically implement the standard IANA timezone database and provide functions for using it in JavaScript. Modern libraries use the time zone data supplied by the Intl API, but older libraries typically have overhead, especially if you are running in a web browser, as the database can get a bit large. Some of these libraries also allow you to selectively reduce the data set, either by which time zones are supported and/or by the range of dates you can work with.
有几个库可用于处理时区。尽管他们仍然无法使Date
对象表现出任何不同,但他们通常实现标准的 IANA 时区数据库并提供在 JavaScript 中使用它的函数。现代库使用 Intl API 提供的时区数据,但较旧的库通常有开销,尤其是当您在 Web 浏览器中运行时,因为数据库可能会变得有点大。其中一些库还允许您有选择地减少数据集,或者根据支持的时区和/或您可以使用的日期范围。
Here are the libraries to consider:
以下是要考虑的库:
Intl-based Libraries
基于国际的图书馆
New development should choose from one of these implementations, which rely on the Intl API for their time zone data:
新的开发应该从这些实现中选择一种,它们依赖于 Intl API 来获取时区数据:
- Luxon(successor of Moment.js)
- date-fns-tz(extension for date-fns)
Non-Intl Libraries
非国际图书馆
These libraries are maintained, but carry the burden of packaging their own time zone data, which can be quite large.
这些库得到维护,但承担着打包它们自己的时区数据的负担,这可能非常大。
- js-joda/timezone(extension for js-joda)
- moment-timezone* (extension for Moment.js)
- date-fns-timezone(extension for older 1.x of date-fns)
- BigEasy/TimeZone
- tz.js
- js-joda/timezone(js-joda 的扩展)
- 时刻时区*(Moment.js 的扩展)
- date-fns-timezone(旧 1.x 的date-fns 的扩展)
- BigEasy/时区
- js.js
* While Moment and Moment-Timezone were previously recommended, the Moment team now prefers users chose Luxon for new development.
* 虽然之前推荐了 Moment 和 Moment-Timezone,但 Moment 团队现在更喜欢用户选择 Luxon 进行新开发。
Discontinued Libraries
停产的图书馆
These libraries have been officially discontinued and should no longer be used.
这些库已正式停产,不应再使用。
Future Proposals
未来的提案
The TC39 Temporal Proposalaims to provide a new set of standard objects for working with dates and times in the JavaScript language itself. This will include support for a time zone aware object.
该TC39颞议案旨在提供一套新的标准对象的日期和时间的JavaScript语言本身的工作。这将包括对时区感知对象的支持。
回答by commonpike
As Matt Johnson said
正如马特约翰逊所说
If you can limit your usage to modern web browsers, you can now do the following without any special libraries:
new Date().toLocaleString("en-US", {timeZone: "America/New_York"})
This isn't a comprehensive solution, but it works for many scenarios that require only output conversion (from UTC or local time to a specific time zone, but not the other direction).
如果您可以将使用限制为现代 Web 浏览器,那么您现在可以在没有任何特殊库的情况下执行以下操作:
new Date().toLocaleString("en-US", {timeZone: "America/New_York"})
这不是一个全面的解决方案,但它适用于许多只需要输出转换(从 UTC 或本地时间到特定时区,而不是其他方向)的场景。
So although the browser can not read IANA timezones when creating a date, or has any methods to change the timezones on an existing Date object, there seems to be a hack around it:
因此,尽管浏览器在创建日期时无法读取 IANA 时区,或者有任何方法可以更改现有 Date 对象上的时区,但似乎存在一个问题:
function changeTimezone(date, ianatz) {
// suppose the date is 12:00 UTC
var invdate = new Date(date.toLocaleString('en-US', {
timeZone: ianatz
}));
// then invdate will be 07:00 in Toronto
// and the diff is 5 hours
var diff = date.getTime() - invdate.getTime();
// so 12:00 in Toronto is 17:00 UTC
return new Date(date.getTime() + diff);
}
// E.g.
var there = new Date();
var here = changeTimezone(there, "America/Toronto");
console.log(`Here: ${here.toString()}\nToronto: ${there.toString()}`);
回答by maowtm
You can specify a time zone offset on new Date()
, for example:
您可以在 上指定时区偏移量new Date()
,例如:
new Date('Feb 28 2013 19:00:00 EST')
or
或者
new Date('Feb 28 2013 19:00:00 GMT-0500')
Since Date
store UTC time ( i.e. getTime
returns in UTC ), javascript will them convert the time into UTC, and when you call things like toString
javascript will convert the UTC time into browser's local timezone and return the string in local timezone, i.e. If I'm using UTC+8
:
由于Date
存储 UTC 时间(即getTime
以 UTC 返回),javascript 会将时间转换为 UTC,并且当您调用诸如toString
javascript 之类的东西时,会将 UTC 时间转换为浏览器的本地时区并返回本地时区中的字符串,即如果我正在使用UTC+8
:
> new Date('Feb 28 2013 19:00:00 GMT-0500').toString()
< "Fri Mar 01 2013 08:00:00 GMT+0800 (CST)"
Also you can use normal getHours/Minute/Second
method:
您也可以使用普通getHours/Minute/Second
方法:
> new Date('Feb 28 2013 19:00:00 GMT-0500').getHours()
< 8
( This 8
means after the time is converted into my local time - UTC+8
, the hours number is 8
. )
(这8
意味着将时间转换为我的本地时间 - 后UTC+8
,小时数为8
. )
回答by chickens
This should solve your problem, please feel free to offer fixes. This method will account also for daylight saving time for the given date.
这应该可以解决您的问题,请随时提供修复。此方法还将考虑给定日期的夏令时。
dateWithTimeZone = (timeZone, year, month, day, hour, minute, second) => {
let date = new Date(Date.UTC(year, month, day, hour, minute, second));
let utcDate = new Date(date.toLocaleString('en-US', { timeZone: "UTC" }));
let tzDate = new Date(date.toLocaleString('en-US', { timeZone: timeZone }));
let offset = utcDate.getTime() - tzDate.getTime();
date.setTime( date.getTime() + offset );
return date;
};
How to use with timezone and local time:
如何使用时区和本地时间:
dateWithTimeZone("America/Los_Angeles",2019,8,8,0,0,0)
回答by Shaun Cockerill
I found the most supported way to do this, without worrying about a third party library, was by using getTimezoneOffset
to calculate the appropriate timestamp, or update the time then use the normal methods to get the necessary date and time.
我发现最受支持的方法是使用getTimezoneOffset
计算适当的时间戳,或更新时间然后使用常规方法获取必要的日期和时间,而不用担心第三方库。
var mydate = new Date();
mydate.setFullYear(2013);
mydate.setMonth(02);
mydate.setDate(28);
mydate.setHours(7);
mydate.setMinutes(00);
// ET timezone offset in hours.
var timezone = -5;
// Timezone offset in minutes + the desired offset in minutes, converted to ms.
// This offset should be the same for ALL date calculations, so you should only need to calculate it once.
var offset = (mydate.getTimezoneOffset() + (timezone * 60)) * 60 * 1000;
// Use the timestamp and offset as necessary to calculate min/sec etc, i.e. for countdowns.
var timestamp = mydate.getTime() + offset,
seconds = Math.floor(timestamp / 1000) % 60,
minutes = Math.floor(timestamp / 1000 / 60) % 60,
hours = Math.floor(timestamp / 1000 / 60 / 60);
// Or update the timestamp to reflect the timezone offset.
mydate.setTime(mydate.getTime() + offset);
// Then Output dates and times using the normal methods.
var date = mydate.getDate(),
hour = mydate.getHours();
EDIT
编辑
I was previously using UTC
methods when performing the date transformations, which was incorrect. With adding the offset to the time, using the local get
functions will return the desired results.
我以前UTC
在执行日期转换时使用过方法,这是不正确的。通过将偏移量添加到时间,使用本地get
函数将返回所需的结果。
回答by JRulle
I ran into a similar problem with unit tests (specifically in jest when the unit tests run locally to create the snapshots and then the CI server runs in (potentially) a different timezone causing the snapshot comparison to fail). I mocked our Date
and some of the supporting methods like so:
我在单元测试中遇到了类似的问题(特别是当单元测试在本地运行以创建快照,然后 CI 服务器在(可能)不同的时区运行导致快照比较失败时,开玩笑)。我嘲笑我们的Date
和一些支持方法,如下所示:
describe('...', () => {
let originalDate;
beforeEach(() => {
originalDate = Date;
Date = jest.fn(
(d) => {
let newD;
if (d) {
newD = (new originalDate(d));
} else {
newD = (new originalDate('2017-05-29T10:00:00z'));
}
newD.toLocaleString = () => {
return (new originalDate(newD.valueOf())).toLocaleString("en-US", {timeZone: "America/New_York"});
};
newD.toLocaleDateString = () => {
return (new originalDate(newD.valueOf())).toLocaleDateString("en-US", {timeZone: "America/New_York"});
};
newD.toLocaleTimeString = () => {
return (new originalDate(newD.valueOf())).toLocaleTimeString("en-US", {timeZone: "America/New_York"});
};
return newD;
}
);
Date.now = () => { return (Date()); };
});
afterEach(() => {
Date = originalDate;
});
});
回答by Sandeep Chowdary
Try using ctoc from npm. https://www.npmjs.com/package/ctoc_timezone
尝试使用 npm 中的 ctoc。 https://www.npmjs.com/package/ctoc_timezone
It has got simple functionality to change timezones (most timezones around 400) and all custom formats u want it to display.
它具有更改时区的简单功能(大多数时区在 400 左右)以及您希望它显示的所有自定义格式。
回答by zerkotin
I know its 3 years too late, but maybe it can help someone else because I haven't found anything like that except for the moment-timezone library, which is not exactly the same as what he's asking for here.
我知道它已经晚了 3 年,但也许它可以帮助其他人,因为除了 moment-timezone 库之外,我还没有找到类似的东西,这与他在这里要求的不完全相同。
I've done something similar for german timezone, this is a little complex because of daylight saving time and leap years where you have 366 days.
我为德国时区做了类似的事情,这有点复杂,因为夏令时和闰年有 366 天。
it might need a little work with the "isDaylightSavingTimeInGermany" function while different timezones change on different times the daylight saving time.
它可能需要使用“isDaylightSavingTimeInGermany”函数做一些工作,而不同的时区在夏令时的不同时间会发生变化。
anyway, check out this page: https://github.com/zerkotin/german-timezone-converter/wiki
无论如何,请查看此页面:https: //github.com/zerkotin/german-timezone-converter/wiki
the main methods are: convertLocalDateToGermanTimezone convertGermanDateToLocalTimezone
主要方法有: convertLocalDateToGermanTimezone convertGermanDateToLocalTimezone
I've put an effort into documenting it, so it won't be so confusing.
我已经努力记录它,所以它不会那么混乱。
回答by Shane
Building on the answers above, I am using this native one liner to convert the long timezone string to the three letter string:
基于上面的答案,我使用这个本机单行将长时区字符串转换为三个字母的字符串:
var longTz = 'America/Los_Angeles';
var shortTz = new Date().
toLocaleString("en", {timeZoneName: "short", timeZone: longTz}).
split(' ').
pop();
This will give PDT or PST depending on the date provided. In my particular use case, developing on Salesforce (Aura/Lightning), we are able to get the user timezone in the long format from the backend.
这将根据提供的日期提供 PDT 或 PST。在我的特定用例中,在 Salesforce(Aura/Lightning)上开发,我们能够从后端以长格式获取用户时区。
回答by Mariusz Nowak
Try: date-from-timezone, it resolves expected date with help of natively available Intl.DateTimeFormat
.
尝试:date-from-timezone,它在本机可用的帮助下解析预期日期Intl.DateTimeFormat
。
I used that method in one of my projects for few years already, but it's now I decided to publish it as small OS project :)
我已经在我的一个项目中使用这种方法几年了,但现在我决定将它作为小型操作系统项目发布:)