Разница в месяцах между датами в MySQL - PullRequest
67 голосов
/ 14 ноября 2008

Я рассчитываю количество месяцев между двумя полями даты и времени.

Есть ли лучший способ, чем получить метку времени Unix и делить на 2 592 000 (секунд) и округлить в пределах MySQL?

Ответы [ 20 ]

179 голосов
/ 30 июля 2012

Разница в месяце между любыми данными двумя датами:

Я удивлен, что это еще не было упомянуто:

Посмотрите на функцию TIMESTAMPDIFF () в MySQL.

Это позволяет вам передавать два значения TIMESTAMP или DATETIME (или даже 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

Обычно получает количество месяцев, прошедших с первой даты в списке параметров. Это решение автоматически компенсирует различное количество дней в каждом месяце (28,30,31), а также учитывает високосные годы & mdash; вам не нужно беспокоиться ни о чем из этого.


Разница в месяц с точностью:

Это немного сложнее, если вы хотите ввести десятичную точность в количестве прошедших месяцев, но вот как вы можете это сделать:

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
  )

Где startdate и enddate - ваши параметры даты, будь то из двух столбцов даты в таблице или как входные параметры из скрипта:

Примеры:

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
100 голосов
/ 18 февраля 2009

PERIOD_DIFF вычисляет месяцы между двумя датами.

Например, чтобы вычислить разницу между now () и столбцом времени в your_table:

select period_diff(date_format(now(), '%Y%m'), date_format(time, '%Y%m')) as months from your_table;
24 голосов
/ 01 марта 2011

Я также использую PERIODDIFF . Чтобы получить год и месяц даты, я использую функцию EXTRACT :

  SELECT PERIOD_DIFF(EXTRACT(YEAR_MONTH FROM NOW()), EXTRACT(YEAR_MONTH FROM time)) AS months FROM your_table;
18 голосов
/ 14 ноября 2008

Функция DATEDIFF может указывать количество дней между двумя датами. Что является более точным, поскольку ... как вы определяете месяц? (28, 29, 30 или 31 день?)

8 голосов
/ 20 августа 2010

Я предпочитаю этот путь, потому что evryone это поймет с первого взгляда:

SELECT
    12 * (YEAR(to) - YEAR(from)) + (MONTH(to) - MONTH(from)) AS months
FROM
    tab;
8 голосов
/ 22 февраля 2018

Как показывают многие ответы здесь, «правильный» ответ зависит именно от того, что вам нужно. В моем случае мне нужно округлить до ближайшего целого числа .

Рассмотрим эти примеры: 1 января -> 31 января: 0 целых месяцев и почти 1 месяц. 1 января -> 1 февраля? Это 1 целый месяц и ровно 1 месяц.

Чтобы получить число целых (полных) месяцев, используйте:

SELECT TIMESTAMPDIFF(MONTH, '2018-01-01', '2018-01-31');  => 0
SELECT TIMESTAMPDIFF(MONTH, '2018-01-01', '2018-02-01');  => 1

Чтобы получить округленную продолжительность в месяцах, вы можете использовать:

SELECT ROUND(TIMESTAMPDIFF(DAY, '2018-01-01', '2018-01-31')*12/365.24); => 1
SELECT ROUND(TIMESTAMPDIFF(DAY, '2018-01-01', '2018-01-31')*12/365.24); => 1

Это с точностью до +/- 5 дней и для диапазонов свыше 1000 лет. Ответ Зейна, очевидно, более точный, но он мне слишком многословен.

7 голосов
/ 14 ноября 2008

Из руководства MySQL:

PERIOD_DIFF (P1, P2)

Возвращает количество месяцев между периодами P1 и P2. P1 и P2 должны быть в формате YYMM или YYYYMM. Обратите внимание, что аргументы периода P1 и P2 не являются значениями даты.

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 - выражения даты.

Мне пришлось использовать оператор if (), чтобы убедиться, что месяцы представляют собой двузначное число, например, 02, а не 2.

6 голосов
/ 27 января 2009

Есть ли лучший способ? да. Не используйте метки времени MySQL. Помимо того, что они занимают 36 байт, с ними совсем не удобно работать. Я бы порекомендовал использовать юлианские даты и секунды с полуночи для всех значений даты / времени. Они могут быть объединены, чтобы сформировать UnixDateTime. Если это сохранено в DWORD (4-байтовое целое число без знака), то даты вплоть до 2106 могут быть сохранены как секунды с момента epoc, 01.01.1970 DWORD max val = 4 294 967 295 - DWORD может содержать 136 лет секунд

Юлианские даты очень удобны при расчете дат Значения UNIXDateTime хороши для работы при расчете даты / времени Ни на что не годятся, поэтому я использую метки времени, когда мне нужен столбец, с которым я не буду много вычислять, но мне нужна краткая индикация.

Преобразование в юлианский и обратно может быть сделано очень быстро на хорошем языке. С помощью указателей у меня это примерно до 900 кликов (это тоже преобразование из STRING в INTEGER)

Когда вы попадаете в серьезные приложения, которые используют информацию о дате / времени, например, о финансовых рынках, юлианские даты де-факто.

5 голосов
/ 09 сентября 2009

Запрос будет выглядеть так:

select period_diff(date_format(now(),"%Y%m"),date_format(created,"%Y%m")) from customers where..

Предоставляет количество календарных месяцев с момента создания метки даты в записи клиента, позволяя MySQL самостоятельно выбирать месяц.

2 голосов
/ 25 июля 2011

Выполните этот код, и он создаст функцию datedeifference, которая даст вам разницу в формате даты гггг-мм-дд.

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;
...