MySQL의 날짜 간의 월 차이


85

두 날짜 시간 필드 사이의 개월 수를 계산하려고합니다.

유닉스 타임 스탬프를 얻고 2 592 000 (초)로 나누고 MySQL을 반올림하는 것보다 더 좋은 방법이 있습니까?

답변:


16

DATEDIFF의 함수는 두 날짜 사이에 당신의 일 수를 제공 할 수 있습니다. 어느 쪽이 더 정확합니까? 왜냐하면 ... 한 달을 어떻게 정의합니까? (28 일, 29 일, 30 일 또는 31 일?)


68
PERIODDIFF 는 개월 수를 정확하게 계산할 수 있습니다.
Max Caceres

10
"더 정확하다"는 것은 날짜와 관련하여 믿을 수 없을 정도로 주관적입니다. 예를 들어, 두 날짜 사이에 몇 개월이 있는지 알아야하는 월간주기가있는 비즈니스에있는 경우 위에 배치 한 바로 그 이유 때문에 일 수보다 더 중요 할 수 있습니다. 한 달은 얼마나 걸리나요? 한 달이 필요하면 30으로 나눌 수 없습니다.
Thomas Paine 2013 년

6
이것은 정답이 아닙니다. 아래에 Max의 대답을 정답으로 표시해야 합니다.
Graham Charles

1
윤년과 한 달의 다른 일 수를 올바르게 고려하여 전체 개월 수를 원한다면 Max의 대답은 올바르지 않습니다. PERIODDIFF단순히 YYYYMM 값을 취하므로 YYYYMM 값을 전달하기 전에 직접 날짜를 고려하지 않는 한 계산하는 모든 것은 월 수이며, 전체 월 수가 적은 경우 가장 가까운 월로 반올림됩니다. 아래 Zane의 답변을 참조하십시오.
rgvcorley

2
PERIODDIFF댓글에 대한 찬성표가 많은 이유는 무엇 입니까? Perioddiff는 일 값을 사용하지 않으므로 전체 개월 수보다 적은 경우 가장 가까운 달로 반올림 한 개월 수를 계산합니다
rgvcorley

218

주어진 두 날짜 간의 월 차이 :

나는 이것이 아직 언급되지 않은 것에 놀랐다.

MySQL 의 TIMESTAMPDIFF () 함수를 살펴보십시오 .

이것이 당신이 할 수있는 것은 차이를 기반으로 할 시간 단위뿐만 아니라 두 개의 TIMESTAMP또는 DATETIME값 (또는 DATEMySQL이 자동 변환되는 것처럼)을 전달하는 것입니다.

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
  )

어디 startdateenddate날짜 매개 변수는 테이블 또는 스크립트에서 입력 매개 변수로 두 개의 날짜 열에서 수 있는지 여부입니다 :

예 :

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

8
이것은 모든 upvotes, 정답 PERIODDIFF선택한 답변에 댓글이 매우 미스를 선도하다
rgvcorley

5
감사합니다. 제 경우에는 포괄적 인 날짜가 필요했기 때문에 모든 "종료일"을 "date_add (enddate, interval 1 day)"로 바꿉니다. 그런 다음 2014-03-01에서 2014-05-31까지 2.97 대신 3.00을 제공합니다
Sven Tore 2014 년

2
정말 감사합니다 ..... "정확한 월 차이 :"에 대한 특별한 고맙습니다. 당신은 MySQL의의 스타입니다
Vidhi

1
동의합니다. 이것이 정답입니다. 내가 찾던 바로 그것! 감사.
Jon Vote

104

PERIOD_DIFF 는 두 날짜 사이의 월을 계산합니다.

예를 들어 now ()와 your_table의 시간 열 간의 차이를 계산하려면 다음을 수행하십시오.

select period_diff(date_format(now(), '%Y%m'), date_format(time, '%Y%m')) as months from your_table;

1
11 개월과 1 일이 될 때 어떤 일을하는지 아십니까? 12 개월이되지만 30 일로 변경하면 11 개월이 될 것입니다.
Darryl Hein

1
11 개월 1 일은 위의 예에서 11 개월을 반환합니다. PERIOD_DIFF는 30 일 대 31 일의 달이 아닙니다.
Max Caceres

26

나는 또한 PERIODDIFF를 사용합니다 . 날짜의 연도와 월을 얻으려면 EXTRACT 함수를 사용합니다 .

  SELECT PERIOD_DIFF(EXTRACT(YEAR_MONTH FROM NOW()), EXTRACT(YEAR_MONTH FROM time)) AS months FROM your_table;

2
놀랄 만한! 그 방법으로 50 % 더 적은 시간을 DATE_FORMAT사용합니다. 감사합니다! +1
David Rodrigues

1
여기에 유닉스 타임 스탬프가 있습니다 SELECT PERIOD_DIFF(EXTRACT(YEAR_MONTH FROM NOW()), EXTRACT(YEAR_MONTH FROM FROM_UNIXTIME(time, "%Y%m%d"))) AS months FROM your_table;
Smolla

2
이것은 정확 PERIOD_DIFF하지 않으며 일 값을 사용하지 않으므로 전체 월 수가 적을 경우 가장 가까운 월로 반올림 된 월 수를 계산합니다. 이를 명확하게하려면 답변을 편집해야합니다.
rgvcorley

12

여기에있는 많은 답변에서 알 수 있듯이 '정답'은 정확히 필요한 것에 따라 다릅니다. 제 경우 에는 가장 가까운 정수반올림 해야합니다 .

다음 예를 고려하십시오. 1 월 1 일-> 1 월 31 일 : 전체 0 개월, 거의 1 개월 길이입니다. 1 월 1 일-> 2 월 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 년 이상의 범위에 대해 정확합니다. Zane의 대답은 분명히 더 정확하지만 내 취향에 비해 너무 장황합니다.


동의하지 않습니다 ... SELECT TIMESTAMPDIFF (MONTH, '2018-01-31', '2018-02-04'); 0 개월 간격을 제공합니다 ... SELECT TIMESTAMPDIFF (MONTH, '2018-01-31', '2018-03-01'); 1을 준다 ... 5 일이 0이면 29 일은 1?
Scott

@Scott, 1 월과 3 월 사이에 한 달 (2 월이라고 함)이 있습니다. TIMESTAMPDIFF는 날짜 사이의 완전한 개월 수를 제공합니다. 월 단위 기간을 한 달과 동일하게하려면 내가 제공 한 반올림 버전을 사용하십시오.
IanS

8

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는 날짜 표현식입니다.

월이 2가 아닌 02와 같은 두 자리 숫자인지 확인하기 위해 if () 문을 사용해야했습니다.


8

evryone이 언뜻보기에 명확하게 이해할 것이기 때문에 저는이 방법을 선호합니다.

SELECT
    12 * (YEAR(to) - YEAR(from)) + (MONTH(to) - MONTH(from)) AS months
FROM
    tab;

Stanislav-월 번호로 데이터를 알고 싶다면이 방법이 정확히 맞습니다. 월별 (1 월 / 2 월 / 3 월 등) 매출을 보여주는 보고서가 있지만 데이터 (분기 / 연도 / 지난 연도 별 차트 등)가 너무 많아서 아무것도 그룹화 할 수 없습니다. 원시 데이터를 가져 와서 반복해야합니다. 1/31 일 때 많은 계산에서 "다음 달"이 2 월이라는 것을 우리가 알고있는 3 월에 넣습니다. 2/4이면 일부 계산에 따르면 1/31은 "이번 달"이지만 1/28은 "지난 달"입니다
Scott은

6

더 좋은 방법이 있습니까? 예. MySQL 타임 스탬프를 사용하지 마십시오. 36 바이트를 차지한다는 사실을 제외하고는 작업하기에 전혀 편리하지 않습니다. 모든 날짜 / 시간 값에 대해 자정부터 Julian Date 및 Seconds를 사용하는 것이 좋습니다. 이들을 결합하여 UnixDateTime을 형성 할 수 있습니다. 이것이 DWORD (부호없는 4 바이트 정수)에 저장되면 epoc, 01/01/1970 DWORD max val = 4,294,967,295-DWORD는 136 년의 초를 저장할 수 있습니다.

Julian Dates는 날짜 계산을 할 때 사용하기에 매우 좋습니다. UNIXDateTime 값은 날짜 / 시간 계산을 할 때 사용하기에 좋습니다. 둘 다보기에는 좋지 않으므로 많은 계산을 수행하지 않을 열이 필요할 때 Timestamps를 사용합니다. 하지만 한눈에 표시하고 싶습니다.

줄리안으로 변환했다가 되 돌리는 것은 좋은 언어로 매우 빠르게 수행 할 수 있습니다. 포인터를 사용하면 약 900 Clks까지 내려갑니다 (물론 STRING에서 INTEGER 로의 변환이기도합니다).

예를 들어 금융 시장과 같은 날짜 / 시간 정보를 사용하는 심각한 애플리케이션에 들어가면 율리우스 력 날짜는 사실상 사실입니다.


36 바이트를 차지한다는 사실 에 대한 정보는 어디서 얻었 습니까? MySQL 설명서에는 TIMESTAMP 열에 대한 스토리지 요구 사항이 4 바이트라고 나와 있습니다. dev.mysql.com/doc/refman/5.1/en/storage-requirements.html
poncha

지금 Y2106 버그에 대한 계획을 시작하십시오! ;-)
ErichBSchulz

5

쿼리는 다음과 같습니다.

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

고객 레코드에 생성 된 날짜 스탬프 이후 달력 월 수를 제공하여 MySQL이 내부적으로 월을 선택할 수 있도록합니다.


2
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

2

이 코드를 실행하면 날짜 형식 yyyy-mm-dd의 차이를 제공하는 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;

1
좀 더 이해할 수 있도록 코드를 정리하고 주석을 달 수 있다고 생각하십니까? 감사합니다
Darryl Hein

1

이것은 정의 할 개월 수에 따라 다릅니다. '달의 차이는 무엇입니까 : 2008 년 2 월 15 일-2009 년 3 월 12 일'질문에 답하십시오. 윤년에 따라 달라지는 명확한 일 수로 정의됩니까-월이 무엇입니까, 아니면 전월의 같은 날 = 1 개월입니까?

일에 대한 계산 :

2 월 15 일-> 29 일 (윤년) = 2008 년 3 월 1 일 + 365 = 2009 년 3 월 1 일. 3 월 1 일-> 3 월 12 일 = 12 일. 14 + 365 + 12 = 391 일. 합계 = 391 일 / (월 평균 일수 = 30) = 13.03333

월 계산 :

2008 년 2 월 15 일-2009 년 2 월 15 일 = 2 월 15 일-> 3 월 12 일 = 1 개월 미만 합계 = 12 개월 또는 2 월 15 일-3 월 12 일이 '지난 달'로 간주되는 경우 13


1
SELECT * 
FROM emp_salaryrevise_view 
WHERE curr_year Between '2008' AND '2009' 
    AND MNTH Between '12' AND '1'

1

나는 정확한 월 차이가 필요했습니다. Zane Bien의 솔루션은 올바른 방향이지만 그의 두 번째 및 세 번째 예는 부정확 한 결과를 제공합니다. 2 월의 하루를 2 월의 일 수로 나눈 값은 5 월의 하루를 5 월의 일 수로 나눈 값과 같지 않습니다. 따라서 두 번째 예는 ((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

1

PERIOD_DIFF () 함수

방법 중 하나는 MySQL PERIOD_DIFF ()가 두 기간의 차이를 반환하는 것입니다. 마침표는 YYYYMM 또는 YYMM과 같은 동일한 형식이어야합니다. 기간은 날짜 값이 아닙니다.

암호:

SELECT PERIOD_DIFF(200905,200811);

여기에 이미지 설명 입력


0

이 방법으로 년, 월, 일을 얻을 수 있습니다.

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

0

다음을 시도해 볼 수도 있습니다.

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;

0

시작 날짜를 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

즐겨 :)))


0

이 시도

SELECT YEAR(end_date)*12 + MONTH(end_date) - (YEAR(start_date)*12 + MONTH(start_date))

Stack Overflow에 오신 것을 환영합니다! 질문의 날짜와 기존 답변에 동일한 솔루션이 있는지 확인하십시오.
lehiester 19-04-25

-1

이 쿼리는 저에게 효과적이었습니다.)

SELECT * FROM tbl_purchase_receipt
WHERE purchase_date BETWEEN '2008-09-09' AND '2009-09-09'

두 개의 날짜를 취하고 그 사이의 값을 검색합니다.


완전히 잘못된 대답은, 그 달의 수는 원
셰인 Rowatt
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.