5

In the Google reference documentation I found a short function to convert RFC3339 date string to a valid Date object. The code is very simple and goes like this :

function parseDate(string) {
  var parts = string.split('T');
  parts[0] = parts[0].replace(/-/g, '/');
  return new Date(parts.join(' '));
}

The problem is that it does not work.(I'm surprised they publish a code that doesn't work... am I missing something ?)

I also had an issue while using JSON to stringify and parse dates because the JSON method returns a UTC value (a Z at the end) and because of that I lose the Time zone information. Google's code does not handle that issue either (even if it worked).

Below is a demo code I used to test it and a solution I wrote to get what I want. Not sure it's very efficient nor well written but at least I get the result I want (I'm executing this code in a script set to GMT+2, Belgium summer time). I'm open to any suggestion to improve this code.(and that would be the subject of this question)

I added a lot of logs and comments in the code to make it as clear as possible :

function testJSONDate() {
  Logger.log('starting value : "2016/3/31 12:00:00"');
  var jsDate = JSON.stringify(new Date("2016/3/31 12:00:00"));// time is 12:00 I'm in GMT+2
  Logger.log('JSON.stringify value : '+jsDate);
  Logger.log('JSON parse jsDate : '+JSON.parse(jsDate)); // time is 10:00, UTC
  var jsDateWithoutQuotes = jsDate.replace(/"/,'');
  var date = parseDate(jsDateWithoutQuotes); 
  Logger.log('parsed RFC3339 date using Google\'s code : '+date);  // does not return a valid date
  var otherFunction = parseDate2(jsDateWithoutQuotes);
  Logger.log('parsed RFC3339 date using other code : '+otherFunction); // does return a valid date in my TZ
}

function parseDate(string) {
  var parts = string.split('T');
  parts[0] = parts[0].replace(/-/g, '/');
  return new Date(parts.join(' '));
}
function parseDate2(string) {
  var refStr = new Date().toString();
  var fus = Number(refStr.substr(refStr.indexOf('GMT')+4,2));
  Logger.log('TZ offset = '+fus);
  var parts = string.split('T');
  parts[0] = parts[0].replace(/-/g, '/');
  var t = parts[1].split(':');
  return new Date(new Date(parts[0]).setHours(+t[0]+fus,+t[1],0));
}

Logger results : enter image description here


EDIT following first answer

After a small change in the code I managed to get Google's snippet to work but the problem of time zone being lost still remains because of the way JSON converts JS date objects.

new code and logger result below:

function testJSONDate() {
  Logger.log('starting value : 2016/3/31 12:00:00');
  var jsDate = JSON.stringify(new Date("2016/3/31 12:00:00"));// time is 12:00 I'm in GMT+2
  Logger.log('JSON.stringify value : '+jsDate);
  Logger.log('JSON parse jsDate : '+JSON.parse(jsDate)); // time is 10:00, UTC
  var jsDateWithoutQuotesAndMillisecAndZ = jsDate.replace(/"/g,'').split('.')[0];
  Logger.log('jsDateWithoutQuotesAndMillisecAndZ = '+jsDateWithoutQuotesAndMillisecAndZ);
  var date = parseDate(jsDateWithoutQuotesAndMillisecAndZ); 
  Logger.log('parsed RFC3339 date using Google\'s code : '+date);  // does not return a valid date
  var otherFunction = parseDate2(jsDateWithoutQuotesAndMillisecAndZ);
  Logger.log('parsed RFC3339 date using other code : '+otherFunction); // does return a valid date in the right tz
}

enter image description here

Serge insas
  • 45,904
  • 7
  • 105
  • 131

1 Answers1

2

You have taken a little helper function out of context. It was only meant as a stopgap device to get the strings returned by a particular API (Google Calendar API) to parse correctly in Apps Script. It is not any kind of universal date converter. A project member threw it together when filing an issue, and a follow-up message in that thread points out another detail that the function doesn't handle.

As of now, the date parser in Apps Script correctly parses the following formats:

function testdate() {
  Logger.log(new Date("2016/03/31 10:00:00"));       // local time
  Logger.log(new Date("2016/03/31 10:00:00 +2:00")); // with given offset
  Logger.log(new Date("2016-03-31T08:00:00.000Z"));  // in UTC 
}

Note that milliseconds are required for UTC timestamp, but are not allowed for the others.

What you do with a datetime string that needs to be parsed but is not one of the above, depends on its format. If you have 2016-03-31T10:00:00 (apparently, this is what Google Calendar API returns) and this is meant to be in local time, then you need exactly what the quoted parse function does: replace T by space and - by /. If the same string represents UTC time, one needs to add .000Z at the end. And so on.

  • thanks for your answer, I didn't know the restrictions about milliseconds not being allowed when TZ is present (and sorry for forgetting the g) but beside that, the simple JSON stringify/parse process on a valid date object is still erasing the tz info. Also, I don't use that for the calendar service but to exchange data between gs script and htmlService client JavaScript. I'll update the question with new code version. – Serge insas Apr 01 '16 at 08:24
  • 2
    This `JSON.stringify` behavior is in no way specific to Apps Script. This is just how [JSON.stringify works](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify) in JavaScript: it stores `date.toISOString()`. The idea is that it's the moment in time that's being captured, not the sender's timezone. If you prefer a different string format, [this post](http://stackoverflow.com/a/31104671) offers a solution using moment.js. You can also produce such as string yourself from `date.toString()` by using string manipulations. –  Apr 01 '16 at 11:37
  • that's what I did in the code above. thx for your feedback, I'll accept your answer. – Serge insas Apr 01 '16 at 11:49