【问题标题】:Calculate the difference between 2 SQLite datetimes in Javascript计算 Javascript 中 2 个 SQLite 日期时间之间的差异
【发布时间】:2012-10-07 11:44:00
【问题描述】:

我有一个 startDate 和一个 endDate 存储在 SQLite 数据库中,需要使用 javascript 计算两个日期时间之间的分钟和秒差。

例如:

startDate = 2012-10-07 11:01:13
endDate = 2012-10-07 12:42:13

我读过很多关于 SO 的类似问题,但只能找到与作为选择的一部分计算此相关的内容。

【问题讨论】:

  • 你真的需要“小时和秒”的格式吗?不是更常见的“小时、分钟、秒”?
  • 是的,抱歉打错了 - 应该是分秒。

标签: javascript sqlite datetime


【解决方案1】:

将字符串转换为 JS Date 对象,减去日期,并使用一些算法从结果中计算小时/秒。比如:

function convertMS(ms) {
  var d, h, m, s, ts, tm, th;
  s = ts = Math.floor(ms / 1000);
  m = tm = Math.floor(s / 60);
  s = s % 60;
  h = th = Math.floor(m / 60);
  m = m % 60;
  d = Math.floor(h / 24);
  h = h % 24;
  return { d: d, h: h, m: m, s: s, tm: tm, th: th, ts: ts};
};
var start = new Date('2012-10-07 11:01:13'.split('-').join('/'))
   ,end   = new Date('2012-10-07 12:42:13'.split('-').join('/'))
   ,dif   = convertMS(end - start);
console.log(dif.h+':'+dif.m);​​​​​​ //=> ​1:41
console.log('total minutes dif: '+dif.tm);​​​​​​ //=> total ​minutes dif: 101
console.log('total seconds dif: '+dif.ts);​​​​​​ //=> ​total seconds dif: 6060

[编辑基于评论]
以提供的格式“手动”解析日期字符串:

Date.tryParse = function(ds){
  var  arr =  ds.match(/\d+/g)
      ,err = 'Expected at least yyyy'
      ,dat = arr.length && String(arr[0]).length === 4
              ? doParse.apply(null,arr) : err;
  return dat;

  function doParse(y,m,d,h,mi,s,ms){
   var dat = new Date(+y,(+m-1)||0,+d||1,+h||0,+mi||0,+s||0,+ms||0);
   return isNaN(dat) ? new Date : dat;
  }
}
var start = Date.tryParse('2012-10-07 11:01:13'); //=> Sun Oct 07 2012 11:01:13
var test  = Date.tryParse('2009');                //=> Sun Jan 01 2009 00:00:00

【讨论】:

  • OP 的日期字符串不符合 ES5 中为 Date.parse 指定的格式。手动解析字符串要好得多。
  • iiuc,OP 要求转换为分钟和秒的总增量,而不仅仅是转换为天、小时、分钟和秒后的增量的分钟和秒部分,这就是您的答案目前正在提供。换句话说,如果两次相隔 3 天 8 小时 3 分钟 15 秒,您的 sn-p 将给他“3 分 15 秒”作为增量。
  • 非常感谢大家的详细解答。由于这似乎是最深入和最详细的,我已经开始将它添加到我的代码中进行测试。再次感谢您。
【解决方案2】:

关于将日期转换为纪元时间的毫秒,减去这些,并将结果从毫秒转换回您所需的单位,所有答案通常都是正确的(尽管其他地方提供的具体实现目前并不能准确地为您提供要求 - 即两个日期时间之间的分钟数和秒数)。

不过,请注意...

新日期('2012-10-07 12:42:13')

...这不是从 SQLite 日期字符串构造日期的可靠方法。

当您将字符串输入到 Date 对象的构造函数中时,您实际上是在调用 Date.parse()。这在不同的浏览器上表现不同。

看看这个:

> new Date('1-1-2012');
Sun Jan 01 2012 00:00:00 GMT-0800 (PST)

> new Date('01-01-2012');
Sun Jan 01 2012 00:00:00 GMT-0800 (PST)

> new Date('2012-1-1');
Sun Jan 01 2012 00:00:00 GMT-0800 (PST)

看起来不错,对吧?但那是在 Chrome 上。

现在看看最新版本的 Firefox 中发生了什么,调用完全相同:

> new Date('1-1-2012');
Date {Invalid Date}

> new Date('01-01-2012');
Date {Invalid Date}

> new Date('2012-1-1');
Date {Invalid Date}

> new Date('2012-01-01');
Date {Sat Dec 31 2011 16:00:00 GMT-0800 (PST)}

此外,看看这两种浏览器的行为:

> new Date('2012-01-01');
Sat Dec 31 2011 16:00:00 GMT-0800 (PST)

简单地将零添加到月份和日期数字会导致时间扭曲!你必须设置时间和时区(对我来说,PST)才能让它消失:

> new Date('2012-01-01T00:00:00-08:00')
Sun Jan 01 2012 00:00:00 GMT-0800 (PST)

基本上,处理日期字符串解析是一件令人头疼的事情。您不需要消化和考虑 thisthisthis 等规范。

所以,这是一个更好的选择——将日期时间的各个部分作为单独的参数传递给 Date 对象的构造函数。这将为您可靠地创建日期,因此您的后续比较是有效的。

新日期(年、月、日[、时、分、秒、毫秒])

对于您的案例,初始化可能如下所示:

// Extract month, day, year from SQLite format, 'trimming' whitespace.
var sqlLiteSampleStr = "2012-10-07 11:01:13";
var re = /^\s*(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})\s*$/;
var match = re.exec(sqlLiteSampleStr);
if (match) {
  var year = parseInt(match[1]);
  var month = parseInt(match[2]) - 1; // Zero-indexed months.
  var date = parseInt(match[3]);
  var hour = parseInt(match[4]);
  var minute = parseInt(match[5]);
  var second = parseInt(match[6]);
  var date = new Date(year, month, date, hour, minute, second);
}

注意:请注意时区问题。您似乎没有任何 SQLite 格式 sn-p 的时区数据。

更新

@james-j 澄清说他正在寻找分钟和秒。

这里有一个 sn-p 来提取分钟和秒:

var msPerMin = 1000 * 60;
var min = Math.floor(timeInMs / msPerMin);
var timeInMs = timeInMs - (min * msPerMin);
var sec = Math.floor(timeInMs / 1000 );

【讨论】:

  • 感谢您非常深入的回答。
【解决方案3】:

其他答案是正确的,但是浏览器不会始终如一地解析日期字符串(见下文),因此您应该手动解析字符串。 OP 中的格式也与 ES5 中的格式不一致,部分浏览器无法正确解析。将 OP 格式转换为适用于所有浏览器的日期的简单函数是:

function stringToDate(s) { 
    s = s.split(/[-\/\. :]/);
    return new Date(s[0], --s[1], s[2], s[3], s[4], s[5], 0)
}

所有浏览器都会解析某些格式,但它们不符合标准,如果使用,则依赖于继续支持未指定格式的所有实现。

编辑

为了容忍格式错误的输入(额外的空格、不同的分隔符、额外的字符),可以使用match 代替split

function stringToDate(s) { 
    s = s.match(/\d+/g);
    return new Date(s[0], --s[1], s[2], s[3], s[4], s[5], 0)
}

但是,由于这些值来自数据库并且已指定格式,因此日期字符串应符合该格式。一开始就不应该存储错误的数据。

为了完整起见,这里有一个函数可以做你想做的事:

/*  Return difference between two dates as minutes and seconds mm:ss.
 *  Input format is yyyy-mm-dd hh:mm:ss
 *  If strings don't converted to dates (incorrect format or invalid values),
 *  return undefined.
 */
function diffInMins(s0, s1) {
  var diff;

  // Convert strings to date ojbects
  var d0 = stringToDate(s0);
  var d1 = stringToDate(s1);

  // Helper function to padd with leading zero
  function z(n) {
    return (n<10? '0' : '') + n;
  }

  // Check conversions
  if (d0 && d1 && typeof d0 == 'object' && typeof d1 == 'object') {

    // Return difference formatted as mm:ss
    if (d0 && d1) {
      diff = d1 - d0;
      return z(diff/60000 | 0) + ':' + z(Math.round(diff%60000/1000));
    }
  }
}

【讨论】:

  • 这个例子有点离谱。如果有前导空格,则拆分数组中会有额外的元素,从而丢弃生成的日期值。月份值中还有一个非一的值(零索引月份)。
  • @manzoid——当然,您需要预处理用户输入以检查格式、删除多余的空格等,这需要一行代码,并且无论您打算如何解析细绳。月指数占,注意--s[1]
  • 是的,只是小问题,因为展示强大的解决方案是件好事。您对各种 cmet 进行了良好的编辑。你是对的,你在那里有 -- 运算符。再次出于稳健性的考虑,如果表示为“- 1”,则可能更易于阅读。类似的可读性说明——最好避免按位或强制转换为数字,以支持更自描述的技术。无论如何,OP应该对这些深思熟虑的答案进行投票,但我将从投票开始。干杯--
【解决方案4】:

JavaScript 实际上使减去日期变得非常简单。以下是它的工作原理:

// Create Date objects from the strings
startDate = new Date('2012-10-07 11:01:13');
endDate = new Date('2012-10-07 12:42:13');

// Subtract Date objects to return milliseconds between them
millisecondsBetween = (endDate - startDate);

// Convert to whatever you like
alert(millisecondsBetween/1000/60 + ' minutes');

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-08
    • 2010-09-22
    • 1970-01-01
    • 2013-02-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-25
    • 2011-08-01
    相关资源
    最近更新 更多