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

问题描述 投票:0回答:3

我的场景是这样的:

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

假设他们预订了早上 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
javascript angular momentjs
3个回答
2
投票
  • 如果您没有进行任何日期时间转换(如您的示例),而只是更改字符串末尾的时区偏移量,则只需执行字符串操作,如下所示:
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
  • 如果您需要转换完整的日期和时间,因为您正在使用 momentjs,您可以改用 moment-timezone:https://momentjs.com/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
  • 如果要获取时区偏移字符串,同样使用moment-timezone:
let ukd = "2019-10-27T01:59:00".split('T')
let finalDate = moment.tz(ukd[0] + "T" + ukd[1], "YYYY-MM-DDTHH:mm:ss", true, "Europe/London").tz('Europe/London').format('Z');
console.log(finalDate) // last minute still in DST, outputs +01:00

ukd = "2019-10-27T02:01:00".split('T')
finalDate = moment.tz(ukd[0] + "T" + ukd[1], "YYYY-MM-DDTHH:mm:ss", true, "Europe/London").tz('Europe/London').format('Z');
console.log(finalDate)  // first minute after DST, outputs +00:00

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


2
投票

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

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

解释一下:

  1. 我们解析字符串,解释字符串在新西兰,但将其转换为本地时间,可能是也可能不是+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()

0
投票

如何创建新的

Date
并将时区设置为 UTC,但值直接从原始
Date
传递,如下所示:

function changeTimezoneToUtc(date: Date): Date {
  return new Date(Date.UTC(date.getFullYear(), date.getMonth(),
    date.getDate(), date.getHours(),
    date.getMinutes(), date.getSeconds(), date.getMilliseconds()));
}

以上是打字稿,当然可以省略类型。

© www.soinside.com 2019 - 2024. All rights reserved.