最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to change timezone without changing date value - Stack Overflow

programmeradmin3浏览0评论

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.

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.

I am using momentjs if that helps.

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. e.g. below I am getting the UK offset for the day before so may have DST issues

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:

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

 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

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.

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.

I am using momentjs if that helps.

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. e.g. below I am getting the UK offset for the day before so may have DST issues

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:

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

 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
Share Improve this question edited Jul 28, 2019 at 20:25 MadMac asked Jul 27, 2019 at 23:35 MadMacMadMac 5,0338 gold badges44 silver badges86 bronze badges 1
  • Once you have a JavaScript Date object like date = new Date(), since London is the location of UTC, you can get conveniently London-specific values (not accounting for daylight savings time) with eitherdate.getTime (for the timestamp) or any of the date.getUTC{{X}} methods (e.g. date.getUTCHours). See: developer.mozilla/en-US/docs/Web/JavaScript/Reference/… (If you need the DST-adjusted London time, that's technically not UTC anymore and you'd need to check whether DST is currently active in London.) – Cat Commented Jul 28, 2019 at 0:01
Add a ment  | 

3 Answers 3

Reset to default 4

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 puter is
  2. use parseZone to undo that conversion, so that our date thinks of itself as being in +12, per the original string
  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".
  4. Format the result in ISO, but pass a second argument (called keepOffset) telling it not to convert to UTC before display

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:

DateTime.fromISO("2019-08-01T05:00:00+12:00", { setZone: true })
  .setZone("Europe/London", { keepLocalTime: true} )
  .toISO()
  • 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./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:
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.

How about creating new Date with timezone set explicite as UTC, but with values passed directly from the original Date, like this:

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

Above is in typescript, but types can be ommited of course.

发布评论

评论列表(0)

  1. 暂无评论