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

时间:2013-02-28 17:22:33

标签: javascript timezone

我将特定时区的日期时间作为字符串,我想将其转换为当地时间。但是,我不知道如何在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中将时间从不同的时区转换为当地时间?

15 个答案:

答案 0 :(得分:226)

背景

JavaScript的Date对象在内部以UTC格式跟踪时间,但通常在其运行的计算机的本地时间内接受输入和输出。它没有任何在其他时区使用时间的设施。它可以解析并输出UTC或Local的日期,但 它不能直接用于其他时区

绝对准确地说,Date对象的内部表示是一个数字,表示自1970-01-01 00:00:00 UTC以来经过的毫秒数,而不考虑闰秒。 Date对象本身没有存储时区或字符串格式。当使用Date对象的各种功能时,计算机的本地时区将应用于内部表示。如果函数生成字符串,则可以考虑计算机的区域设置信息以确定如何生成该字符串。细节因功能而异,有些是特定于实现的。

幸运的是,有些库可用于处理时区。虽然它们仍然无法使Date对象的行为有所不同,但它们通常实现标准的Olson / IANA时区数据库,并提供在JavaScript中使用它的功能。如果您在Web浏览器中运行,有些会产生开销,因为如果您想要整个数据库,数据库可能会变得有点大。幸运的是,许多这些库允许您有选择地选择要支持的区域,使数据大小更加可口。还有一些使用现代功能从Intl API获取时区数据,而不必自己发送。

我知道有几个这样的库:

Luxon可能是所有现代用途中最安全的选择,并且是最轻的权重,因为它使用Intl API作为其时区数据。

Moment-timezone是moment.js的扩展,带来自己的时区数据。

js-joda是Joda-Time API的JavaScript实现(来自Java),并通过单独的模块提供时区支持。

date-fns-tz是date-fns 2.x的扩展名。 date-fns-timezone是date-fns 1.x。

的扩展名

BigEasy / TimeZone似乎也在正确的轨道上。

WallTime-js has reached end-of-life,所有者正在迁移到时刻时区。

TimeZoneJS已经存在时间最长,但已知有一些长期存在的错误,特别是在夏令时转换时。希望这些将在未来的某个时刻得到修复。

tz.js已经存在了一段时间,但记录不是很好,恕我直言。

您应该评估这些库以查看哪些库可以满足您的需求。如果不确定,请使用时刻/时刻 - 时区。

现代环境中的原生支持

如果您可以将您的使用限制在现代环境中,现在可以在没有任何特殊库的情况下执行以下操作:

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

这不是一个全面的解决方案,但它适用于只需要输出转换的许多场景(从UTC或本地时间到特定时区,但不是另一个方向)。这是ECMAScript国际化API(ECMA-402)的一部分。有关详细信息,请参阅this postThis compatibility table跟踪支持的版本。这是上面提到的Intl API,某些库现在在内部使用。

(很明显,这不会初始化Date对象,但可以在生成特定于语言环境的字符串表示时用于应用时区。)

未来提案

TC39 Temporal Proposal旨在提供一组新的标准对象,用于处理JavaScript语言本身的日期和时间。这将包括对时区感知对象的支持。

答案 1 :(得分:16)

您可以在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,当您调用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)"

您也可以使用普通getHours/Minute/Second方法:

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

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

答案 2 :(得分:16)

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

  

如果您可以将使用范围限制在现代网络浏览器中,则现在可以   以下没有任何特殊的库:

     

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

   }

用法

var there = new Date(when);
var here = changeTimezone(there,"America/Toronto");

答案 3 :(得分:6)

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

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)

答案 4 :(得分:3)

我遇到了同样的问题,但我们可以使用我们想要的时区
我们使用 .toLocaleDateString()

例如:

var day=new Date();
const options= {day:'numeric', month:'long', year:"numeric", timeZone:"Asia/Kolkata"};
const today=day.toLocaleDateString("en-IN", options);
console.log(today);

答案 5 :(得分:2)

我知道它的3年已经太晚了,但也许它可以帮助别人,因为除了时间 - 时区库之外,我发现了类似的东西,这与他在这里所要求的并不完全相同。

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

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

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

主要方法是: convertLocalDateToGermanTimezone convertGermanDateToLocalTimezone

我努力记录它,所以它不会那么令人困惑。

答案 6 :(得分:2)

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

});

答案 7 :(得分:2)

我发现最受支持的方法,而不必担心第三方库,是使用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函数将返回所需的结果。

答案 8 :(得分:1)

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

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

答案 9 :(得分:0)

尝试:date-from-timezone,它会在原生SCGeometryElement的帮助下解析预计日期。

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

答案 10 :(得分:0)

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

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

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

答案 11 :(得分:0)

对于Ionic用户,我很难受,因为.toISOString()必须与html模板一起使用。

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

我通过以下方法解决了这个问题:

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

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

答案 12 :(得分:0)

也许这会对您有所帮助

/**
 * 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')
);

答案 13 :(得分:0)

//For mumbai time diffrence is 5.5 hrs so
// city_time_diff=5.5 (change according to your city) 

let timee= Date.now()
    timee=timee+(3600000*city_time_diff); //Add our city time (in msec) 
    let new_date=new Date(timee)
console.log("My city time is: ",new_date);

答案 14 :(得分:-2)

遇到同样的问题,使用了这个

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

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