I giorni in un mese dipende dalla data, proprio come il giorni in un anno (anni bisestili).
Se si utilizza time.Since()
per ottenere il tempo trascorso da quando un valore time.Time
, o quando si calcola la differenza tra i 2 time.Time
valori utilizzando il metodo Time.Sub()
, il risultato è un time.Duration
che perde il contesto di tempo (come Duration
è solo il tempo differenza in nanosecondi). Ciò significa che non è possibile calcolare in modo preciso e senza ambiguità la differenza in anni, mesi, ecc. Da un valore Duration
.
La soluzione giusta deve calcolare la differenza nel contesto del tempo. È possibile calcolare la differenza per ogni campo (anno, mese, giorno, ora, minuto, secondo), quindi normalizzare il risultato per non avere valori negativi. Si consiglia inoltre di scambiare i valori Time
se la relazione tra di essi non è quella prevista.
Normalizzazione significa che se un valore è negativo, aggiungere il valore massimo di quel campo e decrementare il campo successivo di 1. Per esempio, se seconds
è negativo, aggiungere 60
ad esso e decrementare minutes
di 1. Una cosa da guardare fuori per è quando si normalizza la differenza di giorni (giorni in mese), deve essere applicato il numero di giorni nel mese corretto. Questo può essere facilmente calcolato con questo piccolo trucco:
// Max days in year y1, month M1
t := time.Date(y1, M1, 32, 0, 0, 0, 0, time.UTC)
daysInMonth := 32 - t.Day()
La logica alla base di questo è che il giorno 32
è più grande rispetto al giorno massimo in qualsiasi mese. Si normalizzerà automaticamente (i giorni in più verranno spostati al mese successivo e il giorno decrementato correttamente). E quando sottraiamo il giorno che abbiamo dopo la normalizzazione a 32, otteniamo esattamente quello che era l'ultimo giorno del mese.
Tempo manipolazione orario:
Il calcolo differenza sarà solo dà risultato corretto se entrambi i valori temporali Passiamo sono nello stesso fuso orario (time.Location
).Incorporiamo un controllo nel nostro funzione: se questo non è il caso, noi "Convert" uno del valore di tempo per essere nella stessa posizione come l'altro utilizzando il metodo Time.In()
:
if a.Location() != b.Location() {
b = b.In(a.Location())
}
ecco una soluzione che calcola la differenza in anno, mese, giorno, ora, minuti, secondi:
func diff(a, b time.Time) (year, month, day, hour, min, sec int) {
if a.Location() != b.Location() {
b = b.In(a.Location())
}
if a.After(b) {
a, b = b, a
}
y1, M1, d1 := a.Date()
y2, M2, d2 := b.Date()
h1, m1, s1 := a.Clock()
h2, m2, s2 := b.Clock()
year = int(y2 - y1)
month = int(M2 - M1)
day = int(d2 - d1)
hour = int(h2 - h1)
min = int(m2 - m1)
sec = int(s2 - s1)
// Normalize negative values
if sec < 0 {
sec += 60
min--
}
if min < 0 {
min += 60
hour--
}
if hour < 0 {
hour += 24
day--
}
if day < 0 {
// days in month:
t := time.Date(y1, M1, 32, 0, 0, 0, 0, time.UTC)
day += 32 - t.Day()
month--
}
if month < 0 {
month += 12
year--
}
return
}
Alcuni test:
var a, b time.Time
a = time.Date(2015, 5, 1, 0, 0, 0, 0, time.UTC)
b = time.Date(2016, 6, 2, 1, 1, 1, 1, time.UTC)
fmt.Println(diff(a, b)) // Expected: 1 1 1 1 1 1
a = time.Date(2016, 1, 2, 0, 0, 0, 0, time.UTC)
b = time.Date(2016, 2, 1, 0, 0, 0, 0, time.UTC)
fmt.Println(diff(a, b)) // Expected: 0 0 30 0 0 0
a = time.Date(2016, 2, 2, 0, 0, 0, 0, time.UTC)
b = time.Date(2016, 3, 1, 0, 0, 0, 0, time.UTC)
fmt.Println(diff(a, b)) // Expected: 0 0 28 0 0 0
a = time.Date(2015, 2, 11, 0, 0, 0, 0, time.UTC)
b = time.Date(2016, 1, 12, 0, 0, 0, 0, time.UTC)
fmt.Println(diff(a, b)) // Expected: 0 11 1 0 0 0
uscita è come ex pected:
1 1 1 1 1 1
0 0 30 0 0 0
0 0 28 0 0 0
0 11 1 0 0 0
Prova sul Go Playground.
Per calcolare quanti anni hai: uscita
// Your birthday: let's say it's January 2nd, 1980, 3:30 AM
birthday := time.Date(1980, 1, 2, 3, 30, 0, 0, time.UTC)
year, month, day, hour, min, sec := diff(birthday, time.Now())
fmt.Printf("You are %d years, %d months, %d days, %d hours, %d mins and %d seconds old.",
year, month, day, hour, min, sec)
Esempio:
You are 36 years, 3 months, 8 days, 11 hours, 57 mins and 41 seconds old.
La data/ora di magia in cui inizia il tempo di un parco giochi Go è: 2009-11-10 23:00:00 UTC
Questo è il momento in cui Go fu annunciato per la prima volta. Calcoliamo quanto vecchio Go è:
goAnnounced := time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC)
year, month, day, hour, min, sec := diff(goAnnounced, time.Now())
fmt.Printf("Go was announced "+
"%d years, %d months, %d days, %d hours, %d mins and %d seconds ago.",
year, month, day, hour, min, sec)
uscita:
Go was announced 6 years, 4 months, 29 days, 16 hours, 53 mins and 31 seconds ago.
Come precisa l'avete bisogno di essere? Imprecise relative timestamp renderebbe un po 'più semplice – T0xicCode
Preferirei che fosse preciso al secondo – gempir
@ T0xicCode potrebbe darmi la soluzione che è meno precisa? Forse posso migliorarlo in qualche modo – gempir