therealdavidhenderson
therealdavidhenderson

Reputation: 63

Javascript converting Date to UTC (And leave unmodified if is already UTC)

First thing off, I know how to convert the a local date to UTC in Javascript. This isn't a duplicate of that.

I've been trying to get a function that will convert a date to UTC if it isn't already, I don't have control whether or not the input is UTC or not. I can't use Javascript plugins.

Normal solutions would be just to parse a local date into UTC, but parsing a date that's already UTC that way outputs the weird behavior of modifying the already UTC date incorrectly.

I have an example function below.

function temp() {
  var utc = new Date(Date.UTC(2017, 1, 10, 10, 10, 0));
  var local = new Date(2017, 1, 10, 10, 10, 0);

  var utc2 = new Date(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate(),  utc.getUTCHours(), utc.getUTCMinutes(), utc.getUTCSeconds());
  var local2 = new Date(local.getUTCFullYear(), local.getUTCMonth(), local.getUTCDate(),  local.getUTCHours(), local.getUTCMinutes(), local.getUTCSeconds());

  var utc3 = new Date(utc.getTime() + utc.getTimezoneOffset()*60*1000);
  var local3 = new Date(local.getTime() + local.getTimezoneOffset()*60*1000);

  Logger.log("Timezone offset: UTC=" + utc.getTimezoneOffset() + " Local=" + local.getTimezoneOffset());
  Logger.log("UTC: " + utc.getTime() + " -> UTC2(" + utc2.getTime() + ") or UTC3(" + utc3.getTime() +")");
  Logger.log("Local: " + local.getTime() + " -> UTC2(" + local2.getTime() + ") or UTC3(" + local3.getTime() +")");
}

returns

Timezone offset: UTC=420 Local=420
UTC: 1486721400000 -> UTC2(1486746600000) or UTC3(1486746600000)
Local: 1486746600000 -> UTC2(1486771800000) or UTC3(1486771800000)

Note that even the UTC date has a timezone offset. And that both methods of converting a local date to UTC strangly modifies the already UTC date to something incorrect.

Thank you for your help.

Upvotes: 0

Views: 684

Answers (1)

Philipp
Philipp

Reputation: 1298

There is nothing weird about the behavior and unfortunately there is no answer to your question (using the default JavaScript Date implementation).

In JavaScript, each Date is represented by the milliseconds since the epoch. A Date instance is always handled within the interpreters (e.g., your browser's) timezone. Thus, when you call new Date(Date.UTC(2017, 1, 10, 10, 10, 0));, you actually create a Date instance, which is internally represented by 1486721400000.

The getTimezoneOffset() method always returns values from the perspective of your current timezone. So in my case (California), the following:

document.write(new Date(Date.UTC(2017, 1, 8, 10, 0, 0)).toString());
document.write("<br/>");
document.write(new Date(Date.UTC(2016, 8, 8, 10, 0, 0)).toString());

outputs (with comments)

480 // Wed Feb 08 2017 02:00:00 GMT-0800 (PST)
420 // Thu Sep 08 2016 03:00:00 GMT-0700 (PDT)

Trying to find an answer for your question

The only solution I can think of, is that you create your own Date implementation (as you don't want to use any "plug-ins"). You could create your own Date, which can also store the time-zone, or just has a flag which defines if the Date is in UTC. If you reconsider the usage of a JavaScript library, you may want to look at, e.g., https://momentjs.com/timezone/.

Here is a sample on how you could get started with your own implementation

function TzDate (date, utc) {
  if (date instanceof Date) {
    this.date = date;
    this.utc = utc ? true : false;
  } else if (typeof date === 'number') {
    this.date = new Date(date);
    this.utc = true;
  } else if (typeof date === 'boolean') {
    this.date = new Date();
    this.utc = date;
  } else {
    this.date = new Date();
    this.utc = utc ? true : false;
  }
}
 
TzDate.prototype = {
  toString: function() {
    return this.isUTC() ? this.date.toUTCString() : this.date.toString()
  },
  
  getTimezoneOffset: function() {
    return this.isUTC() ? 0 : this.date.getTimezoneOffset();
  },

  isUTC: function() {
    return this.utc;
  }
};

console.log(new TzDate().toString());
console.log(new TzDate(true).toString());
console.log(new TzDate(Date.UTC(2017, 1, 8, 10, 0, 0)).toString());
console.log(new TzDate(new Date(2017, 1, 8, 10, 0, 0)).toString());

see also:

Upvotes: 1

Related Questions