首页 > 解决方案 > 如何计算两个日期之间的差异

问题描述

我想做的就是这个。

假设在 Google 表格中,我有一个包含以下列的页面:

在 I3 栏中,我的日期是 19 年 11 月 30 日。在 J3 列中,我有今天的日期 4/30/20。我希望能够计算这两个日期之间的差异,并告诉我自 2019 年 11 月 30 日以来已经过了几个月。

在此处输入图像描述

目前,我认为代码有点工作,但我得到的结果是:

[20-05-02 01:43:18:650 MDT] 5 个月零 6 天

[20-05-02 01:43:18:656 MDT] 5 个月零 6 天

[20-05-02 01:43:18:660 MDT] 5 个月零 6 天

但是日期计算仍然是错误的。例如,从 2020 年 1 月 1 日至 1 月 25 日,它显示 5 个月和 6 天。

此外,我在过滤器 1 中的循环只是计算第一个可用日期,然后它会执行此操作 3 次,而不是转到下一条记录并计算。

到目前为止,我有以下代码:

function myFunction() {
   
}

var moment = Moment.load();

/**
 * @summary gets date difference
 * @param {Date} startDate
 * @param {Date} endDate
 * @returns {string}
 */
function getDuration(startDate, endDate) {
   const start = moment(startDate);
   const end = moment(endDate);
   const units = ['years', 'months', 'days'];
   const lastIndex = units.length - 1;
   const parts = units
     .map((unit,i) => {
       const diff = Math.floor(end.diff(start, unit, true));
       if (diff > 0 || i === lastIndex) {
         end.subtract(unit, diff);
         return `${diff} ${unit}`;
       }     
     })
     .filter(Boolean);
   return parts.join(', '); 
}


function Filter2() { // Calculate the Time
   const spread = SpreadsheetApp.getActiveSpreadsheet();
   const sheets = spread.getSheets();
   const [ sheet_1, sheet_2 ] = sheets;
   const row = sheet_1.getRange("A:M");
   const arr_col = sheet_1.getRange("I3:I50"); 
   const lastSeen_col = sheet_1.getRange("J3:J50");  
   const startDate = arr_col.getValue();
   
   var ss = SpreadsheetApp.getActiveSpreadsheet();
   var sheet = ss.getSheets()[0];  
   var headerRowNumber = 2;
   var rows = sheet.getDataRange().offset(headerRowNumber, 0, sheet.getLastRow() - headerRowNumber).getValues();
   var filter = rows.filter(row => row[9] !== '');
   // var digest = filter[0][9];
   
  for(var i=0;i<filter.length; i++){
     var res = getDuration(startDate, lastSeen_col);
      Logger.log(res); 
    }  
} 

标签: javascriptgoogle-apps-scriptgoogle-sheetsmomentjs

解决方案


为什么 1969 年 12 月 31 日

1969 年 12 月 31 日在 GMT-7 时区偏移是 1970 年 1 月 1 日 00:00:00 UTC,这是unix epoch。因此,它很可能是由传递给Moment类实例的无效日期格式引起的。

问题

getRange()方法调用返回一个实例,您必须通过/Range从中提取值才能使用它。考虑到这一点,让我们跟踪脚本中发生的事情:getValue()getValues()

  1. var ArrRow = sheet_1.getRange("I3:I")返回一个实例Range
  2. mydata1在全局某处定义(假设它包含 的实例Date
  3. getDuration因此被称为:getDuration( <Range>, <Date> )
  4. startDateendDate分别是和的一个Range实例Date
  5. startend保存调用创建对象包装器的moment工厂的结果。Date

第 5 步很可能是罪魁祸首,根据 Moment 库文档,moment()它可以接受StringNumberDate实例以及格式选项,但会start收到一个Range实例。

可能的解决方案

首先,您需要确保传入正确的类型(这就是为什么很多人更喜欢 TypeScript 的原因——如果那不是你的爱好,至少开始使用JSDoc——它将为你节省大量的调试时间)。

我不知道范围有多大I3:I,所以我从上下文中假设它是一个包含开始日期的单元格。另请注意,我删除了var sld = new Date(dateString)分配,因为您返回的格式为人类可读的字符串,而该getDuration()格式Y years, M months, D days不是构造函数可以接受的。dateStringDate

此外,我建议更改forEach()map()更清洁且副作用更少的代码的方法。一般的经验法则是,如果输入和输出属于同一类型,您可能需要使用映射函数。

function myFunction() {
   Filter2();
}

function Filter2() {
   const spread = SpreadsheetApp.getActiveSpreadsheet();
   const sheets = spread.getSheets();

   const [ sheet_1, sheet_2 ] = sheets;

   const arr_col = sheet_1.getRange("I3:I"); 

   const startDate = arr_col.getValue();

   var dateString = getDuration(startDate, mydata1);

   Logger.log(dateString);
}

var moment = Moment.load();

/**
 * @summary gets date difference
 * @param {Date} startDate
 * @param {Date} endDate
 * @returns {string}
 */
function getDuration(startDate, endDate) {
   const start = moment(startDate);
   const end = moment(endDate);

   const units = ['years', 'months', 'days'];
   const lastIndex = units.length - 1;

   const parts = units
     .map((unit,i) => {
       const diff = Math.floor(end.diff(start, unit, true));

       if (diff > 5 || i === lastIndex) {
         end.subtract(unit, diff);

         return `${diff} ${unit}`;
       }     

     })
     .filter(Boolean);


   return parts.join(', '); 
}

笔记

  1. 答案假设您使用 V8 引擎(如果您不切换到它,旧引擎将在未来某个时间被弃用,作为奖励,您可以使用所有最有趣的语言功能 [嗯,其中大部分]) .

参考

  1. DateMDN 上的构造函数文档
  2. Range文档
  3. getValue()方法文档
  4. getValues()方法文档

推荐阅读