14

我需要得到两个日期之间的差异,如果差异是 84 天,我可能应该有 2 个月和 14 天的输出,我刚刚给出的代码给出了总数。这是代码

SELECT Months_between(To_date('20120325', 'YYYYMMDD'),
       To_date('20120101', 'YYYYMMDD'))
       num_months,
       ( To_date('20120325', 'YYYYMMDD') - To_date('20120101', 'YYYYMMDD') )
       diff_in_days
FROM   dual; 

输出是:

NUM_MONTHS    DIFF_IN_DAYS
2.774193548       84

例如,我需要此查询的输出为 2 个月和最坏的 14 天,否则我不介意我是否可以在月份数字之后获得确切的天数,因为那些天并不是真正的 14 天,因为所有月份都没有30天。

4

9 回答 9

21
select 
  dt1, dt2,
  trunc( months_between(dt2,dt1) ) mths, 
  dt2 - add_months( dt1, trunc(months_between(dt2,dt1)) ) days
from
(
    select date '2012-01-01' dt1, date '2012-03-25' dt2 from dual union all
    select date '2012-01-01' dt1, date '2013-01-01' dt2 from dual union all
    select date '2012-01-01' dt1, date '2012-01-01' dt2 from dual union all
    select date '2012-02-28' dt1, date '2012-03-01' dt2 from dual union all
    select date '2013-02-28' dt1, date '2013-03-01' dt2 from dual union all
    select date '2013-02-28' dt1, date '2013-04-01' dt2 from dual union all
    select trunc(sysdate-1)  dt1, sysdate               from dual
) sample_data

结果:

|                        DT1 |                       DT2 | MTHS |     DAYS |
----------------------------------------------------------------------------
|  January, 01 2012 00:00:00 |   March, 25 2012 00:00:00 |    2 |       24 |
|  January, 01 2012 00:00:00 | January, 01 2013 00:00:00 |   12 |        0 |
|  January, 01 2012 00:00:00 | January, 01 2012 00:00:00 |    0 |        0 |
| February, 28 2012 00:00:00 |   March, 01 2012 00:00:00 |    0 |        2 |
| February, 28 2013 00:00:00 |   March, 01 2013 00:00:00 |    0 |        1 |
| February, 28 2013 00:00:00 |   April, 01 2013 00:00:00 |    1 |        1 |
|   August, 14 2013 00:00:00 |  August, 15 2013 05:47:26 |    0 | 1.241273 |

测试链接:SQLFiddle

于 2013-08-13T16:00:15.603 回答
2

更新的正确性。最初由@jen 回答。

with DATES as (
   select TO_DATE('20120101', 'YYYYMMDD') as Date1,
          TO_DATE('20120325', 'YYYYMMDD') as Date2
   from DUAL union all
   select TO_DATE('20120101', 'YYYYMMDD') as Date1,
          TO_DATE('20130101', 'YYYYMMDD') as Date2
   from DUAL union all
   select TO_DATE('20120101', 'YYYYMMDD') as Date1,
          TO_DATE('20120101', 'YYYYMMDD') as Date2
   from DUAL union all
   select TO_DATE('20130228', 'YYYYMMDD') as Date1,
          TO_DATE('20130301', 'YYYYMMDD') as Date2
   from DUAL union all
   select TO_DATE('20130228', 'YYYYMMDD') as Date1,
          TO_DATE('20130401', 'YYYYMMDD') as Date2
   from DUAL
), MONTHS_BTW as (
   select Date1, Date2,
          MONTHS_BETWEEN(Date2, Date1) as NumOfMonths
   from DATES
)
select TO_CHAR(Date1, 'MON DD YYYY') as Date_1,
       TO_CHAR(Date2, 'MON DD YYYY') as Date_2,
       NumOfMonths as Num_Of_Months,
       TRUNC(NumOfMonths) as "Month(s)",
       ADD_MONTHS(Date2, - TRUNC(NumOfMonths)) - Date1 as "Day(s)"
from MONTHS_BTW;

SQLFiddle演示:

    +--------------+--------------+-----------------+- ----------+--------+
    | DATE_1 | DATE_2 | NUM_OF_MONTHS | 月(S) | 天(S) |
    +--------------+--------------+-----------------+- ----------+--------+
    | 2012 年 1 月 1 日 | 2012 年 3 月 25 日 | 2.774193548387 | 2 | 24 |
    | 2012 年 1 月 1 日 | 2013 年 1 月 1 日 | 12 | 12 | 0 |
    | 2012 年 1 月 1 日 | 2012 年 1 月 1 日 | 0 | 0 | 0 |
    | 2013 年 2 月 28 日 | 2013 年 3 月 1 日 | 0.129032258065 | 0 | 1 |
    | 2013 年 2 月 28 日 | 2013 年 4 月 1 日 | 1.129032258065 | 1 | 1 |
    +--------------+--------------+-----------------+- ----------+--------+

请注意,对于最后两个日期,Oracle 如何错误地报告月份的小数部分(给出天数)。0.1290恰好对应于4Oracle 考虑31一个月中的天数(3 月和 4 月)的天数。

于 2013-08-14T11:12:12.530 回答
2

我认为您的问题定义得不够好,原因如下。

依赖于months_between的答案必须处理以下问题:该函数在2013-02-28和2013-03-31之间,2013-01-28和2013-02-28之间,以及2013-之间准确报告一个月01-31 和 2013-02-28(我怀疑有些回答者在实践中没有使用这些功能,或者现在将不得不审查一些生产代码!)

这是记录在案的行为,其中日期都是各自月份的最后一个日期或属于该月的同一天的日期被判断为相隔整数个月。

因此,将 2013-02-28 与 2013-01-28 或 2013-01-31 进行比较时,您会得到相同的“1”结果,但将其与 2013-01-29 或 2013-01-30 进行比较会得到 0.967741935484 和分别为 0.935483870968 - 因此当一个日期接近另一个日期时,此函数报告的差异可能会增加。

如果这不是可接受的情况,那么您将不得不编写一个更复杂的函数,或者仅依靠假设每月 30(例如)天的计算。在后一种情况下,您将如何处理 2013-02-28 和 2013-03-31?

于 2013-08-15T07:13:49.530 回答
1

这是你说的吗?

select trunc(months_between(To_date('20120325', 'YYYYMMDD'),to_date('20120101','YYYYMMDD'))) months,
             round(To_date('20120325', 'YYYYMMDD')-add_months(to_date('20120101','YYYYMMDD'),
                           trunc(months_between(To_date('20120325', 'YYYYMMDD'),to_date('20120101','YYYYMMDD'))))) days
        from dual;
于 2013-08-15T04:53:32.613 回答
1

这里我只是在做今天和CREATED_DATE DATE表中的一个字段之间的区别,这显然是过去的一个日期:

SELECT  
((FLOOR(ABS(MONTHS_BETWEEN(CREATED_DATE, SYSDATE))) / 12) * 12) || ' months, '  AS MONTHS,
-- we take total days - years(as days) - months(as days) to get remaining days
FLOOR((SYSDATE - CREATED_DATE) -      -- total days
(FLOOR((SYSDATE - CREATED_DATE)/365)*12)*(365/12) -      -- years, as days
-- this is total months - years (as months), to get number of months, 
-- then multiplied by 30.416667 to get months as days (and remove it from total days)
FLOOR(((SYSDATE - CREATED_DATE)/365)*12 - (FLOOR((SYSDATE - CREATED_DATE)/365)*12)) * (365/12))
|| ' days ' AS DAYS 
FROM MyTable

我使用 (365/12) 或 30.416667 作为我的转换因子,因为我使用总天数并删除年份和月份(天数)来获得剩余的天数。无论如何,这对我的目的来说已经足够了。

于 2016-12-08T00:24:19.573 回答
0

我发布的解决方案将考虑一个月 30 天

  select CONCAT (CONCAT (num_months,' MONTHS '), CONCAT ((days-(num_months)*30),' DAYS '))
  from ( 
  SELECT floor(Months_between(To_date('20120325', 'YYYYMMDD'),
   To_date('20120101', 'YYYYMMDD')))
   num_months,
   ( To_date('20120325', 'YYYYMMDD') - To_date('20120101', 'YYYYMMDD') )
   days
  FROM   dual);
于 2013-08-14T12:10:39.913 回答
-2

在 Orale Sql 中找出两天之间的年-月-日


select 
trunc(trunc(months_between(To_date('20120101', 'YYYYMMDD'),to_date('19910228','YYYYMMDD')))/12) years ,
trunc(months_between(To_date('20120101', 'YYYYMMDD'),to_date('19910228','YYYYMMDD'))) 
-
(trunc(trunc(months_between(To_date('20120101', 'YYYYMMDD'),to_date('19910228','YYYYMMDD')))/12))*12
months,
             round(To_date('20120101', 'YYYYMMDD')-add_months(to_date('19910228','YYYYMMDD'),
                           trunc(months_between(To_date('20120101', 'YYYYMMDD'),to_date('19910228','YYYYMMDD'))))) days
        from dual;
于 2013-09-17T05:28:40.713 回答
-3
SELECT   (MONTHS_BETWEEN(date2,date1) +  (datediff(day,date2,date1))/30) as num_months,
datediff(day,date2,date1) as diff_in_days  FROM  dual;

// You should replace date2 with TO_DATE('2012/03/25', 'YYYY/MM/DD')
// You should replace date1 with TO_DATE('2012/01/01', 'YYYY/MM/DD')
// To get you results
于 2012-07-16T09:34:47.350 回答
-4

请参阅下面的查询(假设 @dt1 >= @dt2);

Declare @dt1 datetime = '2013-7-3'
Declare @dt2 datetime = '2013-5-2'

select abs(DATEDIFF(DD, @dt2, @dt1)) Days,
case when @dt1 >= @dt2
    then case when DAY(@dt2)<=DAY(@dt1)
        then Convert(varchar, DATEDIFF(MONTH, @dt2, @dt1)) + CONVERT(varchar, ' Month(s) ') + Convert(varchar, DAY(@dt1)-DAY(@dt2)) + CONVERT(varchar, 'Day(s).')
        else Convert(varchar, DATEDIFF(MONTH, @dt2, @dt1)-1) + CONVERT(varchar, ' Month(s) ') + convert(varchar, abs(DATEDIFF(DD, @dt1, DateAdd(Month, -1, @dt1))) - (DAY(@dt2)-DAY(@dt1))) + CONVERT(varchar, 'Day(s).')
    end
    else 'See asumption: @dt1 must be >= @dt2'
end In_Months_Days

回报:

Days | In_Months_Days

62   |   2 Month(s) 1Day(s).
于 2013-08-13T21:23:33.080 回答