如何将JavaScript日期初始化为特定时区

2020/10/09 13:01 · javascript ·  · 0评论

我有一个特定时区中的日期时间作为字符串,我想将其转换为本地时间。但是,我不知道如何在Date对象中设置时区。

例如,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);  

据我所知,我可以设置UTC时间或本地时间。但是,如何设置其他时区的时间?

我尝试使用加/减UTC的偏移量,但是我不知道如何应对夏令时。不知道我是否朝着正确的方向前进。

如何在javascript中将时间从其他时区转换为本地时间?

背景

JavaScript的Date对象在内部跟踪UTC的时间,但通常在运行它的计算机的本地时间接受输入并产生输出。它几乎没有其他地方的时间来处理时间。

Date对象的内部表示形式是单个数字,表示自以来经过的毫秒数1970-01-01 00:00:00 UTC,而与leap秒无关。 Date对象本身没有存储时区或字符串格式。Date使用对象的各种功能时,计算机的本地时区将应用于内部表示。如果函数产生一个字符串,则可以考虑计算机的语言环境信息以确定如何产生该字符串。具体细节因功能而异,有些具体取决于实现。

唯一的操作Date对象可以用非本地时区做是:

  • 它可以解析包含任何时区的数字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(又称“国际”)的环境中,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)
    

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

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.

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:

非国际图书馆

这些库得到维护,但负担打包自己的时区数据的负担,这可能会很大。

*虽然以前建议使用Moment和Moment-Timezone,但Moment团队现在更喜欢用户选择Luxon进行新开发。

停产的图书馆

这些库已正式停产,不应再使用。

未来提案

TC39颞议案旨在提供一套新的标准对象的日期和时间的JavaScript语言本身的工作。这将包括对时区感知对象的支持。

正如马特·约翰逊(Matt Johnson)所说

如果您可以将使用限制为现代Web浏览器,则现在可以执行以下操作而无需任何特殊的库:

new Date().toLocaleString("en-US", {timeZone: "America/New_York"})

这不是一个全面的解决方案,但是它适用于仅需要输出转换(从UTC或本地时间到特定时区,而不是其他方向)的许多情况。

因此,尽管浏览器在创建日期时无法读取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()}`);

您可以在上指定时区偏移量new Date(),例如:

new Date('Feb 28 2013 19:00:00 EST')

要么

new Date('Feb 28 2013 19:00:00 GMT-0500')

由于Date存储UTC时间(即getTime以UTC返回),因此javascript会将它们将时间转换为UTC,并且当您调用toStringjavascript之类的东西时,会将utc时间转换为浏览器的本地时区并返回本地时区的字符串,即如果我正在使用UTC+8

> new Date('Feb 28 2013 19:00:00 GMT-0500').toString()
< "Fri Mar 01 2013 08:00:00 GMT+0800 (CST)"

您也可以使用常规getHours/Minute/Second方法:

> new Date('Feb 28 2013 19:00:00 GMT-0500').getHours()
< 8

(这8表示将时间转换为我的当地时间后UTC+8,小时数为8。)

这应该可以解决您的问题,请随时提供修复程序。此方法还将考虑给定日期的夏时制时间。

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;
};

如何使用时区和当地时间:

dateWithTimeZone("America/Los_Angeles",2019,8,8,0,0,0)

我发现执行此操作的最受支持的方法而不必担心第三方库,方法是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();

编辑

我以前UTC在执行日期转换时使用的方法是错误的。通过将偏移量与时间相加,使用本地get函数将返回所需的结果。

我在单元测试中遇到了类似的问题(特别是在单元测试在本地运行以创建快照,然后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;
  });

});

尝试从npm使用ctoc。
https://www.npmjs.com/package/ctoc_timezone

它具有更改时区(大多数时区大约为400)和您要显示的所有自定义格式的简单功能。

在上面的答案的基础上,我正在使用本机的一个衬纸将长时区字符串转换为三个字母字符串:

var longTz = 'America/Los_Angeles';
var shortTz = new Date().
    toLocaleString("en", {timeZoneName: "short", timeZone: longTz}).
    split(' ').
    pop();

这将根据提供的日期提供PDT或PST。在我的特定用例中,在Salesforce(Aura / Lightning)上进行开发,我们可以从后端获取长格式的用户时区。

对于Ionic用户,我对此感到非常痛苦,因为.toISOString()必须将其与html模板一起使用。

这将获取当前日期,但是当然可以将其添加到选定日期的先前答案中。

我用这个解决了:

date = new Date();
public currentDate: any = new Date(this.date.getTime() - this.date.getTimezoneOffset()*60000).toISOString();

* 60000表示UTC -6是CST,因此无论需要什么TimeZone,都可以更改数量和差异。

我知道它的3年为时已晚,但是也许可以帮助其他人,因为除了矩时区库(除了他在这里要求的不完全一样)之外,我没有找到其他类似的东西。

我在德国时区做了类似的事情,这有点复杂,因为夏令时和leap年有366天。

它可能需要使用“ isDaylightSavingTimeInGermany”功能进行一些工作,而不同的时区会在夏令时的不同时间改变。

无论如何,请查看此页面:https :
//github.com/zerkotin/german-timezone-converter/wiki

主要方法是:convertLocalDateToGermanTimezone convertGermanDateToLocalTimezone

我已经尽力将其记录在文档中,因此不会那么混乱。

尝试:date-from-timezone,它在本地可用的帮助下解析预期的日期Intl.DateTimeFormat

我已经在我的一个项目中使用该方法几年了,但是现在我决定将其发布为小型OS项目:)

也许这对您有帮助

/**
 * Shift any Date timezone.
 * @param {Date} date - Date to update.
 * @param {string} timezone - Timezone as `-03:00`.
 */
function timezoneShifter(date, timezone) {
  let isBehindGTM = false;
  if (timezone.startsWith("-")) {
    timezone = timezone.substr(1);
    isBehindGTM = true;
  }

  const [hDiff, mDiff] = timezone.split(":").map((t) => parseInt(t));
  const diff = hDiff * 60 + mDiff * (isBehindGTM ? 1 : -1);
  const currentDiff = new Date().getTimezoneOffset();

  return new Date(date.valueOf() + (currentDiff - diff) * 60 * 1000);
}



const _now = new Date()
console.log(
  [
    "Here: " + _now.toLocaleString(),
    "Greenwich: " + timezoneShifter(_now, "00:00").toLocaleString(),
    "New York: " + timezoneShifter(_now, "-04:00").toLocaleString(),
    "Tokyo: " + timezoneShifter(_now, "+09:00").toLocaleString(),
    "Buenos Aires: " + timezoneShifter(_now, "-03:00").toLocaleString(),
  ].join('\n')
);

面临同样的问题,用过这个

Console.log(Date.parse(“ 2018年6月13日10:50:39 GMT + 1”));

它将返回毫秒,您可以检查到毫秒数,以+100 timzone初始化英国时间希望对您有所帮助!

本文地址:http://javascript.askforanswer.com/ruhejiangjavascriptriqichushihuaweitedingshiqu.html
文章标签: ,  
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!

文件下载

老薛主机终身7折优惠码boke112

上一篇:
下一篇:

评论已关闭!