Я хочу рассчитать количество месяцев между двумя полями даты и времени.
Есть ли лучший способ, чем получить временную метку unix и разделить на 2 592 000 (секунд) и округлить в MySQL?
Я хочу рассчитать количество месяцев между двумя полями даты и времени.
Есть ли лучший способ, чем получить временную метку unix и разделить на 2 592 000 (секунд) и округлить в MySQL?
Ответы:
Функция РАЗНДАТ (РАЗНДАТ) может дать вам количество дней между двумя датами. Что более точно, поскольку ... как вы определяете месяц? (28, 29, 30 или 31 день?)
PERIODDIFF
просто принимает значение ГГГГММ, поэтому, если вы сами не учитываете дни перед передачей значений ГГГГММ, тогда все, что вы вычисляете, - это количество месяцев, округленное до ближайшего месяца, если число месяцев меньше целого. См. Ответ Зейна ниже.
PERIODDIFF
комментарий так много положительных отзывов ? Perioddiff не принимает значения дня, поэтому вы вычисляете количество месяцев с округлением до ближайшего месяца, если число месяцев меньше целого
Я удивлен, что об этом еще не упомянули:
Взгляните на функцию 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), а также учитывает високосные годы - вам не нужно беспокоиться ни о чем из этого.
Это немного сложнее, если вы хотите ввести десятичную точность в количество прошедших месяцев, но вот как вы можете это сделать:
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
PERIODDIFF
комментарий к выбранному ответу очень
PERIOD_DIFF вычисляет месяцы между двумя датами.
Например, чтобы вычислить разницу между now () и столбцом времени в your_table:
select period_diff(date_format(now(), '%Y%m'), date_format(time, '%Y%m')) as months from your_table;
Использую также PERIODDIFF . Чтобы получить год и месяц даты, я использую функцию EXTRACT :
SELECT PERIOD_DIFF(EXTRACT(YEAR_MONTH FROM NOW()), EXTRACT(YEAR_MONTH FROM time)) AS months FROM your_table;
DATE_FORMAT
метод использует на 50% меньше времени , спасибо! +1
SELECT PERIOD_DIFF(EXTRACT(YEAR_MONTH FROM NOW()), EXTRACT(YEAR_MONTH FROM FROM_UNIXTIME(time, "%Y%m%d"))) AS months FROM your_table;
PERIOD_DIFF
не принимает значения дня, поэтому вы вычисляете количество месяцев с округлением до ближайшего месяца, если количество месяцев меньше целого. Вы должны отредактировать свой ответ, чтобы прояснить это.
Как показывают многие из приведенных здесь ответов, «правильный» ответ зависит от того, что именно вам нужно. В моем случае мне нужно округлить до ближайшего целого числа .
Рассмотрим эти примеры: 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 должны быть в формате YYMM или YYYYMM. Обратите внимание, что аргументы периода P1 и P2 не являются значениями даты.
mysql> ВЫБРАТЬ 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.
Я предпочитаю этот способ, потому что все это ясно поймет с первого взгляда:
SELECT
12 * (YEAR(to) - YEAR(from)) + (MONTH(to) - MONTH(from)) AS months
FROM
tab;
Есть ли способ лучше? да. Не используйте метки времени MySQL. Кроме того, что они занимают 36 байт, работать с ними совсем не удобно. Я бы рекомендовал использовать юлианские даты и секунды с полуночи для всех значений даты и времени. Их можно объединить в UnixDateTime. Если это сохранено в DWORD (беззнаковое 4-байтовое целое число), тогда даты вплоть до 2106 могут быть сохранены в секундах с момента epoc, 01.01.1970 DWORD max val = 4,294,967,295 - DWORD может содержать 136 лет секунд
Юлианские даты очень удобны для работы при вычислении даты. Значения UNIXDateTime удобны для работы при вычислении даты и времени. На них также не стоит смотреть, поэтому я использую временные метки, когда мне нужен столбец, который я не буду выполнять много вычислений. с, но мне нужна краткая информация.
Преобразование в юлианский и обратно может быть выполнено очень быстро на хорошем языке. Используя указатели, у меня это примерно до 900 Clks (это также преобразование из 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, которая даст вам разницу в формате даты yyyy-mm-dd.
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 марта 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;
Этот запрос сработал для меня :)
SELECT * FROM tbl_purchase_receipt
WHERE purchase_date BETWEEN '2008-09-09' AND '2009-09-09'
Он просто берет две даты и извлекает значения между ними.