42

我想计算两个日期之间的月数。

正在做 :

SELECT TIMESTAMP '2012-06-13 10:38:40' - TIMESTAMP '2011-04-30 14:38:40';

返回:0 年 0 月 409 天 20 小时 0 分钟 0.00 秒

所以:

SELECT extract(month from TIMESTAMP '2012-06-13 10:38:40' - TIMESTAMP '2011-04-30 14:38:40');

返回 0。

4

12 回答 12

56

age函数返回区间:

age(timestamp1, timestamp2)

然后我们尝试从区间中提取年份和月份并相应地添加它们:

select extract(year from age(timestamp1, timestamp2)) * 12 +
extract(month from age(timestamp1, timestamp2))
于 2014-10-09T12:30:21.570 回答
19

age函数给出了一个合理的间隔来使用:

SELECT age(TIMESTAMP '2012-06-13 10:38:40', TIMESTAMP '2011-04-30 14:38:40');

返回1 year 1 mon 12 days 20:00:00,然后您可以轻松地使用它EXTRACT来计算月数:

SELECT EXTRACT(YEAR FROM age) * 12 + EXTRACT(MONTH FROM age) AS months_between
FROM age(TIMESTAMP '2012-06-13 10:38:40', TIMESTAMP '2011-04-30 14:38:40') AS t(age);
于 2014-02-17T02:31:43.970 回答
12

请注意,当您尝试使用日历月差时, @ ram和@angelin投票最多的答案并不准确。

select extract(year from age(timestamp1, timestamp2))*12 + extract(month from age(timestamp1, timestamp2))

例如,如果您尝试这样做:

select extract(year from age('2018-02-02'::date, '2018-03-01'::date))*12 + extract(month from age('2018-02-02'::date , '2018-03-01'::date))

结果将为 0,但从 3 月到 2 月之间的月份,无论日期之间的天数如何,都应为 1。

所以公式应该像下面这样说我们从timestamp1和timestamp2开始:

((year2 - year1)*12) - month1 + month2 = 两个时间戳之间的日历月

在 pg 中将被翻译为:

select ((extract('years' from '2018-03-01 00:00:00'::timestamp)::int -  extract('years' from '2018-02-02 00:00:00'::timestamp)::int) * 12) 
    - extract('month' from '2018-02-02 00:00:00'::timestamp)::int + extract('month' from '2018-03-01 00:00:00'::timestamp)::int;

您可以创建如下函数:

CREATE FUNCTION months_between (t_start timestamp, t_end timestamp)
RETURNS integer
AS $$
select ((extract('years' from $2)::int -  extract('years' from $1)::int) * 12) 
    - extract('month' from $1)::int + extract('month' from $2)::int
$$
LANGUAGE SQL
IMMUTABLE
RETURNS NULL ON NULL INPUT;
于 2018-08-20T10:25:01.487 回答
8

如果要多次执行此操作,则可以定义以下函数

CREATE FUNCTION months_between (t_start timestamp, t_end timestamp)
    RETURNS integer
    AS $$
        SELECT
            (
                12 * extract('years' from a.i) + extract('months' from a.i)
            )::integer
        from (
            values (justify_interval($2 - $1))
        ) as a (i)
    $$
    LANGUAGE SQL
    IMMUTABLE
    RETURNS NULL ON NULL INPUT;

这样你就可以

SELECT months_between('2015-01-01', now());
于 2015-07-07T08:32:50.963 回答
4
SELECT date_part ('year', f) * 12
      + date_part ('month', f)
FROM age ('2015-06-12', '2014-12-01') f

结果:6个月

于 2015-06-12T18:25:47.803 回答
2

给出两个日期的月差

   SELECT ((extract( year FROM TIMESTAMP '2012-06-13 10:38:40' ) - extract( year FROM TIMESTAMP '2011-04-30 14:38:40' )) *12) + extract(MONTH FROM TIMESTAMP '2012-06-13 10:38:40' ) - extract(MONTH FROM TIMESTAMP '2011-04-30 14:38:40' );

结果:14

必须分别提取两个日期的月份,然后提取两个结果的差异

于 2012-06-13T10:25:42.100 回答
1

我曾经有过同样的问题并写了这个......它很丑陋:

postgres=>  SELECT floor((extract(EPOCH FROM TIMESTAMP '2012-06-13 10:38:40' ) - extract(EPOCH FROM TIMESTAMP '2005-04-30 14:38:40' ))/30.43/24/3600);
 floor 
-------
    85
(1 row)

在此解决方案中,“一个月”被定义为 30.43 天,因此它可能会在较短的时间跨度内产生一些意想不到的结果。

于 2012-06-13T10:32:26.417 回答
1

按年和月提取将按月计算:

select extract(year from age('2016-11-30'::timestamp, '2015-10-15'::timestamp)); --> 1
select extract(month from age('2016-11-30'::timestamp, '2015-10-15'::timestamp)); --> 1
--> Total 13 months

这种方法可以维持几个月的分数(感谢 tobixen 的除数)

select round(('2016-11-30'::date - '2015-10-15'::date)::numeric /30.43, 1); --> 13.5 months
于 2019-03-11T18:00:37.187 回答
0

试试这个解决方案:

SELECT extract (MONTH FROM age('2014-03-03 00:00:00'::timestamp, 
'2013-02-03 00:00:00'::timestamp)) + 12 * extract (YEAR FROM age('2014-03-03   
00:00:00'::timestamp, '2013-02-03 00:00:00'::timestamp)) as age_in_month;
于 2014-02-16T02:00:18.440 回答
0
SELECT floor(extract(days from TIMESTAMP '2012-06-13 10:38:40' - TIMESTAMP
'2011-04-30 14:38:40')/30.43)::integer as months;

给出一个近似值,但避免重复时间戳。这使用了来自tobixen 的答案的提示,即除以 30.43 代替 30,以便在计算月份时长时间跨度不那么不正确。

于 2017-03-24T08:47:35.053 回答
0

我做了一个这样的函数:

/* similar to ORACLE's MONTHS_BETWEEN */
CREATE OR REPLACE FUNCTION ORACLE_MONTHS_BETWEEN(date_from DATE, date_to DATE)
RETURNS REAL LANGUAGE plpgsql
AS
$$
DECLARE age INTERVAL;
declare rtn real;
BEGIN
    age := age(date_from, date_to);
    rtn := date_part('year', age) * 12 + date_part('month', age) + date_part('day', age)/31::real;
    return rtn;
END;
$$;

甲骨文示例)

SELECT MONTHS_BETWEEN
(TO_DATE('2015-02-02','YYYY-MM-DD'), TO_DATE('2014-12-01','YYYY-MM-DD') ) 
"Months" FROM DUAL;
--result is: 2.03225806451612903225806451612903225806

我的 PostgreSQL 函数示例)

select ORACLE_MONTHS_BETWEEN('2015-02-02'::date, '2014-12-01'::date) Months;
-- result is: 2.032258

根据结果​​,您可以使用 CEIL()/FLOOR() 进行舍入。

select ceil(2.032258)  --3
select floor(2.032258) --2
于 2021-03-02T22:08:35.563 回答
-2

尝试;

select extract(month from  age('2012-06-13 10:38:40'::timestamp, '2011-04-30 14:38:40'::timestamp)) as my_months; 
于 2012-08-13T22:01:53.463 回答