MySQLの日付間の月の差
-
08-07-2019 - |
質問
2つの日時フィールド間の月数を計算しようとしています。
UNIXタイムスタンプを取得し、2 592 000(秒)で割ってMySQLで切り上げるよりも良い方法はありますか?
解決
DATEDIFF 関数は、2つの日付間の日数を提供できます。どちらがより正確ですか?...月をどのように定義するのですか? (28、29、30、または31日?)
他のヒント
指定された2つの日付の月差:
これがまだ言及されていないことに驚いています:
<をご覧くださいstrong> TIMESTAMPDIFF() MySQLの関数。
これでできることは、2つの TIMESTAMP
または DATETIME
値(またはMySQLが自動変換する DATE
)を次のように渡すことです。差異の基準とする時間単位も含めてください。
最初のパラメーターの単位として 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
は、テーブル内の2つの日付列からのものでも、スクリプトからの入力パラメーターとしてのものでも、日付パラメーターです。
例:
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 2つの日付間の月を計算します。
たとえば、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月1日-&gt; 1月31日:全体で0か月、ほぼ1か月です。 1月1日-&gt; 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の答えは明らかに正確ですが、私の好みには冗長すぎます。
MySQLマニュアルから:
PERIOD_DIFF(P1、P2)
期間P1とP2の間の月数を返します。 P1とP2はYYMMまたはYYYYMMの形式である必要があります。期間引数P1およびP2は日付値ではないことに注意してください。
mysql&gt; SELECT PERIOD_DIFF(200802,200703); -&gt; 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()ステートメントを使用して、月が2ではなく02などの2桁の数字であることを確認する必要がありました。
もっと良い方法はありますか? はい。 MySQLタイムスタンプを使用しないでください。 36バイトを占有しているという事実は別として、それらは作業するのにまったく便利ではありません。 すべての日付/時刻の値には、真夜中からのユリウス日付と秒を使用することをお勧めします。 これらを組み合わせてUnixDateTimeを形成できます。これがDWORD(符号なし4バイト整数)に保存されている場合、1970年1月1日からepocまでの秒として2106までの日付を保存できます。 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
このコードを実行すると、日付形式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;
これは、月数をどのように定義するかによって異なります。この質問に答えてください:「月の違いは何ですか:2008年2月15日-2009年3月12日」。うるう年に依存する明確な日数で定義されていますか?それは何月ですか、または前月の同じ日= 1か月です。
日数の計算:
2月15日-&gt; 29(うるう年)= 14 2008年3月1日+ 365 = 2009年3月1日。 3月1日-&gt; 3月12日= 12日。 14 + 365 + 12 = 391日。 合計= 391日/(月の平均日数= 30)= 13.03333
月の計算:
2008年2月15日-2009年2月15日= 12 2月15日-&gt; 3月12日= 1か月未満 合計= 12か月、または2月15日-12月3日が「過去1か月」と見なされる場合は13
SELECT *
FROM emp_salaryrevise_view
WHERE curr_year Between '2008' AND '2009'
AND MNTH Between '12' AND '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
この方法で年、月、日を取得できます:
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'
単純に2つの日付を取り、その間の値を取得します。