La differenza in mesi tra le date in MySQL


86

Sto cercando di calcolare il numero di mesi tra 2 campi di data e ora.

Esiste un modo migliore per ottenere il timestamp unix e la divisione per 2 592 000 (secondi) e arrotondare per eccesso all'interno di MySQL?

Risposte:


16

La funzione DATEDIFF può fornire il numero di giorni tra due date. Quale è più preciso, dal momento che ... come definisci un mese? (28, 29, 30 o 31 giorni?)


68
PERIODDIFF può calcolare con precisione il numero di mesi.
Max Caceres

10
"Più accurato" è una soggettiva incredibile quando si tratta di date. Se, ad esempio, sei in un'azienda che ha cicli mensili, la necessità di sapere quanti mesi sono tra due date può essere più importante del numero di giorni proprio per il motivo che hai esposto sopra. Quanto dura un mese? Se ho bisogno di contare un mese non posso semplicemente dividere per 30.
Thomas Paine

6
Questa non è la risposta corretta; dovresti contrassegnare la risposta di Max come corretta, di seguito.
Graham Charles

1
La risposta di Max non è corretta se si desidera il numero di mesi interi, tenendo conto correttamente degli anni bisestili e del diverso numero di giorni in un mese. PERIODDIFFprende semplicemente un valore AAAAMM, quindi a meno che tu non tenga conto dei giorni prima di passare i valori AAAAMM, tutto ciò che stai calcolando è il numero di mesi, arrotondato per eccesso al mese più vicino se c'è meno di un numero intero di mesi. Vedi la risposta di Zane di seguito.
rgvcorley

2
Perché ci sono così tanti voti positivi per il PERIODDIFFcommento? Perioddiff non accetta valori giornalieri, quindi stai calcolando il numero di mesi arrotondato al mese più vicino se c'è meno di un numero intero di mesi
rgvcorley

220

Differenza di mese tra due date date:

Sono sorpreso che questo non sia stato ancora menzionato:

Dai un'occhiata alla funzione TIMESTAMPDIFF () in MySQL.

Ciò che questo ti permette di fare è passare in due TIMESTAMPo DATETIMEvalori (o anche DATEcome MySQL si convertirà automaticamente) così come l'unità di tempo su cui vuoi basare la tua differenza.

È possibile specificare MONTHcome unità nel primo parametro:

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

Fondamentalmente ottiene il numero di mesi trascorsi dalla prima data nell'elenco dei parametri. Questa soluzione compensa automaticamente la quantità variabile di giorni in ogni mese (28,30,31) e tiene conto degli anni bisestili: non devi preoccuparti di nulla di tutto ciò.


Differenza di mese con precisione:

È un po 'più complicato se vuoi introdurre la precisione decimale nel numero di mesi trascorsi, ma ecco come puoi farlo:

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
  )

Dove startdatee enddatesono i parametri della data, sia che si tratti di due colonne di data in una tabella o come parametri di input di uno script:

Esempi:

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
Questa è la risposta corretta, tutti i voti positivi per il PERIODDIFFcommento sulla risposta selezionata sono molto sbagliati
rgvcorley

5
Grazie, nel mio caso avevo bisogno di date inclusive, quindi sostituisco tutte le "enddate" con "date_add (enddate, interval 1 day)". Quindi il 01/03/2014 al 31/05/2014 darà 3.00 invece di 2.97
Sven Tore

2
Grazie mille ..... un ringraziamento speciale per "Differenza di mese con precisione:". Sei la star di mysql
Vidhi

1
Concordato. Questa è la risposta corretta. Esattamente quello che stavo cercando! Grazie.
Jon votare il

105

PERIOD_DIFF calcola i mesi tra due date.

Ad esempio, per calcolare la differenza tra now () e una colonna time in your_table:

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

1
Qualche idea su cosa fa quando potrebbe essere di 11 mesi e 1 giorno, quindi 12 mesi, ma se passi a mesi di 30 giorni, sarebbero ancora 11?
Darryl Hein

1
11 mesi e 1 giorno restituiranno 11 mesi con l'esempio precedente. PERIOD_DIFF non ha senso di 30 contro 31 giorni mesi.
Max Caceres

27

Uso anche PERIODDIFF . Per ottenere l'anno e il mese della data, utilizzo la funzione ESTRATTA :

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

2
Incredibile! Usa il 50% in meno di tempo rispetto a quel DATE_FORMATmetodo, grazie! +1
David Rodrigues

1
Qui per un timestamp 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

2
Questo non è corretto, PERIOD_DIFFnon accetta valori giornalieri, quindi stai calcolando il numero di mesi arrotondato per eccesso al mese più vicino se c'è meno di un numero intero di mesi. Dovresti modificare la tua risposta per renderlo chiaro.
rgvcorley

12

Come molte delle risposte qui dimostrano, la risposta "giusta" dipende esattamente da ciò di cui hai bisogno. Nel mio caso, devo arrotondare al numero intero più vicino .

Considera questi esempi: 1 gennaio -> 31 gennaio: sono 0 mesi interi e quasi 1 mese. 1 gennaio -> 1 febbraio? È 1 mese intero e esattamente 1 mese.

Per ottenere il numero di mesi interi (completi) , utilizzare:

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

Per ottenere una durata arrotondata in mesi, puoi utilizzare:

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

È accurato fino a +/- 5 giorni e per intervalli superiori a 1000 anni. La risposta di Zane è ovviamente più accurata, ma è troppo prolissa per i miei gusti.


Non sono d'accordo ... SELEZIONA TIMESTAMPDIFF (MESE, '2018-01-31', '2018-02-04'); ti concede 0 mesi di distanza ... SELECT TIMESTAMPDIFF (MONTH, '2018-01-31', '2018-03-01'); ti dà 1 ... se 5 giorni è 0, 29 giorni è 1?
Scott

@Scott, c'è un intero mese (chiamato febbraio) tra gennaio e marzo. TIMESTAMPDIFF fornisce solo il numero di mesi completi tra le date. Se vuoi che un periodo delle dimensioni di un mese sia uguale a un mese, usa la versione arrotondata che ho fornito.
IanS

8

Dal manuale MySQL:

PERIOD_DIFF (P1, P2)

Restituisce il numero di mesi tra i periodi P1 e P2. P1 e P2 devono essere nel formato YYMM o YYYYMM. Notare che gli argomenti del periodo P1 e P2 non sono valori di data.

mysql> SELEZIONA PERIODO_DIFF (200802,200703); -> 11

Quindi potrebbe essere possibile fare qualcosa del genere:

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;

Dove d1 e d2 sono le espressioni di data.

Ho dovuto usare le istruzioni if ​​() per assicurarmi che i mesi fossero un numero di due cifre come 02 anziché 2.


8

Preferisco così, perché tutti lo capiranno chiaramente al primo sguardo:

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

Stanislav: questo metodo è esattamente corretto se vuoi conoscere i dati PER NUMERO MESE. Ho alcuni rapporti che mostrano le vendite per mese (gennaio / febbraio / marzo ecc.) Ma ci sono così tanti dati (grafici per trimestre / anno / anni passati ecc.) Che non posso raggruppare per nulla. Devo inserire i dati grezzi e scorrere i dati - quando è 1/31, molti dei calcoli mettono il "mese prossimo" a marzo quando noi umani sappiamo che è febbraio. SE è 2/4, alcuni calcoli dicono che 1/31 è "questo mese" ma 1/28 è stato "il mese scorso"
Scott

6

Esiste un modo migliore? sì. Non utilizzare i timestamp MySQL. A parte il fatto che occupano 36 byte, non è affatto conveniente lavorarci. Consiglio di utilizzare Julian Date e Seconds from mezzanotte per tutti i valori di data / ora. Questi possono essere combinati per formare un UnixDateTime. Se questo è memorizzato in un DWORD (numero intero di 4 byte senza segno), le date fino a 2106 possono essere memorizzate come secondi da epoc, 01/01/1970 DWORD max val = 4,294,967,295 - Un DWORD può contenere 136 anni di secondi

È molto bello lavorare con le date Julian quando si effettuano calcoli di data I valori UNIXDateTime sono buoni con cui lavorare quando si effettuano calcoli di data / ora Né sono buoni da guardare, quindi uso i timestamp quando ho bisogno di una colonna che non farò molti calcoli con, ma voglio un'indicazione a colpo d'occhio.

La conversione in Giuliano e ritorno può essere eseguita molto rapidamente in una buona lingua. Usando i puntatori lo ho fino a circa 900 Clks (questa è anche una conversione da STRING a INTEGER ovviamente)

Quando entri in applicazioni serie che utilizzano informazioni su data / ora come ad esempio i mercati finanziari, le date giuliane sono di fatto.


Dove hai preso le informazioni sul fatto che occupano 36 byte ? Il manuale MySQL afferma che il requisito di archiviazione per la colonna TIMESTAMP è di 4 byte . dev.mysql.com/doc/refman/5.1/en/storage-requirements.html
poncha

inizia subito a pianificare il bug Y2106! ;-)
ErichBSchulz

5

La query sarà come:

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

Fornisce un numero di mesi di calendario a partire dal datestamp creato su un record del cliente, consentendo a MySQL di selezionare internamente il mese.


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

Esegui questo codice e creerà una funzione dateifference che ti darà la differenza nel formato della data aaaa-mm-gg.

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
Pensi che potresti ripulire e commentare un po 'il tuo codice in modo che sia un po' più comprensibile? Grazie
Darryl Hein

1

Dipende da come si desidera definire il numero di mesi. Rispondi a queste domande: "Qual è la differenza in mesi: 15 febbraio 2008 - 12 marzo 2009". È definito da un chiaro numero di giorni che dipende dagli anni bisestili: di che mese si tratta o lo stesso giorno del mese precedente = 1 mese.

Un calcolo per giorni :

15 febbraio -> 29 (anno bisestile) = 14 1 marzo 2008 + 365 = 1 marzo 2009. 1 marzo -> 12 marzo = 12 giorni. 14 + 365 + 12 = 391 giorni. Totale = 391 giorni / (giorni medi nel mese = 30) = 13,03333

Un calcolo di mesi :

15 febbraio 2008 - 15 febbraio 2009 = 12 15 febbraio -> 12 marzo = meno di 1 mese Totale = 12 mesi, o 13 se 15 febbraio - 12 marzo è considerato "il mese passato"


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

1

Avevo bisogno di un mese di differenza con precisione. Sebbene la soluzione di Zane Bien vada nella giusta direzione, il suo secondo e terzo esempio danno risultati imprecisi. Un giorno di febbraio diviso per il numero di giorni di febbraio non è uguale a un giorno di maggio diviso per il numero di giorni di maggio. Quindi il secondo esempio dovrebbe restituire ((31-5 + 1) / 31 + 13/30 =) 1.3043 e il terzo esempio ((29-27 + 1) / 29 + 2/30 + 3 =) 3.1701.

Ho finito con la seguente domanda:

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

Funzione PERIOD_DIFF ()

Uno dei modi è MySQL PERIOD_DIFF () restituisce la differenza tra due punti. I periodi devono essere nello stesso formato, ovvero AAAAMM o AAMM. È da notare che i periodi non sono valori di data.

Codice:

SELECT PERIOD_DIFF(200905,200811);

inserisci qui la descrizione dell'immagine


0

Puoi ottenere anni, mesi e giorni in questo modo:

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

Puoi anche provare questo:

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

O

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

0

Risposta semplice data la data di inizio come ins_frm e la data di fine come 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

Godere :)))


0

Prova questo

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

Benvenuto in Stack Overflow! Assicurati di controllare la data sulle domande e se le risposte esistenti hanno la stessa soluzione.
Lehiester

-1

Questa query ha funzionato per me :)

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

Richiede semplicemente due date e recupera i valori tra di loro.


risposta totalmente errata, vuole un conteggio dei mesi
Shane Rowatt
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.