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?
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:
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?)
PERIODDIFF
prende 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.
PERIODDIFF
commento? 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
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 TIMESTAMP
o DATETIME
valori (o anche DATE
come MySQL si convertirà automaticamente) così come l'unità di tempo su cui vuoi basare la tua differenza.
È possibile specificare MONTH
come 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ò.
È 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 startdate
e enddate
sono 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
PERIODDIFF
commento sulla risposta selezionata sono molto sbagliati
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;
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;
DATE_FORMAT
metodo, grazie! +1
SELECT PERIOD_DIFF(EXTRACT(YEAR_MONTH FROM NOW()), EXTRACT(YEAR_MONTH FROM FROM_UNIXTIME(time, "%Y%m%d"))) AS months FROM your_table;
PERIOD_DIFF
non 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.
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.
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.
Preferisco così, perché tutti lo capiranno chiaramente al primo sguardo:
SELECT
12 * (YEAR(to) - YEAR(from)) + (MONTH(to) - MONTH(from)) AS months
FROM
tab;
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.
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.
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
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;
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"
SELECT *
FROM emp_salaryrevise_view
WHERE curr_year Between '2008' AND '2009'
AND MNTH Between '12' AND '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
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
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;
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.