Google Apps 脚本和 RFC 3339 问题

Ser*_*sas 5 google-apps-script

Google 参考文档中,我找到了一个简短的函数,可以将 RFC3339 日期字符串转换为有效的 Date 对象。代码非常简单,如下所示:

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

问题是它不起作用。(我很惊讶他们发布了一个不起作用的代码......我错过了什么吗?)

我在使用 JSON 字符串化和解析日期时也遇到了问题,因为 JSON 方法返回 UTC 值(末尾有 Z),因此我丢失了时区信息。谷歌的代码也不能处理这个问题(即使它有效)。

下面是我用来测试它的演示代码以及我为获得我想要的东西而编写的解决方案。不确定它是否非常高效或写得很好,但至少我得到了我想要的结果(我在设置为 GMT+2(比利时夏季时间)的脚本中执行此代码)。我愿意接受任何改进此代码的建议。(这将是这个问题的主题)

我在代码中添加了很多日志和注释,以使其尽可能清晰:

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));
}
Run Code Online (Sandbox Code Playgroud)

记录器结果: 在此输入图像描述


编辑以下第一个答案

在对代码进行了一些小改动后,我设法让 Google 的代码片段正常工作,但由于 JSON 转换 JS 日期对象的方式,时区丢失的问题仍然存在。

新代码和记录器结果如下:

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
}
Run Code Online (Sandbox Code Playgroud)

在此输入图像描述

小智 2

您断章取义地使用了一些辅助函数。它只是作为一种权宜之计,用于获取特定 API(Google Calendar API)返回的字符串,以便在 Apps 脚本中正确解析。它不是任何类型的通用日期转换器。项目成员在提交问题时将其放在一起,并且该线程中的后续消息指出了该函数无法处理的另一个细节。

截至目前,Apps 脚本中的日期解析器可以正确解析以下格式:

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 
}
Run Code Online (Sandbox Code Playgroud)

请注意,UTC 时间戳需要毫秒,但其他时间戳则不允许。

您如何处理需要解析但不属于上述情况之一的日期时间字符串,取决于其格式。如果您有2016-03-31T10:00:00(显然,这就是 Google Calendar API 返回的内容)并且这意味着是本地时间,那么您需要的正是引用的解析函数的功能:将 T 替换为空格,将 - 替换为 /。.000Z如果同一个字符串表示UTC时间,则需要在末尾添加。等等。

  • 此“JSON.stringify”行为绝不是 Apps 脚本所特有的。这就是 JavaScript 中 JSON.stringify 的工作原理:它存储 `date.toISOString() `。这个想法是捕获的是时间上的时刻,而不是发送者的时区。如果您更喜欢不同的字符串格式,[这篇文章](http://stackoverflow.com/a/31104671) 提供了一个使用 moment.js 的解决方案。您还可以使用字符串操作从“date.toString()”自行生成字符串。 (2认同)