MySQL中date之间的差异

我正在计算两个date时间字段之间的月数。

有没有比得到unix时间戳和除以2 592 000(秒)并在MySQL中取整更好的方法?

DATEDIFF函数可以给你两个date之间的天数。 哪一个更准确,因为…你如何定义一个月? (28,29,30或31天?)

任何给定的两个date之间的月份差异:

我很惊讶,这还没有提到:

看看MySQL中的TIMESTAMPDIFF()函数。

这可以让你做的是传递两个TIMESTAMPDATETIME值(甚至DATE因为MySQL将自动转换)以及你想要根据你的差异的时间单位。

您可以在第一个参数中指定MONTH作为单位:

 SELECT TIMESTAMPDIFF(MONTH, '2012-05-05', '2012-06-04') -- Outputs: 0 

 SELECT TIMESTAMPDIFF(MONTH, '2012-05-05', '2012-06-05') -- Outputs: 1 

 SELECT TIMESTAMPDIFF(MONTH, '2012-05-05', '2012-06-15') -- Outputs: 1 

 SELECT TIMESTAMPDIFF(MONTH, '2012-05-05', '2012-12-16') -- Outputs: 7 

它基本上从参数列表中获取从第一个date起经过的月数。 这个解决scheme可以自动补偿每个月的不同天数(28,30,31),同时考虑到闰年 – 你不必担心这些东西。


月份与精确度的差异:

如果您想要在已经过去的月数中引入小数精度,那会更复杂一些,但是您可以这样做:

 SELECT TIMESTAMPDIFF(MONTH, startdate, enddate) + DATEDIFF( enddate, startdate + INTERVAL TIMESTAMPDIFF(MONTH, startdate, enddate) MONTH ) / DATEDIFF( startdate + INTERVAL TIMESTAMPDIFF(MONTH, startdate, enddate) + 1 MONTH, startdate + INTERVAL TIMESTAMPDIFF(MONTH, startdate, enddate) MONTH ) 

startdateenddate是您的date参数,无论是来自表中的两个date列还是来自脚本的input参数:

例子:

 With startdate = '2012-05-05' AND enddate = '2012-05-27': -- Outputs: 0.7097 

 With startdate = '2012-05-05' AND enddate = '2012-06-13': -- Outputs: 1.2667 

 With startdate = '2012-02-27' AND enddate = '2012-06-02': -- Outputs: 3.1935 

PERIOD_DIFF计算两个date之间的月份。

例如,要计算your_table中now()和time列之间的差异:

 select period_diff(date_format(now(), '%Y%m'), date_format(time, '%Y%m')) as months from your_table; 

我也使用PERIODDIFF 。 要获取date的年份和月份,我使用函数EXTRACT :

  SELECT PERIOD_DIFF(EXTRACT(YEAR_MONTH FROM NOW()), EXTRACT(YEAR_MONTH FROM time)) AS months FROM your_table; 

从MySQL手册:

PERIOD_DIFF(P1,P2)

返回期间P1和P2之间的月数。 P1和P2的格式应该是YYMM或YYYYMM。 请注意,周期参数P1和P2不是date值。

mysql> SELECT PERIOD_DIFF(200802,200703); – > 11

所以有可能做这样的事情:

 Select period_diff(concat(year(d1),if(month(d1)<10,'0',''),month(d1)), concat(year(d2),if(month(d2)<10,'0',''),month(d2))) as months from your_table; 

其中d1和d2是dateexpression式。

我不得不使用if()语句来确保月份是一个两位数字,如02而不是2。

我更喜欢这种方式,因为艾弗龙一眼就能明白地理解它:

 SELECT 12 * (YEAR(to) - YEAR(from)) + (MONTH(to) - MONTH(from)) AS months FROM tab; 

有没有更好的办法? 是。 不要使用MySQL时间戳。 除了占用36字节之外,还不方便使用。 我会build议从午夜时分开始使用Julian Date和Seconds来计算所有date/时间值。 这些可以组合起来形成UnixDateTime。 如果这是存储在一个DWORD(无符号4字节整数),那么date一直到2106可以存储为自从epoc,01/01/1970 DWORD最大val = 4,294,967,295秒 – 一个DWORD可以保存136年的秒

Julian Dates在进行date计算时非常好用UNIXDateTime值在进行date/时间计算时非常有用既不好看,所以我使用Timestamps时我需要一个列,我不会做太多的计算与,但我想要一目了然的迹象。

转换到朱利安和回来可以用一种良好的语言很快完成。 使用指针,我已经下降到大约900 Clks(当然这也是从STRING转换为INTEGER)

当你进入使用date/时间信息(比如金融市场)的严重应用程序时,Juliandate是事实上的。

select来自客户的period_diff(date_format(now(),“%Y%m”),date_format(创build,“%Y%m”))..

自从客户logging上创build的date戳之后给出许多日历月,让MySQL在内部执行月份select。

 DROP FUNCTION IF EXISTS `calcula_edad` $$ CREATE DEFINER=`root`@`localhost` FUNCTION `calcula_edad`(pFecha1 date, pFecha2 date, pTipo char(1)) RETURNS int(11) Begin Declare vMeses int; Declare vEdad int; Set vMeses = period_diff( date_format( pFecha1, '%Y%m' ), date_format( pFecha2, '%Y%m' ) ) ; /* Si el dia de la fecha1 es menor al dia de fecha2, restar 1 mes */ if day(pFecha1) < day(pFecha2) then Set vMeses = VMeses - 1; end if; if pTipo='A' then Set vEdad = vMeses div 12 ; else Set vEdad = vMeses ; end if ; Return vEdad; End select calcula_edad(curdate(),born_date,'M') -- for number of months between 2 dates 

执行这个代码,它会创build一个函数datedeifference,它会给你date格式yyyy-mm-dd的区别。

 DELIMITER $$ CREATE FUNCTION datedifference(date1 DATE, date2 DATE) RETURNS DATE NO SQL BEGIN DECLARE dif DATE; IF DATEDIFF(date1, DATE(CONCAT(YEAR(date1),'-', MONTH(date1), '-', DAY(date2)))) < 0 THEN SET dif=DATE_FORMAT( CONCAT( PERIOD_DIFF(date_format(date1, '%y%m'),date_format(date2, '%y%m'))DIV 12 , '-', PERIOD_DIFF(date_format(date1, '%y%m'),date_format(date2, '%y%m'))% 12 , '-', DATEDIFF(date1, DATE(CONCAT(YEAR(date1),'-', MONTH(DATE_SUB(date1, INTERVAL 1 MONTH)), '-', DAY(date2))))), '%Y-%m-%d'); ELSEIF DATEDIFF(date1, DATE(CONCAT(YEAR(date1),'-', MONTH(date1), '-', DAY(date2)))) < DAY(LAST_DAY(DATE_SUB(date1, INTERVAL 1 MONTH))) THEN SET dif=DATE_FORMAT( CONCAT( PERIOD_DIFF(date_format(date1, '%y%m'),date_format(date2, '%y%m'))DIV 12 , '-', PERIOD_DIFF(date_format(date1, '%y%m'),date_format(date2, '%y%m'))% 12 , '-', DATEDIFF(date1, DATE(CONCAT(YEAR(date1),'-', MONTH(date1), '-', DAY(date2))))), '%Y-%m-%d'); ELSE SET dif=DATE_FORMAT( CONCAT( PERIOD_DIFF(date_format(date1, '%y%m'),date_format(date2, '%y%m'))DIV 12 , '-', PERIOD_DIFF(date_format(date1, '%y%m'),date_format(date2, '%y%m'))% 12 , '-', DATEDIFF(date1, DATE(CONCAT(YEAR(date1),'-', MONTH(date1), '-', DAY(date2))))), '%Y-%m-%d'); END IF; RETURN dif; END $$ DELIMITER; 

这取决于你想要如何定义月数。 回答这个问题:“几个月有什么不同:2008年2月15日 – 2009年3月12日”。 它是由明确的天数定义的,这取决于闰年 – 月份是哪一天,还是上个月的同一天= 1个月。

计算天数

2月15日 – > 29日(闰年)= 2008年3月1日+ 365日= 2009年3月1日3月1日 – > 3月12日= 12日。 14 + 365 + 12 = 391天。 总计= 391天/(平均每月的30天)= 13.03333

一个月的计算

2008年2月15日 – 2009年2月15日= 12月15日 – > 3月12日=less于1个月总数= 12个月,如果15日 – 15日12月被认为是“过去一个月”

 SELECT * FROM emp_salaryrevise_view WHERE curr_year Between '2008' AND '2009' AND MNTH Between '12' AND '1' 

你可以用这种方法得到几年,几个月和几天:

 SELECT username ,date_of_birth ,DATE_FORMAT(CURDATE(), '%Y') - DATE_FORMAT(date_of_birth, '%Y') - (DATE_FORMAT(CURDATE(), '00-%m-%d') < DATE_FORMAT(date_of_birth, '00-%m-%d')) AS years ,PERIOD_DIFF( DATE_FORMAT(CURDATE(), '%Y%m') , DATE_FORMAT(date_of_birth, '%Y%m') ) AS months ,DATEDIFF(CURDATE(),date_of_birth) AS days FROM users 

我需要精确的月份差异。 虽然Zane Bien的解决方法是正确的,但他的第二个和第三个例子给出了不准确的结果。 二月份的一天除以二月份的天数不等于五月份的一天,再除以五月份的天数。 所以第二个例子应该输出((31-5 + 1)/ 31 + 13/30 =)1.3043和第三个例子((29-27 + 1)/ 29 + 2/30 + 3 =)3.1701。

我结束了以下查询:

 SELECT '2012-02-27' AS startdate, '2012-06-02' AS enddate, TIMESTAMPDIFF(DAY, (SELECT startdate), (SELECT enddate)) AS days, IF(MONTH((SELECT startdate)) = MONTH((SELECT enddate)), 0, (TIMESTAMPDIFF(DAY, (SELECT startdate), LAST_DAY((SELECT startdate)) + INTERVAL 1 DAY)) / DAY(LAST_DAY((SELECT startdate)))) AS period1, TIMESTAMPDIFF(MONTH, LAST_DAY((SELECT startdate)) + INTERVAL 1 DAY, LAST_DAY((SELECT enddate))) AS period2, IF(MONTH((SELECT startdate)) = MONTH((SELECT enddate)), (SELECT days), DAY((SELECT enddate))) / DAY(LAST_DAY((SELECT enddate))) AS period3, (SELECT period1) + (SELECT period2) + (SELECT period3) AS months 

这个查询为我工作:)

 SELECT * FROM tbl_purchase_receipt WHERE purchase_date BETWEEN '2008-09-09' AND '2009-09-09' 

它只需要两个date,并检索它们之间的值。