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?
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?)
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.
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
)
Où 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
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;
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;
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;
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.
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.
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.
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.
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
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;
SELECT *
FROM emp_salaryrevise_view
WHERE curr_year Between '2008' AND '2009'
AND MNTH Between '12' AND '1'
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
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"
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;
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
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 :)))
Essaye ça
SELECT YEAR(end_date)*12 + MONTH(end_date) - (YEAR(start_date)*12 + MONTH(start_date))