Разница в месяцах между датами в MySQL
-
08-07-2019 - |
Вопрос
Я хочу рассчитать количество месяцев между двумя полями даты и времени.
Есть ли лучший способ, чем получить временную метку Unix, разделить ее на 2 592 000 (секунд) и округлить в большую сторону в MySQL?
Решение
DATEDIFF Функция может дать вам количество дней между двумя датами. Что более точно, так как ... как вы определяете месяц? (28, 29, 30 или 31 день?)
Другие советы
Разница в месяцах между любыми двумя датами:
Я удивлен, что об этом еще не упомянули:
Взгляните на ТАЙМСТАМПДИФФ() функция в 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), а также учитывает високосные годы — вам не нужно беспокоиться ни о чем из этого.
Разница в месяце с точностью:
Это немного сложнее, если вы хотите ввести десятичную точность в количестве прошедших месяцев, но вот как это можно сделать:
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
PERIOD_DIFF рассчитывает месяцы между двумя датами.
Например, чтобы вычислить разницу между now () и временным столбцом в your_table:
select period_diff(date_format(now(), '%Y%m'), date_format(time, '%Y%m')) as months from your_table;
Я также использую PERIODDIFF . Чтобы получить год и месяц даты, я использую функцию ВЫПИСКА :
SELECT PERIOD_DIFF(EXTRACT(YEAR_MONTH FROM NOW()), EXTRACT(YEAR_MONTH FROM time)) AS months FROM your_table;
Я предпочитаю этот путь, потому что каждый на первый взгляд это поймет:
SELECT
12 * (YEAR(to) - YEAR(from)) + (MONTH(to) - MONTH(from)) AS months
FROM
tab;
Как показывают многие ответы здесь, «правильный» ответ зависит именно от того, что вам нужно. В моем случае мне нужно округлить до ближайшего целого числа .
Рассмотрим эти примеры: 1 января - > 31 января: 0 целых месяцев и почти 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 лет. Ответ Зейна, очевидно, более точный, но он мне слишком многословен.
Из руководства MySQL:
PERIOD_DIFF(P1,P2)
Возвращает количество месяцев между периодами P1 и P2.P1 и P2 должны быть в формате ГГММ или ГГГГММ.Обратите внимание, что аргументы периода 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.
Есть ли лучший способ? да. Не используйте метки времени MySQL. Помимо того, что они занимают 36 байт, с ними совсем не удобно работать. Я бы порекомендовал использовать юлианские даты и секунды с полуночи для всех значений даты / времени. Они могут быть объединены, чтобы сформировать UnixDateTime. Если это сохранено в DWORD (4-байтовое целое число без знака), то даты вплоть до 2106 могут быть сохранены как секунды с момента epoc, 01.01.1970 DWORD max val = 4 294 967 295 - DWORD может содержать 136 лет секунд
Юлианские даты очень удобны при расчете дат Значения UNIXDateTime хороши для работы при расчете даты / времени Ни на что не годятся, поэтому я использую метки времени, когда мне нужен столбец, с которым я не буду много вычислять, но мне нужна быстрая индикация.
Преобразование в юлианский и обратно может быть выполнено очень быстро на хорошем языке. С помощью указателей у меня это примерно до 900 кликов (это тоже, конечно, преобразование из STRING в INTEGER)
Когда вы попадаете в серьезные приложения, которые используют информацию о дате / времени, например, финансовые рынки, юлианские даты де-факто.
Запрос будет выглядеть так:
select period_diff(date_format(now(),"%Y%m"),date_format(created,"%Y%m")) from customers where..
Предоставляет количество календарных месяцев с момента создания метки даты в записи клиента, что позволяет MySQL самостоятельно выбирать месяц. Р>
DROP FUNCTION IF EXISTS `calcula_edad` $
CREATE DEFINER=`root`@`localhost` FUNCTION `calcula_edad`(pFecha1 date, pFecha2 date, pTipo char(1)) RETURNS int(11)
Begin
Declare vMeses int;
Declare vEdad int;
Set vMeses = period_diff( date_format( pFecha1, '%Y%m' ), date_format( pFecha2, '%Y%m' ) ) ;
/* Si el dia de la fecha1 es menor al dia de fecha2, restar 1 mes */
if day(pFecha1) < day(pFecha2) then
Set vMeses = VMeses - 1;
end if;
if pTipo='A' then
Set vEdad = vMeses div 12 ;
else
Set vEdad = vMeses ;
end if ;
Return vEdad;
End
select calcula_edad(curdate(),born_date,'M') -- for number of months between 2 dates
Выполните этот код, и он создаст функцию 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;
Это зависит от того, как вы хотите определить количество месяцев. Ответьте на следующие вопросы: «Какая разница в месяцах: 15 февраля 2008 г. - 12 марта 2009 г.». Определяется ли оно четким числом # дней, которое зависит от високосных лет - какой это месяц или тот же день предыдущего месяца = 1 месяц.
Расчет для дней .
15 февраля - > 29 (високосный год) = 14 1 марта 2008 г. + 365 = 1 марта 2009 г. 1 марта - > 12 марта = 12 дней. 14 + 365 + 12 = 391 день. Итого = 391 день / (среднее число дней в месяце = 30) = 13,03333
Расчет месяцев .
15 февраля 2008 г. - 15 февраля 2009 г. = 12 15 февраля - > 12 марта = менее 1 месяца Итого = 12 месяцев или 13, если 15 февраля - 12 марта считается «прошедшим месяцем»
SELECT *
FROM emp_salaryrevise_view
WHERE curr_year Between '2008' AND '2009'
AND MNTH Between '12' AND '1'
Мне нужна была разница в месяц с точностью. Хотя решение Зейна Бина идет в правильном направлении, его второй и третий примеры дают неточные результаты. День в феврале, деленный на количество дней в феврале, не равен дню в мае, деленному на число дней в мае. Таким образом, второй пример должен вывести ((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
Вы можете получить годы, месяцы и дни следующим образом:
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
Вы также можете попробовать это:
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;
Простой ответ с указанием начальной даты в виде 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
Наслаждайтесь:)))
Попробуйте это
SELECT YEAR(end_date)*12 + MONTH(end_date) - (YEAR(start_date)*12 + MONTH(start_date))
Этот запрос работал для меня:)
SELECT * FROM tbl_purchase_receipt
WHERE purchase_date BETWEEN '2008-09-09' AND '2009-09-09'
Он просто берет две даты и получает значения между ними.