MySQLの日付間の月の違い


86

2つの日時フィールド間の月数を計算しようとしています。

UNIXタイムスタンプを取得して2592000(秒)で除算し、MySQLで切り上げるよりも良い方法はありますか?

回答:


16

DATEDIFFの機能を使用すると、2つの日付の間の日数を与えることができます。どちらがより正確ですか...月をどのように定義しますか?(28、29、30、または31日?)


68
PERIODDIFFは月数を正確に計算できます。
Max Caceres

10
「より正確」は、日付に関しては信じられないほど主観的です。たとえば、月次サイクルがあり、2つの日付の間の月数を知る必要があるビジネスの場合、上記の理由から、日数よりも重要になる可能性があります。月はどのくらいですか?私は月が必要な場合、私は単純に30で割ることはできませんカウント
トマス・ペイン

6
これは正解ではありません。以下で、マックスの答えを正解とマークする必要があります。
グラハムチャールズ

1
うるう年と1か月の日数の違いを正しく考慮して、月全体の数が必要な場合、Maxの答えは正しくありません。PERIODDIFF単純にYYYYMM値をとるので、YYYYMM値を渡す前に自分で日数を考慮しない限り、計算するのは月数だけで、整数未満の場合は最も近い月に切り上げられます。以下のゼーンの答えを参照してください。
rgvcorley 2014年

2
PERIODDIFFコメントに対する賛成票が非常に多いのはなぜですか?Perioddiffは日の値をとらないため、月の数が整数未満の場合は、最も近い月に切り上げられた月の数を計算します
rgvcorley 2014年

220

任意の2つの日付の月差:

これがまだ言及されていないことに驚いています:

MySQLのTIMESTAMPDIFF()関数を見てください。

これにより、2つ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
  )

テーブルの2つの日付列からのものか、スクリプトからの入力パラメーターとしてかを問わず、日付パラメーターはどこに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

8
これはPERIODDIFF正解です。選択した回答に対するコメントに対するすべての賛成票は非常に
誤解を

5
おかげで、私の場合は包括的日付が必要だったので、すべての「enddate」を「date_add(enddate、interval1day)」に置き換えます。その後、2014-03-01から2014-05-31は2.97ではなく3.00になります
Sven Tore

2
どうもありがとうございました.....「正確な月差:」に感謝します。あなたはmysqlのスターです
Vidhi 2015

1
同意しました。これが正解です。まさに私が探していたものです!ありがとう。
ジョン投票

105

PERIOD_DIFF、2つの日付の間の月を計算します。

たとえば、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か月のままでしょうか。
ダリル・ヘイン

1
上記の例では、11か月と1日で11か月が返されます。PERIOD_DIFFには、30日と31日の月の意味がありません。
Max Caceres

27

PERIODDIFFも使用しています。日付の年と月を取得するには、関数EXTRACTを使用します 。

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

2
信じられない!そのDATE_FORMAT方法の使用時間は50%少なくなります、ありがとう!+1
David Rodrigues

1
ここにUNIXタイムスタンプがあります SELECT PERIOD_DIFF(EXTRACT(YEAR_MONTH FROM NOW()), EXTRACT(YEAR_MONTH FROM FROM_UNIXTIME(time, "%Y%m%d"))) AS months FROM your_table;
Smolla 2012年

2
これは正しくPERIOD_DIFFなく、日の値をとらないため、月の数が整数未満の場合は、最も近い月に切り上げられた月の数を計算しています。これを明確にするために、回答を編集する必要があります。
rgvcorley 2014年

12

ここでの答えの多くが示すように、「正しい」答えはあなたが必要とするものに正確に依存します。私の場合、最も近い整数丸める必要があります。

次の例を検討してください。1月1日-> 1月31日:丸1か月で、ほぼ1か月です。1月1日-> 2月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年以上の範囲で正確です。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、1月から3月までの1か月(2月と呼ばれる)があります。TIMESTAMPDIFFは、日付間の完全な月数を示すだけです。月のサイズの期間を1か月に等しくしたい場合は、私が提供した丸められたバージョンを使用してください。
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のような2桁の数字であることを確認するために、if()ステートメントを使用する必要がありました。


8

evryoneは一目でそれを明確に理解するので、私はこの方法を好みます。

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

スタニスラフ-この方法は、月番号でデータを知りたい場合に最適です。月別(1月/ 2月/ 3月など)のレポートがいくつかありますが、データ(四半期/年/過去の年別のグラフなど)が多すぎて、何もグループ化できません。生データを取得してループする必要があります。1/ 31の場合、多くの計算では「来月」が2月であることがわかっている3月になります。2/ 4の場合、一部の計算では次のようになります。 1/31は「今月」ですが、1/28は「先月」でした
スコット

6

もっと良い方法はありますか?はい。MySQLタイムスタンプは使用しないでください。それらが36バイトを占めるという事実を除けば、それらは操作するのにまったく便利ではありません。すべての日付/時刻の値には、真夜中からのユリウス日と秒を使用することをお勧めします。これらを組み合わせてUnixDateTimeを形成できます。これがDWORD(符号なし4バイト整数)に格納されている場合、2106までの日付はepocからの秒数として格納できます。1970年1月1日DWORD最大値= 4,294,967,295-DWORDは136年の秒を保持できます

ユリウス日は、日付計算を行うときに非常に便利です。UNIXDateTime値は、日付/時刻計算を行うときに使用するのに適しています。どちらも見栄えがよくないため、あまり計算を行わない列が必要な場合は、タイムスタンプを使用します。と、しかし私は一目で表示したいです。

ジュリアンへの変換とその逆の変換は、優れた言語で非常に迅速に行うことができます。ポインターを使用すると、約900 Clksになります(これはもちろん、STRINGからINTEGERへの変換でもあります)

たとえば金融市場のような日付/時刻情報を使用する本格的なアプリケーションに入ると、ユリウス日は事実上です。


それらが36バイトを占めるという事実に関する情報はどこで入手しましたか?MySQLのマニュアルには、TIMESTAMP列のストレージ要件は4バイトであると記載されていますdev.mysql.com/doc/refman/5.1/en/storage-requirements.html
poncha

今すぐY2106バグの計画を始めましょう!;-)
ErichBSchulz 2013

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 2011

1

これは、月数をどのように定義するかによって異なります。この質問に答えてください:「月の違いは何ですか:2008年2月15日-2009年3月12日」。うるう年に応じた明確な日数で定義されていますか?それは何月ですか、それとも前月の同じ日= 1か月です。

日数の計算

2月15日-> 29(うるう年)= 14 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日= 12月15日-> 3月12日= 1か月未満合計= 12か月、または2月15日-3月12日が「先月」と見なされる場合は13



1

正確な月差が必要でした。Zane Bienの解決策は正しい方向にありますが、彼の2番目と3番目の例では不正確な結果が得られます。2月の日を2月の日数で割った値は、5月の日を5月の日数で割った値と同じではありません。したがって、2番目の例は((31-5 + 1)/ 31 + 13/30 =)1.3043を出力し、3番目の例は((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()関数

方法の1つは、MySQL PERIOD_DIFF()が2つの期間の差を返すことです。ピリオドは同じ形式、つまり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

-1

このクエリは私のために働いた:)

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

2つの日付を取得し、それらの間の値を取得するだけです。


完全に間違った答え、彼は月の数を望んでいます
シェーンロワット2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.