web-dev-qa-db-fra.com

La différence de mois entre les dates dans MySQL

Je cherche à calculer le nombre de mois entre 2 champs de date et heure.

Existe-t-il un meilleur moyen que d’obtenir l’horodatage Unix et de diviser par 2 592 000 (secondes) et d’arrondir dans MySQL?

63
Darryl Hein

La fonction DATEIFF peut vous donner le nombre de jours entre deux dates. Qu'est-ce qui est plus précis, puisque ... comment définissez-vous un mois? (28, 29, 30 ou 31 jours?)

18
SoapBox

Mois-différence entre deux dates données:

Je suis surpris que cela n'ait pas encore été mentionné:

Examinez la fonction TIMESTAMPDIFF () dans MySQL.

Cela vous permet de transmettre deux valeurs TIMESTAMP ou DATETIME (ou même DATE car MySQL convertira automatiquement), ainsi que l'unité de temps sur laquelle vous souhaitez baser votre différence.

Vous pouvez spécifier MONTH comme unité dans le premier paramètre:

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

En gros, il indique le nombre de mois écoulés depuis la première date de la liste de paramètres. Cette solution compense automatiquement le nombre de jours variable chaque mois (28,30,31) et tient compte des années bissextiles - vous n'avez pas à vous soucier de cela.


Mois-différence avec précision:

C'est un peu plus compliqué si vous souhaitez introduire une précision décimale dans le nombre de mois écoulés, mais voici comment vous pouvez le faire:

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 et enddate sont vos paramètres de date, que ce soit à partir de deux colonnes de date dans une table ou en tant que paramètres d'entrée à partir d'un script:

Exemples:

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
169
Zane Bien

PERIOD_DIFF calcule les mois entre deux dates.

Par exemple, pour calculer la différence entre now () et une colonne time dans votre_table:

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

J'utilise aussi PERIODDIFF . Pour obtenir l'année et le mois de la date, j'utilise la fonction EXTRACT :

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

Je préfère cette façon, parce que tout le monde comprendra au premier abord:

SELECT
    12 * (YEAR(to) - YEAR(from)) + (MONTH(to) - MONTH(from)) AS months
FROM
    tab;
8
Stanislav Basovník

Du manuel MySQL:

PERIOD_DIFF (P1, P2)

Renvoie le nombre de mois entre les périodes P1 et P2. P1 et P2 doivent être au format AAMM ou AAAAMM. Notez que les arguments de période P1 et P2 ne sont pas des valeurs de date.

mysql> SELECT PERIOD_DIFF (200802,200703); -> 11

Donc, il peut être possible de faire quelque chose comme ceci:

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;

Où d1 et d2 sont les expressions de date.

Je devais utiliser les déclarations if () pour m'assurer que les mois étaient composés de deux chiffres comme 02 plutôt que 2. 

7
Vincent Ramdhanie

Comme le montrent de nombreuses réponses, la «bonne» réponse dépend de ce dont vous avez besoin. Dans mon cas, j'ai besoin de arrondir au nombre entier le plus proche.

Considérez ces exemples: 1er janvier -> 31 janvier: 0 mois entier et presque un mois . 1er janvier -> 1er février? C'est 1 mois entier, et exactement 1 mois.

Pour obtenir le nombre de entier (complet) mois, utilisez:

SELECT TIMESTAMPDIFF(MONTH, '2018-01-01', '2018-01-31');  => 0
SELECT TIMESTAMPDIFF(MONTH, '2018-01-01', '2018-02-01');  => 1

Pour obtenir une durée arrondie en mois, vous pouvez utiliser:

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

Ceci est précis à +/- 5 jours et pour des intervalles supérieurs à 1000 ans. La réponse de Zane est évidemment plus précise, mais elle est trop verbeuse à mon goût.

7
IanS

Y a-t-il un meilleur moyen? Oui. N'utilisez pas les horodatages MySQL. Mis à part le fait qu’ils occupent 36 octets, il n’est pas du tout pratique de travailler avec. Je recommanderais d’utiliser Julian Date et Seconds à partir de minuit pour toutes les valeurs de date/heure . Celles-ci peuvent être combinées pour former un UnixDateTime. Si ceci est stocké dans un DWORD (entier non signé de 4 octets), les dates jusqu'à 2106 peuvent être stockées en secondes depuis epoc, 01/01/1970 DWORD max val = 4 294 967 295 - Un DWORD peut contenir 136 Secondes 

Les dates juliennes sont très agréables à utiliser pour les calculs de date Les valeurs UNIXDateTime sont utiles pour les calculs de date/heure Ni sont bonnes à regarder, donc j'utilise les horodatages quand j'ai besoin d'une colonne que je ne fera pas beaucoup de calculs avec, mais je veux une indication en un coup d’œil.

La conversion en julien et vice versa peut se faire très rapidement dans une bonne langue. En utilisant des pointeurs, je l’ai jusqu’à 900 Clks environ (c’est aussi une conversion de STRING en INTEGER)

Lorsque vous entrez dans des applications sérieuses qui utilisent des informations de date/heure telles que, par exemple, les marchés financiers, les dates en Julien sont de facto.

6
Mike Trader

La requête sera comme:

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

Donne un certain nombre de mois de calendrier depuis la date de création sur une fiche client, laissant ainsi MySQL sélectionner le mois en interne. 

5
Mike Harrison
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
Rama

Exécutez ce code et cela créera une fonction datéifference qui vous donnera la différence de format de date aaaa-mm-jj.

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;
2
enor
SELECT * 
FROM emp_salaryrevise_view 
WHERE curr_year Between '2008' AND '2009' 
    AND MNTH Between '12' AND '1'
1
JAVED

J'avais besoin de différence de mois avec précision. Bien que la solution de Zane Bien va dans la bonne direction, ses deuxième et troisième exemples donnent des résultats inexacts. Un jour de février divisé par le nombre de jours de février n'est pas égal à un jour de mai divisé par le nombre de jours de mai. Ainsi, le deuxième exemple devrait produire ((31-5 + 1)/31 + 13/30 =) 1,3043 et le troisième exemple ((29-27 + 1)/29 + 2/30 + 3 =) 3.1701. 

J'ai fini avec la requête suivante:

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
Michel Mix

Cela dépend de la manière dont vous souhaitez définir le nombre de mois. Répondez à ces questions: «Quelle est la différence en mois: 15 février 2008 - 12 mars 2009». Est-ce défini par un nombre de jours bien défini qui dépend des années bissextiles, de quel mois il s’agit ou du même jour du mois précédent = 1 mois.

Un calcul pour les jours :

15 février -> 29 (année bissextile) = 14 1er mars 2008 + 365 = 1 mars 2009 . 1er mars -> 12 mars = 12 jours ..__ 14, 365 + 12 = 391 jours . Total = 391 jours/(jours moyens dans le mois = 30) = 13.03333

Un calcul de mois

15 fév 2008 - 15 fév 2009 = 12 15 févr. -> 12 mars = moins d'un moisTotal = 12 mois, ou 13 si 15 févr. - 12 mars est considéré comme "le mois dernier" 

1
Klathzazt

Fonction PERIOD_DIFF ()

MySQL PERIOD_DIFF () renvoie notamment la différence entre deux périodes. Les périodes doivent être au même format, c'est-à-dire AAAAMM ou AAMM. Il est à noter que les périodes ne sont pas des valeurs de date.

Code:

SELECT PERIOD_DIFF(200905,200811);

 enter image description here

0
Amitesh

Vous pouvez aussi essayer ceci:

select MONTH(NOW())-MONTH(table_date) as 'Total Month Difference' from table_name;

OR

select MONTH(Newer_date)-MONTH(Older_date) as 'Total Month Difference' from table_Name;
0
Shubham Verma

Vous pouvez obtenir des années, des mois et des jours de cette façon:

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
Artur Kędzior

Réponse simple avec la date de début ins_frm et la date de fin 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

Prendre plaisir :)))

0
Mo Kassab

Essaye ça

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