如何使用MySQL查询获取两个日期之间的月份差异?

115

我想要计算两个日期时间字段之间的月数。

MySQL 中是否有更好的方法,而不是获取 Unix 时间戳,然后除以 2592000(秒),并向上取整?

21个回答

2

执行此代码,它将创建一个名为datedifference的函数,该函数将以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;

1
你觉得你能否清理并注释一下你的代码,使其更易于理解一些?谢谢。 - Darryl Hein

1

PERIOD_DIFF() 函数

MySQL 中 PERIOD_DIFF() 函数可以返回两个周期之间的差值。这两个周期应该采用相同的格式,即 YYYYMM 或 YYMM。需要注意的是,这里的周期不是日期值。

代码:

SELECT PERIOD_DIFF(200905,200811);

enter image description here


1

这取决于您希望如何定义月数。回答以下问题:“二月15日,2008年至三月12日,2009年之间相差几个月?”它是由明确的天数定义的,这取决于闰年的数量、月份或上个月的同一天= 1个月。

天数计算:

2月15日-> 29(闰年)= 14 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个月 2月15日-> 3月12日= 不到1个月 总计= 12个月,如果将2月15日-3月12日视为“上个月”,则为13个月


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

1
我需要精确的月份差。虽然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

0

你也可以尝试这个:

select MONTH(NOW())-MONTH(table_date) as 'Total Month Difference' from table_name;

或者

select MONTH(Newer_date)-MONTH(Older_date) as 'Total Month Difference' from table_Name;

0

尽管这是一个古老的话题,但它在谷歌上排名靠前,我没有看到与Mysql相关的更新问题来计算月份差异。我需要非常精确的计算,包括不完整月份的计算。

这是为了计算订阅费用,例如每个月8欧元。然后,2月1日的价格与其他月份不同。因此,需要计算月份的分数,这里分数的精度基于秒。

它将计算分为3部分,当计算@from和@to日期之间的差异时:

  1. @from和@from日历月份结束之间的日历月份分数
  2. @from和@to之间的整个日历月份数
  3. 从日历月份开始到@to之间的日历月份分数

例如从'2021-09-29 12:00:00'到'2021-11-07 00:00:00':

  1. 2021年9月底的1.5天。由于9月有30天,所以分数为0.05个月(1.5/30)。
  2. 2021年10月整个月,因此是1个完整的月。
  3. 2021年11月初的6天。由于11月有30天,所以分数为0.2个月(6/30)。

因此,总共为1.25个月。

set @from  = '2021-09-29 12:00:00';
set @to    = '2021-11-07 00:00:00';
select 
/* part 1 */ (unix_timestamp(last_day(@from)) + 86400 - unix_timestamp(@from)) / 86400 / day(last_day(@from))
/* part 2 */ + PERIOD_DIFF(EXTRACT(YEAR_MONTH FROM @to), EXTRACT(YEAR_MONTH FROM @from)) - 1 +
/* part 3 */ 1 - (unix_timestamp(last_day(@to)) + 86400 - unix_timestamp(@to)) / 86400 / day(last_day(@to)) 
month_fraction;

完全相同的计算,但现在基于字段进行,适用于不使用MySQL变量且更容易接管自己的字段:

select 
/* part 1 */ (unix_timestamp(last_day(periodStart)) + 86400 - unix_timestamp(periodStart)) / 86400 / day(last_day(periodStart))
/* part 2 */ + PERIOD_DIFF(EXTRACT(YEAR_MONTH FROM periodTill), EXTRACT(YEAR_MONTH FROM periodStart)) - 1 +
/* part 3 */ 1 - (unix_timestamp(last_day(periodTill)) + 86400 - unix_timestamp(periodTill)) / 86400 / day(last_day(periodTill))
month_fraction
from (select '2021-09-29 12:00:00' periodStart, '2021-11-07 00:00:00' periodTill) period

为了提高速度优化,我使用了unix_timestamp,它应该能够快速执行数学计算。 unix_timestamp返回一个以秒为单位的数字。 86400是一天中的秒数。

0

试试这个

SELECT YEAR(end_date)*12 + MONTH(end_date) - (YEAR(start_date)*12 + MONTH(start_date))

欢迎来到 Stack Overflow!请确保检查问题的日期以及现有答案是否具有相同的解决方案。 - lehiester

0
你可以用以下方式获取年份、月份和日期:
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

0

简单回答:将起始日期命名为 ins_frm,将结束日期命名为 ins_to。

SELECT convert(TIMESTAMPDIFF(year, ins_frm, ins_to),UNSIGNED) as yrs,
       mod(TIMESTAMPDIFF(MONTH, ins_frm, ins_to),12) mnths
FROM table_name

享受 :)))


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接