javascript - 如何计算两个日期之间的差异
问题描述
我想做的就是这个。
假设在 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);
}
}
解决方案
为什么 1969 年 12 月 31 日
1969 年 12 月 31 日在 GMT-7 时区偏移是 1970 年 1 月 1 日 00:00:00 UTC,这是unix epoch。因此,它很可能是由传递给Moment
类实例的无效日期格式引起的。
问题
getRange()
方法调用返回一个实例,您必须通过/Range
从中提取值才能使用它。考虑到这一点,让我们跟踪脚本中发生的事情:getValue()
getValues()
var ArrRow = sheet_1.getRange("I3:I")
返回一个实例Range
mydata1
在全局某处定义(假设它包含 的实例Date
)getDuration
因此被称为:getDuration( <Range>, <Date> )
startDate
和endDate
分别是和的一个Range
实例Date
start
并end
保存调用创建对象包装器的moment
工厂的结果。Date
第 5 步很可能是罪魁祸首,根据 Moment 库文档,moment()
它可以接受String
、Number
、Date
实例以及格式选项,但会start
收到一个Range
实例。
可能的解决方案
首先,您需要确保传入正确的类型(这就是为什么很多人更喜欢 TypeScript 的原因——如果那不是你的爱好,至少开始使用JSDoc——它将为你节省大量的调试时间)。
我不知道范围有多大I3:I
,所以我从上下文中假设它是一个包含开始日期的单元格。另请注意,我删除了var sld = new Date(dateString)
分配,因为您返回的格式为人类可读的字符串,而该getDuration()
格式Y years, M months, D days
不是构造函数可以接受的。dateString
Date
此外,我建议更改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(', ');
}
笔记
- 答案假设您使用 V8 引擎(如果您不切换到它,旧引擎将在未来某个时间被弃用,作为奖励,您可以使用所有最有趣的语言功能 [嗯,其中大部分]) .
参考
推荐阅读
- python - 在 Python 中使用 glob 时如何选择具有最新版本号的路径?
- c# - HttpRequest on Azure Function doesn't work with https
- web-scraping - 如何为表格中的表格进行网络抓取 google-sheet通过 importxml 或 importhtml?
- python - 导出到 excel 文件时如何抑制 pandas DF 中的科学记数法?
- random - 生成和调用许多随机数的最佳方法?
- vb.net - 使用 FilterDataRow VB.Net 在 DataGridView 中搜索数据
- terraform - 无法从 Terraform 外部打开 terraform plan -out 文件?
- python - 查询以在 pymongo 中查找嵌套字典
- c++ - 如何解决 mingw32-make.exe : *** [ALL] Codelite 中的错误 2?
- f# - 不考虑 if-else 表达式后的缩进变化?