【问题标题】:Google Sheet script to automatically calculate a countdown谷歌表格脚本自动计算倒计时
【发布时间】:2016-05-09 21:15:55
【问题描述】:

我已经几十年没有编码了,我正在寻找一种方法来自动化我当前的“倒计时”电子表格。我目前以一种丑陋、容易出错和迂回的方式做事,一个非常小的脚本应该可以让它变得更好。

目标:

- 在单元格中输入以小时为单位的持续时间(通常在 0 到 1,000 之间) - 下面的一个单元格,获取剩余小时数的运行倒计时。

目前情况:

我已将工作表设置为每小时自动重新计算,这很好 然后是 4 单元设置,在多个列上重复以跟踪多个计时器:
  • 第一个单元格 (B2) 是输入单元格,以小时为单位输入持续时间
  • 第二个单元格 (B3) 是 =now()+B2/24 ,它计算 B2 产生的预期完成日期
  • 第三个单元格 (B4) 包含 B3 值的硬拷贝,因此重新计算不会更改“确定的预期完成”日期。每次修改 B2 时,我都必须将 + pastevalue 从 B3 复制到 B4,这是该设置的主要问题
  • 第 4 个单元格 (B5) 是 =(int(B4)-int(now()))*24+hour(B4)-hour(now()) 并且是我要注意的运行倒计时。必须使用 int() 而不是 day() 否则当开始日期和完成日期不同时我会遇到错误。

我想要什么:

- 摆脱 2 个中间单元格和它们之间繁琐且容易出错的手动复制粘贴值。 - 一个自动触发脚本,使用可能的公式直接填充 B5(实际上,这将变为 B3)和倒计时 (int(B2+$datetime_of_B2_modification) - int(now())*24 + 小时(B2+$datetime_of_B2_modification) - 小时(now))。 B2 是对 B2 值的直接引用,$datetime_of_B2_modification 是每次我修改 B2 时计算的值,并且只有这样(不是在重新计算工作表时,不是当我将鼠标悬停在 B2 上但实际上没有修改它时)并且是然后硬编码成 B5 的公式; now() 是 gSheet 的实际函数,它返回现在的日期时间。 - 理想情况下,如果我输入小时持续时间,该自动触发脚本会自动在该公式下方的一个单元格中创建该公式,即我不必为电子表格中的每一列制作不同的脚本,它会创建公式“下方一个单元格”,不在固定单元格。

我几十年前的技能已经生疏了,我一直在努力入门,但我无处可去。如果有人能神奇地写出那个剧本,我将不胜感激!

最好的问候,奥利维尔

想一想,自动化复制+粘贴值步骤而不更改任何其他内容的脚本将是一个不错的第一步。去掉多余的 2 行并不是那么重要,尽管它会很好。

在第一个答案后编辑:我觉得我需要以下内容; ??行是我知道是错误的行

function onEdit(e)() {
  if(!e) return;

  var book = SpreadsheetApp.getActiveSpreadsheet();
  var sheet = book.getActiveSheet()
  var sourcecell = book.getActiveCell();

//check the edited cell is a valid source cell

??  var sourcecelladdress = right(getA1Notation(sourcecell),2)  // need to get result such as: 'A1" or 'B1'...
  if ('B2C2D2B8C8D8'.indexOf(sourcecelladress) =-1) return;

// check the cell has actually been modified
  if (e.value = e.oldValue) return; 

//OK, so we're in a valid source cell, and it HAS been modified
// now let's build the formula string

  var sourcevalue = sourcecell.getValue()
  var enddate = sourcevalue/24 + now()
  var enddateday = int (endate) * 24
  var endatetime = hour (enddate)
??  var countdownformula = '=' + (enddateday + enddatehour) + '- (int(now())*24) - hour(now())'


//and now let's put it in the destination cell

??  var destcell = sourcecell + ????? (one row down from active cell)
??  destcell.setformula(countdownformula)
}

【问题讨论】:

    标签: google-apps-script google-sheets


    【解决方案1】:

    下面的代码不是优化的、高效的,也不一定是处理它的最佳方式。下面展示了您声称想要的几个功能,并提出了解决问题的多种方法。

    function onEdit(e){
      // if we did not receive the event data, it is likely 
      // no event occured. This should only happen if we 
      // call it directly.
      // So... if (no event object) get out;
      if(!e) return;
    
    
      // Look up the spreadsheet and and actual 
      // sheet we are goign to be interacting with
      var book = SpreadsheetApp.getActiveSpreadsheet();
      var sheet = book.getSheetByName('Sheet1')
    
      // get the "Working Range" of cells
      var range = book.getRange('B2');
    
      // determine if its the range we are interested in
      var target = range.getA1Notation();
      var change = e.range.getA1Notation();
      if(range.getA1Notation() == e.range.getA1Notation()){
    
        // double check that the value actually changed
        if(e.value != e.oldValue){
          // IT CHANGED!!
          book.toast('Timer setting change detected: ' + e.oldValue + ' -> ' + e.value);
    
          // Change some formulas using relative notiation
          range = book.getRange('B4');
          range.setFormulaR1C1('=R[-1]C[0]');
          range.setValues(range.getValues());
    
          // Apply the future time to a formula in the spreadsheet
          range = book.getRange('B5');
          range.setFormula('=floor((B4-now())*24)');
          // copy and paste the value calculated by the formula
          range.setValue(range.getValue());
    
          //** Hardcoded alternative
          //** I would actually suggest not doing i this way and instead just hiding row 4
    
          // Calculate future time 
          // (this is broken because date math is annoying)
          var future = new Date(); // get NOW
          future.setHours(future.getHours() + e.value); //Add the specified hours to the current hours
          future = (future.getTime() / 86400000.0); // convert the time to fractional days
          future = future + 25569; //adjust the days for different start epochs
    
          // set the formula
          range = book.getRange('B6');
          range.setFormula('=floor((' + future + '-now())*24)');
        }
      }
    }
    

    我知道至少 B6 的计算是不正确的,尽管几乎是正确的。我把它作为一个练习题留给读者来修复日期数学部分。

    GoogleAppsScript 使用 javascript 作为其基础语言,并带有一些自定义库来处理各种自定义内容(如电子表格)。

    一些您可能会觉得有用的参考资料:

    【讨论】:

    • 好的,谢谢,这有帮助。我需要分 3 步完成 1- 设置全局编辑触发器,并检查活动单元格是否在输入单元格列表(硬编码列表)内并且它已被更改;如果不退出 2a- 构建目标单元格的地址(从当前行向下一行) 2b- 将目标单元格的公式构建为文本字符串 3- 粘贴该公式。该死的语法对我来说完全陌生
    • 我已经用我用来构建示例的参考资料更新了答案,并更新了 cmets 以(希望)更好地解释代码。您的 cmets 和代码相似(足够)。该代码确实有效,尽管其中一些是多余的(我做了两次以演示实现同一件事的两种不同方法)。根据您希望流程如何流动,您可能需要更多功能,我尝试将所有功能打包到一个功能中。
    猜你喜欢
    • 2021-06-04
    • 1970-01-01
    • 1970-01-01
    • 2021-09-15
    • 1970-01-01
    • 1970-01-01
    • 2015-05-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多