Come eseguire il confronto data / ora


98

Ci sono opzioni per fare il confronto delle date in Go? Devo ordinare i dati in base a data e ora, in modo indipendente. Quindi potrei consentire un oggetto che si verifica in un intervallo di date purché si presenti anche in un intervallo di volte. In questo modello, non potevo semplicemente selezionare la data più vecchia, l'ora più giovane / la data più recente, l'ora più recente e i secondi Unix () per confrontarli. Apprezzerei davvero qualsiasi suggerimento.

Alla fine, ho scritto un modulo di confronto della stringa di analisi del tempo per verificare se un tempo rientra in un intervallo. Tuttavia, questo non sta andando bene; Ho alcuni problemi a bocca aperta. Lo posterò qui solo per divertimento, ma spero che ci sia un modo migliore per confrontare il tempo.

package main

import (
    "strconv"
    "strings"
)

func tryIndex(arr []string, index int, def string) string {
    if index <= len(arr)-1 {
        return arr[index]
    }
    return def
}

/*
 * Takes two strings of format "hh:mm:ss" and compares them.
 * Takes a function to compare individual sections (split by ":").
 * Note: strings can actually be formatted like "h", "hh", "hh:m",
 * "hh:mm", etc. Any missing parts will be added lazily.
 */
func timeCompare(a, b string, compare func(int, int) (bool, bool)) bool {
    aArr := strings.Split(a, ":")
    bArr := strings.Split(b, ":")
    // Catches margins.
    if (b == a) {
        return true
    }
    for i := range aArr {
        aI, _ := strconv.Atoi(tryIndex(aArr, i, "00"))
        bI, _ := strconv.Atoi(tryIndex(bArr, i, "00"))
        res, flag := compare(aI, bI)
        if res {
            return true
        } else if flag { // Needed to catch case where a > b and a is the lower limit
            return false
        }
    }
    return false
}

func timeGreaterEqual(a, b int) (bool, bool) {return a > b, a < b}
func timeLesserEqual(a, b int) (bool, bool) {return a < b, a > b}

/*
 * Returns true for two strings formmated "hh:mm:ss".
 * Note: strings can actually be formatted like "h", "hh", "hh:m",
 * "hh:mm", etc. Any missing parts will be added lazily.
 */
func withinTime(timeRange, time string) bool {
    rArr := strings.Split(timeRange, "-")
    if timeCompare(rArr[0], rArr[1], timeLesserEqual) {
        afterStart := timeCompare(rArr[0], time, timeLesserEqual)
        beforeEnd := timeCompare(rArr[1], time, timeGreaterEqual)
        return afterStart && beforeEnd
    }
    // Catch things like `timeRange := "22:00:00-04:59:59"` which will happen
    // with UTC conversions from local time.
    // THIS IS THE BROKEN PART I BELIEVE
    afterStart := timeCompare(rArr[0], time, timeLesserEqual)
    beforeEnd := timeCompare(rArr[1], time, timeGreaterEqual)
    return afterStart || beforeEnd
}

Quindi TLDR, ho scritto una funzione withinTimeRange (range, time) ma non funziona del tutto correttamente. (In effetti, per lo più solo il secondo caso, in cui un intervallo di tempo attraversa i giorni è interrotto. La parte originale ha funzionato, ho appena capito che avrei dovuto tenerne conto quando effettuavo conversioni a UTC da locale.)

Se c'è un modo migliore (preferibilmente integrato), mi piacerebbe saperne di più!

NOTA: solo come esempio, ho risolto questo problema in Javascript con questa funzione:

function withinTime(start, end, time) {
    var s = Date.parse("01/01/2011 "+start);
    var e = Date.parse("01/0"+(end=="24:00:00"?"2":"1")+"/2011 "+(end=="24:00:00"?"00:00:00":end));
    var t = Date.parse("01/01/2011 "+time);
    return s <= t && e >= t;
}

Tuttavia, voglio davvero fare questo filtro lato server.

Risposte:


110

Usa il pacchetto orario per lavorare con le informazioni sull'ora in Go.

Gli istanti di tempo possono essere confrontati utilizzando i metodi Prima, Dopo e Uguale. Il metodo Sub sottrae due istanti, producendo una Durata. Il metodo Add aggiunge un Time e una Duration, producendo un Time.

Esempio di gioco :

package main

import (
    "fmt"
    "time"
)

func inTimeSpan(start, end, check time.Time) bool {
    return check.After(start) && check.Before(end)
}

func main() {
    start, _ := time.Parse(time.RFC822, "01 Jan 15 10:00 UTC")
    end, _ := time.Parse(time.RFC822, "01 Jan 16 10:00 UTC")

    in, _ := time.Parse(time.RFC822, "01 Jan 15 20:00 UTC")
    out, _ := time.Parse(time.RFC822, "01 Jan 17 10:00 UTC")

    if inTimeSpan(start, end, in) {
        fmt.Println(in, "is between", start, "and", end, ".")
    }

    if !inTimeSpan(start, end, out) {
        fmt.Println(out, "is not between", start, "and", end, ".")
    }
}

Forse non so leggere, ma non ho visto niente sui confronti temporali. Se è lì, potresti indicarmi un articolo esatto?
eatonphil

12
Prova godoc.org/time#Time.Equal o godoc.org/time#Time.After per un semplice confronto, o godoc.org/time#Time.Sub per scoprire la differenza tra due tempi.
andybalholm

1
"segnala se l'istante di tempo t è dopo u." inquietante
Damien Roche

22

Per il confronto tra due volte utilizzare time.Sub ()

// utc life
loc, _ := time.LoadLocation("UTC")

// setup a start and end time
createdAt := time.Now().In(loc).Add(1 * time.Hour)
expiresAt := time.Now().In(loc).Add(4 * time.Hour)

// get the diff
diff := expiresAt.Sub(createdAt)
fmt.Printf("Lifespan is %+v", diff)

Il programma produce:

Lifespan is 3h0m0s

http://play.golang.org/p/bbxeTtd4L6


Questa è la migliore risposta.
MithunS

15

Per i casi in cui l'intervallo finisce è la data senza ore come "dal 01/01/2017 all'intero giorno del 16/01/2017", è meglio regolare l'intervallo su 23 ore, 59 minuti e 59 secondi come:

end = end.Add(time.Duration(23*time.Hour) + time.Duration(59*time.Minute) + time.Duration(59*time.Second)) 

if now.After(start) && now.Before(end) {
    ...
}

1
Esattamente quello di cui avevo bisogno per confrontare un TimeStamp memorizzato con l'ora corrente.
PGP_Protector

1

I protocolli recenti preferiscono l'utilizzo di RFC3339 per la documentazione del pacchetto temporale .

In generale, RFC1123Z dovrebbe essere utilizzato al posto di RFC1123 per i server che insistono su quel formato e RFC3339 dovrebbe essere preferito per i nuovi protocolli. RFC822, RFC822Z, RFC1123 e RFC1123Z sono utili per la formattazione; quando vengono utilizzati con time.Parse non accettano tutti i formati di ora consentiti dalle RFC.

cutOffTime, _ := time.Parse(time.RFC3339, "2017-08-30T13:35:00Z")
// POSTDATE is a date time field in DB (datastore)
query := datastore.NewQuery("db").Filter("POSTDATE >=", cutOffTime).

-1

Quanto segue ha risolto il mio problema di convertire la stringa in data

pacchetto principale

import (
    "fmt"
    "time"
)

func main() {
    value  := "Thu, 05/19/11, 10:47PM"
    // Writing down the way the standard time would look like formatted our way
    layout := "Mon, 01/02/06, 03:04PM"
    t, _ := time.Parse(layout, value)
    fmt.Println(t)
}

// => "Thu May 19 22:47:00 +0000 2011"

Grazie a paul adam smith


1
È tutto carino ma non ha molto a che fare con la domanda, deos?
matthias krull,

Hai ragione @matthiaskrull. Non risponde alla domanda sul confronto delle date, ma aiuta parzialmente ad analizzare le date con facilità.
suryakrupa

Quindi fai questo e un paio di altri. Sto solo dicendo che collegare qualcosa nei commenti sarebbe più adatto che rispondere con bit utili casuali.
matthias krull
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.