0

I am using new Date(<date-string>) and then .getTime() to pass date strings to milliseconds from 1970.

The problem is that the date strings does not contain the timezone on them. They are British, so the timezone will be GMT or GMT+1 depending on the date...

When I use this technique in the front-end (Chrome), or in the back-end (Node.js). The time zone taken is the British one (GMT or GMT+1 depending on the date). I assume that is taken from the OS.

However, when using a Node.js server which I have been told is configured to be in UTC... the timezone is always going to be GMT, leading to errors during the British Summer Time.

Is there any way to tell Date to take the timezone from the OS without changing the server configuration?

Example:

var aDate = new Date('2016-06-23 10:15:0');
var timestamp = aDate.getTime();

Just in case my explanation is not clear:

// Executed on 28-06-2016

// In the browser (in London)
new Date().getTimezoneOffset();                            // -60
new Date('28-06-2016 11:11:11').getTimezoneOffset();       // -60
new Date('28-01-2016 11:11:11').getTimezoneOffset();       // 0

// In the Node.js server I am forced to use, which is configured to use UTC
new Date().getTimezoneOffset();                            // 0
new Date('28-06-2016 11:11:11').getTimezoneOffset();       // 0
new Date('28-01-2016 11:11:11').getTimezoneOffset();       // 0

// Ideally, I would like to have the output I get in the browser when I run the code in the UTC Node.js server
David Torres
  • 1,767
  • 1
  • 16
  • 19

2 Answers2

2

I recommend using Moment Timezone for this, since this would be needlessly complicated to implement without a library. To get UTC in milliseconds from a given date in a given timezone, you can do this:

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

function londonTimeToUTC(dateString) {
  return moment.tz(dateString, 'DD-MM-YYYY HH:mm:ss', 'Europe/London').valueOf();
}

console.log(londonTimeToUTC('28-06-2016 11:11:11')); // 1467108671000
console.log(londonTimeToUTC('28-01-2016 11:11:11')); // 1453979471000

The second argument passed to moment.tz() is a format string, which is necessary if the date string is not in ISO format. The third argument is any valid timezone identifier.

McMath
  • 6,862
  • 2
  • 28
  • 33
  • That does not work for me. As I said I am using a server configured to use UTC. So, for me, `new Date().getTimezoneOffset();` will always return `0`, no matter my timezone. My question is: what can I do so my timezone is considered by the `Date()` constructor? – David Torres Jun 28 '16 at 15:26
  • @DavidTorres Sorry, I think I'm still unclear about the question. Do you mean you want to adjust a date string for British daylight savings time, and then pass it to the Date constructor? – McMath Jun 28 '16 at 15:30
  • What I want is to give the date string to the constructor, and the constructor to take care of consider it BST or GMT depending on the date. Which is what happens if you run that code in most of environments (but not in the server where I am running the code because it is configured to work on UTC) (Also, I was told that it is a good practice that the server is in UTC, but for me is being a pain). – David Torres Jun 28 '16 at 15:57
  • I added some examples which I hope will clarify the problem. – David Torres Jun 28 '16 at 16:05
  • @DavidTorres Thanks, I understand. I'm a bit slow today. I'll update my answer. – McMath Jun 28 '16 at 16:09
  • @McMath - The function you wrote is better implemented as `moment.tz(dateString, 'Europe/London').utcOffset()`. You don't need to use the `Date` object at all. – Matt Johnson-Pint Jun 28 '16 at 18:47
  • @MattJohnson Thanks. I thought there must have been better way to do it. It's been a while since I've used this library. – McMath Jun 28 '16 at 19:14
  • `moment.tz(dateString, 'Europe/London')` is giving the next warning: Deprecation warning: moment construction falls back to js Date. This is discouraged and will be removed in upcoming major release. Please refer to https://github.com/moment/moment/issues/1407 for more info. – David Torres Jun 29 '16 at 11:09
  • 1
    @DavidTorres You must be using a non-ISO-formatted date string. While the `Date` constructor can handle these, this is apparently deprecated in moment. Instead, pass a `Date` object to `moment.tz()`. I've edited the answer to reflect this. – McMath Jun 29 '16 at 11:20
  • @McMath Thank you, but now this 2 lines `moment.tz(new Date('2016-6-23 10:15:0'), 'Europe/London').valueOf();` and `moment.tz(new Date('2016-6-23 10:15:0'), 'Europe/Madrid').valueOf();` are returning the same number. – David Torres Jun 29 '16 at 11:39
  • 1
    `.valueOf()` returns the time in UTC, and the `dateString` parameter is expected to be standardized to UTC, so this is expected. `.utcOffset()` will give you the offset from UTC, which will give you different results for London and Madrid. Is it not the UTC offset you wanted? I feel like I'm still missing something. – McMath Jun 29 '16 at 11:54
  • @McMath what I want is the milliseconds (UTC timestamp) of the date string interpreted as a British. I think a way of getting it would be this: `var aDate = moment.tz(new Date('2016-6-23 10:15:00'), 'Europe/London'); var milliseconds = aDate.valueOf() - aDate.utcOffset() * 60000;` – David Torres Jun 29 '16 at 14:22
  • @McMath I am accepting your answer because is the one that helped me the most. Perhaps you want to include my latest comment on it. – David Torres Jun 29 '16 at 14:46
  • @DavidTorres Alright, I think I've finally got it. See the latest edit. – McMath Jun 29 '16 at 16:20
  • @DavidTorres Also, if you were feeling really generous, you might consider accepting the answer rather than just upvoting it :-p – McMath Jun 29 '16 at 16:28
2

Is there any way to tell Date to take the timezone from the OS without changing the server configuration?

The time zone from the OS is what the Date object uses. If you're asking if you can change that time zone without changing the configuration, then no - there is not a way to do that. The Date object always takes on the behavior of the local time zone. Even if you supply an offset in the input string, it just uses that to determine the internal UTC timestamp. Output via most of the properties (including toString and getTimezoneOffset) will always use the local time zone.

Even in your examples, you cannot count on the browser behavior always returning the values you showed, simply because each user visiting your web site may have a different time zone setting.

The recommended way to deal with this is by using the moment.js library, which can handle UTC and local time by itself, but may require use of the moment-timezone extension if you are wanting to work with a specific time zone, such as Europe/London.

Now, with that said, if you're certain that your entire node.js application will run in a single time zone, and you're running on Linux or OSX (not Windows), then you can indeed change which time zone that node.js considers to be "local". Simply set the TZ environment variable before you launch node, like this:

env TZ='Europe/London' node server.js

There is no equivalent for the browser, or for Windows. And you still have to contend with possible non-UK users on your web site - so this doesn't guaranteed a match between client and server time. But it does address your question.

See also:

Community
  • 1
  • 1
Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
  • What I need is to get the correct timestamp when running `new Date('')`. No matter where the Node.js server is, as the server will keep the UTC. I only see options to transform the date to different timezones after the date has been created, but the date is created wrong in the first place because `new Date()` doesn't know the date is receiving is British. – David Torres Jun 29 '16 at 10:54