处理日期/时间和时区的问题

Posted

技术标签:

【中文标题】处理日期/时间和时区的问题【英文标题】:Problem dealing with date/time and timezone 【发布时间】:2019-07-02 23:42:34 【问题描述】:

我正在根据链接到 Google 表单的 Google 表格中的信息在 Google 日历上创建活动系列。处理日期是一团糟,我得到了不稳定的结果。

我在电子表格中有一个字段,其开始日期显示为YYYY/MM/DD 我有一个开始时间显示为 HH:mm 的字段 我有一个结束时间显示为 HH:mm 的字段

我了解,在内部,时间关联了年/月/日,而 DATE 也关联了未显示的时间。

我最终需要使用 DATE 中的 DATE 部分和可以使用 setHours() setMinutes() 方法更改的时间部分创建日历事件系列。

现在我的问题是从 DATE 单元格值创建一个一致的 Date 对象,因为它似乎发生了奇怪的变化。

var ssTZ = SpreadsheetApp.getActive().getSpreadsheetTimeZone();
var SSDate = ss.getRange(6,8).getValue();
var dataStart = Utilities.formatDate(SSDate, 'America/Brasilia' , 'MMMM dd, yyyy 12:00:00 Z');
var dataStartTZ = Utilities.formatDate(SSDate, ssTZ , 'MMMM dd, yyyy 12:00:00 Z');
var dataStartSP = Utilities.formatDate(SSDate, 'America/Sao_Paulo' , 'MMMM dd, yyyy 12:00:00 Z');
var dataStartOS = Utilities.formatDate(SSDate, 'GMT-3' , 'MMMM dd, yyyy 12:00:00 Z');

var date = new Date(dataStart);
var dateTZ = new Date(dataStartTZ);
var dateSP = new Date(dataStartSP);
var dateOS = new Date(dataStartOS);  

Logger.log("Spreadsheet TimeZone: " + ssTZ);
Logger.log(SSDate);
Logger.log("");
Logger.log(date);  
Logger.log(dateTZ);
Logger.log(dateSP);
Logger.log(dateOS);

该代码产生以下日志输出:

[19-07-02 20:39:49:780 BRT] 电子表格时区:美国/圣保罗 [19-07-02 20:39:49:781 BRT] 2016 年 1 月 12 日星期二 00:00:00 GMT-02:00 [19-07-02 20:39:49:782 BRT] [19-07-02 20:39:49:784 BRT] 2016 年 1 月 12 日星期二 10:00:00 GMT-02:00 [19-07-02 20:39:49:784 BRT] 2016 年 1 月 12 日星期二 12:00:00 GMT-02:00 [19-07-02 20:39:49:785 BRT] 2016 年 1 月 12 日星期二 12:00:00 GMT-02:00 [19-07-02 20:39:49:786 BRT] 2016 年 1 月 11 日星期一 13:00:00 GMT-02:00

这没有意义,因为使用的所有时区实际上应该是相同的。

编辑....添加信息

根据@TheMaster 的要求,来自文本格式变量的日志是:

  Logger.log(dataStart);  
  Logger.log(dataStartTZ);
  Logger.log(dataStartSP);
  Logger.log(dataStartOS);

[19-07-03 12:39:33:099 BRT] 2016 年 1 月 12 日 12:00:00 +0000

[19-07-03 12:39:33:100 BRT] 2016 年 1 月 12 日 12:00:00 -0200

[19-07-03 12:39:33:100 BRT] 2016 年 1 月 12 日 12:00:00 -0200

[19-07-03 12:39:33:100 BRT] 2016 年 1 月 11 日 12:00:00 -0300

@ziganotscha 解释的前 3 个输出是由于夏令时更改为 GMT-2 和美国/巴西利亚未被识别为有效时区。

我仍然不明白为什么当 GMT-3 指定为时区时它会更改为 1 月 11 日。

此外,如果我直接从单元格值构建 Date 对象而不进行格式化,我会得到另一个不同的时间:

var rawDate = new Date(SSDate);

19-07-03 12:39:33:101 BRT] rawDate:2016 年 1 月 12 日星期二 00:00:00 GMT-0200 (BRST)

我讨厌处理日期...太混乱了...

EDIT 2 ...更多时间问题。

  var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Passeios");
  var timeStart = ss.getRange(6,4).getValue();
  var timeEnd = ss.getRange(6,5).getValue();
  var ssTZ = SpreadsheetApp.getActive().getSpreadsheetTimeZone();

  Logger.log("timeStart: " + timeStart );
  Logger.log("timeEnd: " + timeEnd);


  var dateStart = ss.getRange(6,8).getValue();

  var dateStartObj = new Date(Utilities.formatDate(dateStart, 'ssTZ' , 'MMMM dd, yyyy HH:mm:ss Z'));

var timeStartObj= new Date(Utilities.formatDate(timeStart, 'ssTZ' , 'MMMM dd, yyyy HH:mm:ss Z'));

var justTimeStart = Utilities.formatDate(timeStart, ssTZ, 'HH:mm');


Logger.log(" Time Start Object: " + timeStartObj);
Logger.log("Time Start Object Hours: " + timeStartObj.getHours());
Logger.log("Time Start Object Minutes: " + timeStartObj.getMinutes());

Logger.log("Start Time HH:mm: " + justTimeStart)

var hourStart = Utilities.formatDate(timeStart, ssTZ, 'HH');
var minutesStart = Utilities.formatDate(timeStart, ssTZ, 'mm');
var hourEnd = Utilities.formatDate(timeEnd, ssTZ, 'HH');
var minutesEnd = Utilities.formatDate(timeEnd, ssTZ, 'mm');


Logger.log(" TimeZone :" + ssTZ);
Logger.log(hourStart);
Logger.log(minutesStart);
Logger.log(hourEnd);
Logger.log(minutesEnd);  

产生以下日志

时间开始:1899 年 12 月 30 日星期六 07:06:28 GMT-0300 (BRT)

时间结束:1899 年 12 月 30 日星期六 07:36:28 GMT-0300 (BRT)

时间开始对象:1899 年 12 月 30 日星期六 07:06:28 GMT-0300 (BRT)

时间开始对象小时:7

时间开始对象分钟:6

开始时间 HH:mm: 07:00

时区:美国/圣保罗

07

00

07

30

电子表格单元格的格式为 HH:mm 并显示 07:00 开始时间 07:30 结束时间

如您所见,在记录单元格值或使用单元格值构造 Date() 对象时,我不确定从哪里来的 6 分 28 秒的偏移量。

将单元格格式化为仅小时或分钟或 HH:mm 不会带有该偏移量。

【问题讨论】:

改为记录SSDate, dataStart,dataStartTZ, dataStartSP,dataStartOS 这是那些日志:Logger.log(dataStart);记录器.log(dataStartTZ); Logger.log(dataStartSP); Logger.log(dataStartOS); 19-07-03 12:27:40:438 BRT] 2016 年 1 月 12 日 12:00:00 +0000 [19-07-03 12:27:40:439 BRT] 2016 年 1 月 12 日 12:00:00 - 0200 [19-07-03 12:27:40:440 BRT] 2016 年 1 月 12 日 12:00:00 -0200 [19-07-03 12:27:40:440 BRT] 2016 年 1 月 11 日 12:00: 00 -0300 您的脚本时区是什么?文件>项目设置? 我的脚本时区是 (GMT-03:00) Sao Paulo 但我想我在一月份使用的日期设置为 GMT-02:00,因为那时夏令时已经到位并且确实那时圣保罗时间是格林威治标准时间 -02:00 【参考方案1】:

关于时区有一个混淆:

您的时区是 'America/Sao_Paulo' 时区 - 这就是为什么 Logger.log(dateTZ);Logger.log(dateSP); 给您相同的时间 - 正如您所期望的那样。

但是,请记住,1 月份圣保罗遵守巴西利亚夏令时(UTC−02 而不是UTC−03),这就是Logger.log(dateSP);Logger.log(dateOS); 之间的区别。

https://www.timeanddate.com/time/zones/brt

至于 dataStart - 您为其分配时区 'America/Brasilia',这不是时区的定义名称。这就是为什么 Apps 脚本不接受该值并为您提供 UTC+0 时区的原因。

您可以验证 formatDate() 使用 Java SimpleDateFormat 指定的时区: https://developers.google.com/apps-script/reference/utilities/utilities http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html

而 java 使用 Olson 时区数据库。

https://www.oracle.com/technetwork/java/javase/dst-faq-138158.html#worldwide https://en.wikipedia.org/wiki/Time_in_Brazil

【讨论】:

我虽然前 2 个涉及夏令时,但我仍然不明白为什么 GMT-3 将日期从 Jan12 更改为 Jan 11 @ 13:00 我也无法调用 getTimeZone() 或 setTimeZone () 谷歌脚本上的方法,不知道为什么......我得到“TypeError:在对象中找不到函数 getTimeZone” 而且...如果我从原始单元格值构建 Date() 而不进行格式化,我会得到不同的时间... var rawDate = new Date(SSDate); Logger.log("rawDate:" + rawDate);日志输出:rawDate:2016 年 1 月 12 日星期二 00:00:00 GMT-0200 (BRST)【参考方案2】:

所以,电子表格时间SSDate

2016 年 1 月 12 日星期二 00:00:00 GMT-02:00

即 1 月 12 日从 GMT 时区的午夜开始 -2 小时。

'America/Brasilia' 不是有效时区,可以忽略。

America/Sao_PaulossTZ 作为Utilities.formatDate() 的第二个参数都产生相同的有效日期

2016 年 1 月 12 日 00:00:00 -0200

当偏移量为GMT-3时,距离格林威治标准时间午夜-3小时,或距离格林威治标准时间2时区-1小时,日期为

2016年1月11日23:00:00-0300

即前一天晚上 11 点。

问题:

您的日志会忽略日期的时间部分,因为您为所有日期 12:00:00 Z 而不是 HH:mm:ss 提供了静态时间格式。

因此,例如,格式化为GMT-3 的最后日期变为

2016 年 1 月 11 日 12:00:00 -0300

调用 new Date() 将上述对象更改为当地时间 GMT-2(+1 from GMT-3):

2016 年 1 月 11 日星期一 13:00:00 GMT-02:00

请注意,强烈建议不要使用 new Date(timestring) 进行解析。

参考资料:

Timezone format javascript#date

【讨论】:

这更有意义......我没有意识到 12:00:00 而不是 HH:mm:ss 会产生这种行为。我确实在尝试使用 Date() 使用单个组件值的构造函数,但是因为我使用来自不同单元格值的日期和时间,所以我需要了解我得到的不稳定 Date() 行为。这很有帮助,谢谢。 这次我刚刚更新了帖子,在时间部分添加了一些其他奇怪的行为。 @Pablo 请提出一个新问题 刚刚发布了新问题here

以上是关于处理日期/时间和时区的问题的主要内容,如果未能解决你的问题,请参考以下文章

处理数据集市/仓库中的时区

如何优雅地处理时区

在带有/不带时区的日期或时间戳的查询中处理 generate_series()

Java盲点攻克「时间与时区系列」让我们一起完全吃透对于时区和日期相关的功能开发原理

在 OLAP 计算期间使用哪些技术来处理不同的时区?

带有时区和夏令时的纪元的日期和时间(以秒为单位)