简体   繁体   English

如何计算MySQL中两个日期之间的年月日(不定义函数)

[英]How to Compute Years, Months and Days Between Two Dates in MySQL (without defining a function)

My goal is to use MySQL to calculate the number of years, months and days between two dates without defining a function/stored procedure.我的目标是使用 MySQL 来计算两个日期之间的年数、月数和天数,而无需定义函数/存储过程。 The desired output would be "12y 5m 3d" (twelve years, five months, three days).所需的 output 将是“12y 5m 3d”(十二年零五个月零三天)。

I've studied multiple earlier posts, and I'm close but struggling with the "days" component.我已经研究了多个早期的帖子,我很接近但正在努力解决“天”部分。

So far I have:到目前为止,我有:

SET @ReferenceDate = '1988-06-04';

SELECT CONCAT (  FLOOR( (TIMESTAMPDIFF(MONTH, @ReferenceDate, CURDATE()) / 12) ), 'y ',
                 MOD(    TIMESTAMPDIFF(MONTH, @ReferenceDate, CURDATE()) , 12)  , 'm ',
                 /* not sure what function to use for the remaining "days" portion */   'd '
               ) AS Duration;

I believe I can use the DATEDIFF(date1, date2) to get the number of dates, but I am struggling to configure the correct second argument so it only calculates the days in the final partial month (not the number of days since inception).我相信我可以使用 DATEDIFF(date1, date2) 来获取日期数,但我正在努力配置正确的第二个参数,因此它只计算最后部分月份的天数(而不是自开始以来的天数)。

Any guidance on this point would be greatly appreciated.任何关于这一点的指导将不胜感激。 Thank you!谢谢!

Heavily based on this answer , and also accounting for @ReferenceDate possibly being in the future (hence the use of ABS() ):很大程度上基于这个答案,并且还考虑到@ReferenceDate可能在未来(因此使用ABS() ):

SET @ReferenceDate = '1988-06-04';

SELECT 
CONCAT(
  ABS(DATE_FORMAT( CURDATE(),  '%Y' ) - DATE_FORMAT( @ReferenceDate,  '%Y' )), 'y',
  ABS(DATE_FORMAT( CURDATE(),  '%m' ) - DATE_FORMAT( @ReferenceDate,  '%m' )), 'm',
  ABS(DATE_FORMAT( CURDATE(),  '%d' ) - DATE_FORMAT( @ReferenceDate,  '%d' )), 'd'
) AS Duration

The problem you are encountering is you could have any day as the reference basis, and the date you run could be any other day.您遇到的问题是您可以将任何一天作为参考基础,而您运行的日期可能是其他任何一天。 Ex: a date basis of 19th of the month, but today is the 4th.例如:日期为每月 19 日,但今天是 4 日。 What you need to do is bring the NOW date back however many days of the base date so the base date is now in effect the first of its month.您需要做的是将 NOW 日期带回基准日期的多少天,因此基准日期现在是其月份的第一天。

So, reference date (just to be different than the 4th which is same as current date)所以,参考日期(只是不同于与当前日期相同的 4 日)

RefDate = '1988-06-18' (June 18th). RefDate = '1988-06-18'(6 月 18 日)。 So, if we bring this date back to the first of the month, we are subtracting 17 days.所以,如果我们把这个日期带回到本月的第一天,我们就会减去 17 天。 Now, take whatever TODAY is and bring IT back 17 days so it is offset by the same day shift.现在,不管今天是什么,把它带回来 17 天,这样它就会被同一个白班抵消。 Sept 4th - 17 days gets you to Aug 18th. 9 月 4 日 - 17 天让您到 8 月 18 日。 Now, you have a 1st-of-the-month date correlation to the same date-shift as today.现在,您将每月 1 日的日期关联到与今天相同的日期偏移。 So your # of days is now 18. Your years and month computations looked to be ok.所以你的天数现在是 18。你的年月计算看起来没问题。

By doing a DATE_ADD() based on 1 - dayofmonth( @ReferenceDate ) gets you to first of the month.通过基于 1 - dayofmonth( @ReferenceDate ) 执行 DATE_ADD() 可以让您到达本月的第一天。 Ex: 18th becomes a date add of 1-18 = negative 17, thus rolling BACK 17 days.例如:18 日变成 1-18 的日期加法 = 负 17,因此回滚 17 天。

Here is a sample of such output.以下是此类 output 的示例。

select
       FLOOR( (TIMESTAMPDIFF(MONTH, subset.baseDate, subset.DateShift) / 12) ) difYears,
       MOD(  TIMESTAMPDIFF(MONTH, subset.baseDate, subset.DateShift) , 12) difMonths,
       DAYOFMONTH( subset.DateShift ) difDays
   from
      ( select 
             dayofmonth( @ReferenceDate ) -1 as daysOffset,
             date_add( @ReferenceDate, INTERVAL 1-dayofmonth( @ReferenceDate ) DAY ) as baseDate,
             date_add( curdate(), INTERVAL 1-dayofmonth( @ReferenceDate ) DAY ) as DateShift
          from 
             ( select @ReferenceDate := '1988-06-08' ) sqlvars ) subset

If you are trying to pull all records for some given criteria, just change the inner query to something like如果您尝试提取某些给定条件的所有记录,只需将内部查询更改为类似

select
       subset.*,
       FLOOR( (TIMESTAMPDIFF(MONTH, subset.baseDate, subset.DateShift) / 12) ) difYears,
       MOD(  TIMESTAMPDIFF(MONTH, subset.baseDate, subset.DateShift) , 12) difMonths,
       DAYOFMONTH( subset.DateShift ) difDays
   from
      ( select 
             dayofmonth( yt.SomeDateColumn ) -1 as daysOffset,
             date_add( yt.SomeDateColumn, INTERVAL 1-dayofmonth( yt.SomeDateColumn ) DAY ) as baseDate,
             date_add( curdate(), INTERVAL 1-dayofmonth( yt.SomeDateColumn ) DAY ) as DateShift,
             yt.OtherColumnsYouMayWant
          from 
             YourTable yt
          where 
             yt.SomeColumnCondition = 'whatever' ) subset

So now, you can get MANY records with each of their respective reference date basis, with its corresponding daysOffset computedd and its current date shifted by said days all in a pre-query.因此,现在,您可以在预查询中获得具有各自参考日期基础的许多记录,并计算其相应的 daysOffset 并将其当前日期偏移所述天数。 THEN pull your years/months/days from that result.然后从该结果中提取您的年/月/日。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM