【问题标题】:How to read the correct time/duration values from Google Spreadsheet如何从 Google 电子表格中读取正确的时间/持续时间值
【发布时间】:2013-07-16 22:53:17
【问题描述】:

我正在尝试从时间格式的单元格 (hh:mm:ss) 中获取小时值,该值可以更大 24:00:00 例如 20000:00:00 应该给出 20000:

表:

如果你读到 E1 的值:

var total = sheet.getRange("E1").getValue();
Logger.log(total);

结果是:

4 月 12 日星期六 07:09:21 GMT+00:09 1902

现在我尝试将其转换为 Date 对象并获取它的 Unix 时间戳:

  var date = new Date(total);
  var milsec = date.getTime();
  Logger.log(Utilities.formatString("%11.6f",milsec));
  var hours = milsec / 1000 / 60 / 60; 
  Logger.log(hours)

1374127872020.000000

381702.1866722222

问题是如何获得 20000 的正确值?

【问题讨论】:

  • 快速说明:您实际上不是在读取时间值,而是持续时间值。时间值最多只能到 23:59:59 或 11:59 PM。我建议更改问题的标题,因为它目前具有误导性(我自己正在寻找它,而是来到这里)。

标签: javascript time google-apps-script google-sheets


【解决方案1】:

扩展 Serge 所做的工作,我编写了一些函数,这些函数应该更易于阅读,并考虑到电子表格和脚本之间的时区差异。

function getValueAsSeconds(range) {
  var value = range.getValue();

  // Get the date value in the spreadsheet's timezone.
  var spreadsheetTimezone = range.getSheet().getParent().getSpreadsheetTimeZone();
  var dateString = Utilities.formatDate(value, spreadsheetTimezone, 
      'EEE, d MMM yyyy HH:mm:ss');
  var date = new Date(dateString);

  // Initialize the date of the epoch.
  var epoch = new Date('Dec 30, 1899 00:00:00');

  // Calculate the number of milliseconds between the epoch and the value.
  var diff = date.getTime() - epoch.getTime();

  // Convert the milliseconds to seconds and return.
  return Math.round(diff / 1000);
}

function getValueAsMinutes(range) {
  return getValueAsSeconds(range) / 60;
}

function getValueAsHours(range) {
  return getValueAsMinutes(range) / 60;
}

你可以像这样使用这些函数:

var range = SpreadsheetApp.getActiveSheet().getRange('A1');
Logger.log(getValueAsHours(range));

不用说,要从一个范围内获取小时数需要做很多工作。请为Issue 402 加注星标,这是一项功能请求,可以从单元格中获取文字字符串值。

【讨论】:

  • 感谢这个不错的小功能,比我的代码方便得多;-) 顺便说一句,我在尝试解释时确实混淆了 JS 和 SS 参考,我现在更正了我的解释,希望它可以理解任何人...
  • 一个细节:我刚刚注意到,对于像 03:30 这样的“特殊”时区,它不会返回整数......在最终返回的值上添加 Math.round()(分钟和小时)在这种特殊情况下可能很有用。毕竟它不会打扰其他情况;-)
  • 感谢 Serge,我已经调整了逻辑,使其能够正确处理不是整小时的时区偏移。
  • 谢谢 Eric,帮助完整的脚本
【解决方案2】:

有两个新函数getDisplayValue()getDisplayValues() 可以返回日期时间或任何与电子表格上看起来完全一样的东西。查看文档here

【讨论】:

  • 将此用于 Google Docs 文本文档,我得到“未定义”
  • 问答是关于床单的。
  • 谢谢,是的,我需要专门从工作表中获取时间和日期到文档中。显示值,而不是被时区或其他东西弄乱。我现在通过将所有相关文件和脚本中的时区设置为“GMT(无夏令时)”来解决这个问题。
【解决方案3】:

您看到的值(Sat Apr 12 07:09:21 GMT+00:09 1902)是 Javascript 标准时间中的等效日期,比参考日期晚 20000 小时。

您应该简单地从结果中删除电子表格参考值以获得您想要的结果。

这段代码可以解决问题:

function getHours(){
  var sh = SpreadsheetApp.getActiveSpreadsheet();
  var cellValue = sh.getRange('E1').getValue();
  var eqDate = new Date(cellValue);// this is the date object corresponding to your cell value in JS standard 
  Logger.log('Cell Date in JS format '+eqDate)
  Logger.log('ref date in JS '+new Date(0,0,0,0,0,0));
  var testOnZero = eqDate.getTime();Logger.log('Use this with a cell value = 0 to check the value to use in the next line of code '+testOnZero);
  var hours = (eqDate.getTime()+ 2.2091616E12 )/3600000 ; // getTime retrieves the value in milliseconds, 2.2091616E12 is the difference between javascript ref and spreadsheet ref. 
  Logger.log('Value in hours with offset correction : '+hours); // show result in hours (obtained by dividing by 3600000)
}

注意:这段代码只有几小时,如果你有几分钟和/或几秒钟,那么它也应该被开发来处理它......如果你需要它,请告诉我们。


编辑:解释一下……

电子表格使用 1899 年 12 月 30 日作为参考日期,而 Javascript 使用 1970 年 1 月 1 日,这意味着两个参考日期之间存在 25568 天的差异。所有这一切都假设我们在两个系统中使用相同的时区。当我们将电子表格中的日期值转换为 javascript 日期对象时,GAS 引擎会自动添加差异以保持日期之间的一致性。

在这种情况下,我们不想知道某事的真实日期,而是想知道绝对小时值,即“持续时间”,因此我们需要删除 25568 天的偏移量。这是使用 getTime() 方法完成的,该方法返回从 JS 引用日期开始计算的毫秒数,我们唯一需要知道的是电子表格引用日期的毫秒值,并从实际日期对象中减去该值。然后进行一些数学运算,得到小时而不是毫秒,我们就完成了。

我知道这似乎有点复杂,我不确定我的解释是否能真正澄清问题,但总是值得尝试不是吗?

无论如何,只要(如 cmets 中所述)根据电子表格的时区设置调整偏移值,结果就是我们需要的。当然可以让脚本自动处理,但它会使脚本更复杂,不确定是否真的有必要。

【讨论】:

  • 形成这个值来自哪里:2.2091616E12?
  • 一个小问题,我得到 19999.0 是否值 2.2091616E12 取决于电子表格的时区?
  • 我添加了一行,您可以使用小时值 = 0 来获得适合您的 TZ 的常量值,这确实取决于您的电子表格时区
  • Eric 的回答要“优雅”得多,我建议您将他的回答标记为最佳回答。
【解决方案4】:

对于简单的电子表格,您可以在没有夏令时的情况下将电子表格时区更改为 GMT 并使用这个简短的转换功能:

function durationToSeconds(value) {
  var timezoneName = SpreadsheetApp.getActive().getSpreadsheetTimeZone();
  if (timezoneName != "Etc/GMT") {
    throw new Error("Timezone must be GMT to handle time durations, found " + timezoneName);
  }
  return (Number(value) + 2209161600000) / 1000;
}

Eric Koleda 的回答在许多方面更为笼统。我写这篇文章是为了了解它如何处理电子表格时区、浏览器时区以及 1900 年阿拉斯加和斯德哥尔摩的时区变化的极端情况。

【讨论】:

  • “没有夏令时的 GMT” - 天才。非常感谢你,伙计。
【解决方案5】:

在某处创建一个持续时间值为“00:00:00”的单元格。该单元格将用作参考。可能是隐藏单元格,也可能是具有配置值的不同工作表中的单元格。例如。如下:

然后编写一个带有两个参数的函数 - 1)您要处理的值,以及 2)“00:00:00”的参考值。例如:

function gethours(val, ref) {

  let dv = new Date(val)
  let dr = new Date(ref)

  return (dv.getTime() - dr.getTime())/(1000*60*60)

}

由于 Sheets 对 Duration 类型所做的任何事情对两者都是完全相同的,我们现在可以将它们转换为 Dates 并减去,这会给出正确的值。在上面的代码示例中,我使用了 .getTime(),它给出了自 1970 年 1 月 1 日以来的毫秒数,...。

如果我们试图计算该值究竟发生了什么并进行更正,代码就会变得过于复杂。

一个警告:如果小时数非常大,比如 200,000:00:00,则会出现大量小数值,因为天/年不完全是 24 小时/365 天(?在这里推测)。具体来说,200000:00:00 结果为 200,000.16。

【讨论】:

    猜你喜欢
    • 2016-07-17
    • 2013-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-11
    • 1970-01-01
    相关资源
    最近更新 更多