如何在不更改日期值的情况下更改时区

时间:2019-07-27 23:35:39

标签: javascript angular momentjs

我的情况是这样的:

我有一个日期选择器,它接受来自用户的输入,并且假定选择的日期/时间是本地时间。我似乎无法改变这种行为。用户实际上应该在欧洲/伦敦时间选择日期/时间,因为他们当时正在伦敦预订服务。

让我们说他们正在预订早上5点从伦敦起飞的航班。

所以我有这个日期(用户来自新西兰):

2019-08-01T05:00:00+12:00 (NZ time)

我需要将其更改为:

2019-08-01T05:00:00+01:00 (Europe/London time)

此后,我将发送到服务器并以UTC存储。

如果有帮助,我正在使用momentjs。

编辑: 最新尝试: 我只需要弄清楚如何从用户输入的确切时间中获取时区偏移量,这样就可以解决夏令时问题。 例如下面我将在前一天获得英国补偿,因此可能会有DST问题

const moment = require('moment-timezone');

const nzd = '2019-08-01T05:00:00+12:00'; // This is the date my user entered via the datepicker

const ukTempString = moment(new Date(nzd.slice(0, -6))).tz('Europe/London').format('YYYY-MM-DDTHH:mm:ssZ'); // 2019-07-31T18:00:00+01:00
const ukOffset = ukTempString.substr(ukTempString.length - 6); // +01:00

const ukString = nzd.slice(0, -6) + ukOffset; // 2019-08-01T05:00:00+01:00
const ukDate = new Date(ukString);  // I can then this to the backend

编辑:

当前解决方案:

在英国没有DST的示例:

 let nzd = moment('2019-10-27T05:00:00+13:00'); // This is the date my user entered via the datepicker
 let nzString = nzd.format('YYYY-MM-DDTHH:mm:ssZ');
 let ukd = moment().tz('Europe/London');

 ukd.set(nzd.toObject());
 console.log(ukd.format('YYYY-MM-DDTHH:mm:ssZ')); // 2019-10-27T05:00:00+00:00

 let ukDate = new Date(ukd.format('YYYY-MM-DDTHH:mm:ssZ')); // I can then this to the backend
 console.log(ukDate.toUTCString()); // Sun, 27 Oct 2019 05:00:00 GMT

在英国示例中具有DST(相同代码):

 nzd = moment('2019-10-27T00:30:00+13:00'); // This is the date my user entered via the datepicker
 nzString = nzd.format('YYYY-MM-DDTHH:mm:ssZ');
 ukd = moment().tz('Europe/London');
 ukd.set(nzd.toObject());

 console.log(ukd.format('YYYY-MM-DDTHH:mm:ssZ')); // 2019-10-27T00:30:00+01:00

 ukDate = new Date(ukd.format('YYYY-MM-DDTHH:mm:ssZ')); // I can then this to the backend
 console.log(ukDate.toUTCString()); // Sat, 26 Oct 2019 23:30:00 GMT

2 个答案:

答案 0 :(得分:1)

  • 如果您不进行任何日期时间转换(例如您的示例),而只是更改字符串末尾的时区偏移量,则只需执行字符串操作即可,如下所示:
import Brand from "./Brand";
  • 如果您需要转换完整的日期和时间(如使用momentjs),则可以使用moment-timezone:https://momentjs.com/timezone/。然后,下面的代码可以解决问题:
var nzd = '2019-08-01T05:00:00+12:00'
var ukd = nzd.slice(0, -6) + '+01:00'
console.log(ukd) // outputs 2019-08-01T05:00:00+01:00
  • 如果要获取时区偏移量字符串,请同时使用moment-timezone:
const moment = require('moment-timezone')
var nz = moment('2019-08-01T05:00:00+12:00')
var uk = nz.tz('Europe/London').format()
console.log(uk) // outputs 2019-07-31T18:00:00+01:00

这似乎很hacky,代码也不干净,但这是由于时区中的bug解析为UTC日期而不是时区日期。

答案 1 :(得分:0)

这是一个更简单的解决方案:

moment("2019-08-01T05:00:00+12:00")
  .parseZone()
  .tz("Europe/London", true)
  .toISOString(true) // => "2019-08-01T05:00:00.000+01:00"

解释一下:

  1. 我们解析该字符串,该字符串将解释为在NZ中,但是将其转换为本地时间,该时间可能是+12,也可能不是+12,具体取决于您的计算机所在的位置
  2. 使用parseZone撤消该转换,以便我们的日期根据原始字符串将其自身视为+12。
  3. 使用tz,但使用keepTime的第二个参数(称为true)将时间转换为伦敦时间,这意味着“而不是将时间保持不变并更改当地时间,请更改该时间以保持本地时间相同。”
  4. 以ISO格式格式化结果,但传递第二个参数(称为keepOffset),告诉它在显示之前不要转换为UTC

那么,那行得通,但是也许最好将时间选择器更改为伦敦时间,这样他们选择的时间已经在您想要的区域了?

编辑,等效的Luxon代码更清晰一些,如果可以解释的话:

DateTime.fromISO("2019-08-01T05:00:00+12:00", { setZone: true })
  .setZone("Europe/London", { keepLocalTime: true} )
  .toISO()