【问题标题】:How to change timezone without changing date value如何在不更改日期值的情况下更改时区
【发布时间】:2019-07-27 23:35:39
【问题描述】:

我的情况是这样的:

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

假设他们预订了早上 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

编辑:

目前的解决方案:

英国没有夏令时示例:

 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

【问题讨论】:

  • 一旦你有了像date = new Date() 这样的JavaScript Date 对象,由于伦敦是UTC 的所在地,你可以很方便地使用date.getTime (时间戳)或任何date.getUTC{{X}} 方法(例如date.getUTCHours)。请参阅:developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…(如果您需要 DST 调整后的伦敦时间,从技术上讲,这不再是 UTC,您需要检查 DST 目前在伦敦是否有效。)

标签: javascript angular momentjs


【解决方案1】:
  • 如果您不进行任何日期时间转换(如您的示例中),而只是更改字符串末尾的时区偏移量,则只需执行字符串操作,如下所示:
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 日期而不是时区日期。

【讨论】:

  • 太棒了。这就是我需要的。我现在有一个几乎完整的解决方案。我已经用底部的最新代码编辑了我的问题。
  • 感谢您的帮助。我认为 DST 的代码不正确,请参见以下示例://英国的夏令时于 2019 年 10 月 27 日星期日凌晨 2:00 结束 const ukd = moment(new Date('2019-10-27T05: 00:00')).tz('欧洲/伦敦'); console.log(ukd.format('YYYY-MM-DDTHH:mm:ssZ')); // 2019-10-26T17:00:00+01:00  当创建一个新日期时,它认为它是当地时间。对我来说新西兰时间。因此,它在不应该应用夏令时。我需要能够为特定时区创建一个日期,而不需要更改它并且不提供偏移量。
  • 我想我有。我在问题的底部添加了一个解决方案。明天我将对此进行更多测试。这些日期真是令人费解。
  • 这真是个问题,我猜是时刻时区的错误引起的,请再次查看我编辑的答案
【解决方案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 将时间转换为伦敦时间,但使用true 的第二个参数(称为keepTime),这意味着“与其保持时间相同并更改本地时间,不如更改什么时间就是保持当地时间不变”。
  4. 以 ISO 格式格式化结果,但传递第二个参数(称为 keepOffset)告诉它在显示前不要转换为 UTC

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

编辑,等效的 Luxon 代码更清晰一些,如果这有助于解释它:

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

【讨论】:

  • 这正是我在尝试并报告之后的样子。是的,理想情况下我想将应用程序时间或日期时间选择器时间修复为伦敦时间,但我无法弄清楚如何做到这一点,因此我的解决方法是。
猜你喜欢
  • 2013-09-10
  • 2018-07-24
  • 1970-01-01
  • 2023-03-17
  • 2021-08-30
  • 1970-01-01
  • 1970-01-01
  • 2011-11-29
  • 1970-01-01
相关资源
最近更新 更多