简体   繁体   English

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

[英]How to change timezone without changing date value

My scenario is this: 我的情况是这样的:

I have a datepicker that accepts input from the user and it assumes the date/time picked is local time. 我有一个日期选择器,它接受用户的输入,并且假定选择的日期/时间是本地时间。 I can't seem to change this behavior. 我似乎无法改变这种行为。 The user should actually be picking the date/time in Europe/London time as they are booking a service in London at that time. 用户实际上应该在欧洲/伦敦时间选择日期/时间,因为他们当时正在伦敦预订服务。

Lets say they are booking a flight from London at 5AM. 可以说他们正在预订凌晨5点从伦敦出发的航班。

So I have this date the user picked (from New Zealand): 因此,我有这个日期(来自新西兰):

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

I need to change this to: 我需要将其更改为:

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

After that I am sending to server and storing as UTC. 之后,我将发送到服务器并存储为UTC。

I am using momentjs if that helps. 如果有帮助,我正在使用momentjs。

Edit: Latest attempt: I just need to figure out how to get the timezone offset from the exact time the user entered so I have daylight savings covered. 编辑:最新尝试:我只需要弄清楚如何从用户输入的确切时间中获取时区偏移量,这样就可以解决夏令时问题。 eg below I am getting the UK offset for the day before so may have DST issues 例如下面,我要在前一天获得英国补偿,所以可能会有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

Edit: 编辑:

Current solution: 当前解决方案:

No DST in UK example: 英国没有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

Has DST in UK example (same code): 在英国示例中有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
  • If you are not doing any date time conversion (like in your example), and just changing the time zone offset in the end of the string, just do a string operation, like this: 如果您不进行任何日期时间转换(例如您的示例),而只是更改字符串末尾的时区偏移量,则只需执行字符串操作,如下所示:
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
  • If you need to convert the full date and time, as you are using momentjs, you could use moment-timezone instead: https://momentjs.com/timezone/ . 如果在使用momentjs时需要转换完整的日期和时间,则可以改用moment-timezone: https ://momentjs.com/timezone/。 Then the following code do the trick: 然后,下面的代码可以解决问题:
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
  • If you want to get the time zone offset string, also use moment-timezone: 如果要获取时区偏移量字符串,请也使用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

This seems hacky and not clean code, but it's due to a bug in timezone that parses as UTC date instead of timezone date. 这似乎很hacky,代码也不干净,但这是由于时区中的错误解析为UTC日期而不是时区日期。

Here is a simpler solution: 这是一个更简单的解决方案:

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

To explain that a bit: 解释一下:

  1. We parse the string, which interprets the string as being in NZ, but translates it to a local time, which may or may not be +12, depending on where your computer is 我们解析该字符串,该字符串将其解释为NZ,但会将其转换为本地时间,该时间可能为+12,也可能不是+12,具体取决于您的计算机所在的位置
  2. use parseZone to undo that conversion, so that our date thinks of itself as being in +12, per the original string 使用parseZone撤消该转换,以便我们的日期根据原始字符串将自身视为+12
  3. Convert the time to London time using tz , but with the a second argument (called keepTime ) of true , which means "instead of keeping the time the same and changing the local time, change what time it is to keep the local time the same". 使用tz将时间转换为伦敦时间,但第二个参数(称为keepTime )为true ,这意味着“与其保持相同的时间并更改本地时间, keepTime更改时间以保持本地时间相同。 ”。
  4. Format the result in ISO, but pass a second argument (called keepOffset ) telling it not to convert to UTC before display 以ISO格式格式化结果,但传递第二个参数(称为keepOffset ),告诉它在显示之前不要转换为UTC

So, that works, but perhaps it would be better to change the timepicker to London time so that the times they pick are already in the zone you want? 因此,这行得通,但也许最好将时间选择器更改为伦敦时间,以使他们选择的时间已经在您想要的区域中?

Edit, the equivalent Luxon code is a little more legible, if that helps explain it: 编辑,等效的Luxon代码更清晰一些,如果可以解释的话:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM