处理日期/时间和时区的奇怪时间偏移量

时间:2019-07-31 17:56:39

标签: datetime google-apps-script google-sheets timezone timezone-offset

我一直在尝试对一些函数进行编码,以基于来自Google电子表格中多个单元格的信息来创建Google日历和google日历事件。

here中发布日期部分的第一期问题已经解决。

现在我在“时间”部分遇到了问题。

以下代码:

  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);  

产生以下日志

  

timeStart:1899年12月30日星期六GMT-0300(BRT)

     

timeEnd:1899年12月30日星期六GMT-0300(BRT)

     

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

     

开始时间对象小时:7

     

时间开始对象分钟数:6

     

开始时间HH:mm:07:00

     

TimeZone:美国/圣保罗

     

07

     

00

     

07

     

30

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

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

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

编辑。

我注意到Date()构造函数的单引号之间有ssTZ变量,因此它可能被丢弃,因为它不应被识别为有效的时区。

不知道它使用的是什么,但是实际的电子表格时区和被错误引用的时区之间的时差似乎是28秒,我也不知道它们的来源。

6分钟的偏移量仍然存在,您可以检查以下代码并进行日志打印。

  var timeStart = ss.getRange(6,4).getValue();
  var ssTZ = SpreadsheetApp.getActive().getSpreadsheetTimeZone();

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

  Logger.log("timeStart: " + timeStart );
  Logger.log(" Time Start Object1: " + timeStartObj1);
  Logger.log(" Time Start Object2: " + timeStartObj2);
  Logger.log("justTimeStart: " + justTimeStart)
  

timeStart:1899年12月30日星期六GMT-0300(BRT)

     

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

     

时间起始对象2:1899年12月30日星期六GMT-0300(BRT)

     

justTimeStart:07:00

编辑2

它与时区有关,并且可能由于Date年份被解释为120年前的1899年而有所调整。

在使用以下构造函数时,在指定格式的字符串中不带Z的情况下:

var timeStartObj3= new Date(Utilities.formatDate(timeStart, ssTZ , 'MMMM dd, yyyy HH:mm:ss'));
Logger.log(" Time Start Object3: " + timeStartObj3);

日志结果为:

  

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

编辑3。

越来越奇怪...

如果我在Logger.log调用上使用文本串联,则会得到另一个String,如果我仅使用var名称调用日志,就会得到一个不同的字符串:

  var ss = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("Passeios");
  var timeStart = ss.getRange(6,4).getValue();
  Logger.log("timeStart: " + timeStart);
  Logger.log(timeStart);
  

timeStart:1899年12月30日星期六GMT-0300(BRT)

     

星期六12月30日07:00:00 GMT-03:06 1899

我确实知道实际上同一时间表示的时间有所不同(我假设即使没有显示28秒也在那里)。

我的猜测是,无论是否使用串联,文本解析方法都有不同的行为(至少令人困惑)。

我仍然不知道那06分28秒来自哪里,或者当使用来自日期和时间的单元格值来混合时间时使用时间和日期时如何确保一致性。

这真令人困惑...

2 个答案:

答案 0 :(得分:2)

6分钟28秒来自圣保罗与格林尼治标准时间之间的Local Mean Time(LMT)偏移。 You can see it in the TZDB sources

# Zone  NAME               STDOFF    RULES   FORMAT   [UNTIL]
Zone    America/Sao_Paulo  -3:06:28  -       LMT      1914
                           -3:00     Brazil  -03/-02  1963 Oct 23  0:00
                           -3:00     1:00    -02      1964
                           -3:00     Brazil  -03/-02

LMT条目位于第一行。最后一列(1914)是“直到”日期-意味着在TZDB中,LMT一直使用到1914年。之后,将应用区域条目中的下一条规则(-3:00)。

LMT是根据参考位置的经度和纬度计算的。它与当时该地区可能已经使用的计时无关。在许多情况下,如果使用的是旧日期,则没有历史信息可用来了解这么久之前的确切时间。

换句话说,您的示例日期为1899年,该日期是在巴西已知的计时惯例开始之前的某个时期,因此将采用当地平均时间。

使用更现代的日期,您应该得到的结果对于今天的标准来说更有意义。

答案 1 :(得分:1)

Google工作表将日期或时间单元格值存储为一个数字,该数字与here所述的开始于12/30/1899 0:00:00的整天(或小数)的数量相对应。

在处理仅包含时间值的单元格时,the getValues()函数将生成日期部分设置为12/30/1899的Date对象,但这将具有相应的时区偏移量,该偏移量会及时创建@Matt Johnson在先前的答案中解释的奇数偏移量

最大的问题是,该偏移量对于不同的时区将是不一致的,因为该日期将针对不同的位置/时区和不同的年份产生不同的偏移量,因此您需要解决很多可能的情况。

当尝试创建Date()对象时,这会产生不同的结果,因为有时偏移量作为时区偏移量传递,而有时它是实际时间值的一部分,具体取决于构造函数和文本解析的格式,从此代码中可以看到,造成了很多混乱:

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

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

var date4 = new Date(Utilities.formatDate(timeStart, ssTZ , "yyyy-MM-dd'T'HH:mm:ss'Z'"));


Logger.log("date1: " + date1);
Logger.log("date2: " + date2);
Logger.log("date3: " + date3);
Logger.log("date4: " + date4);

生成此日志:

  

date1:​​1899年12月30日星期六GMT-0300(BRT)

     

date2:1899年12月30日星期六GMT-0300(BRT)

     

date3:1899年12月30日星期六GMT-0300(BRT)

     

date4:1899年12月30日星期六格林尼治标准时间0300(BRT)

有时,时区偏移量将被完全忽略,有时,仅秒部分将被忽略,并且它可能被解释为以小时为单位的完全不同的时区。 (该字符串格式来自formatDate() class documentation example

正如@TheMaster所建议的那样,可以在电子表格中解决该问题,在工作表上创建辅助单元格/列以添加更一致的日期部分,但是在动态处理此信息的情况下(在我的情况下为组合方式多个相关表单的多个答案中的多个QUERY结果的结果。

@TheMaster还建议另一种方法是使用getDisplayValues()并解析文本,但是如果在工作表中更改了显示格式,这可能会带来各种麻烦。

似乎没有明确的答案

我认为,解决此问题的最简单方法是在代码中使用数字变量,并使用Utilities.formatDate()并将format属性设置为{{ 1}}和'HH'

'mm'

给出以下结果:

  

营业时间:07

     

分钟:00

这似乎是一致的,并且它忽略了与时区相关的偏移量,并将产生一个简单的小时数和一个简单的分钟数,与工作表上显示的值相对应,然后可以一致地使用它们创建Date( )对象。

请注意,电子表格上的单元格仍需要设置为日期/时间格式才能正常工作,但与解析var hours = Utilities.formatDate(timeStart, ssTZ, 'HH'); var minutes = Utilities.formatDate(timeStart, ssTZ, 'mm'); Logger.log("Hours: "+ hours); Logger.log("Minutes: "+ minutes); 结果中的文本不同,任何日期/时间格式仍将保持相同。

我对秒或毫秒不感兴趣,但我怀疑可以用相同的方式解决这些问题。

希望这会帮助其他人。