web-dev-qa-db-fra.com

Comparaison date/heure en golang

Existe-t-il des options pour comparer les dates à Golang? Je dois trier les données en fonction de la date et de l'heure - indépendamment. Je pourrais donc autoriser un objet qui se produit dans une plage de dates, à condition qu'il se produise également dans une plage de temps. Dans ce modèle, je ne pouvais pas simplement sélectionner la date la plus ancienne, la plus récente/la plus récente, la dernière heure et Unix () secondes pour les comparer. J'apprécierais vraiment toutes les suggestions.

En fin de compte, j’ai écrit un module de comparaison de chaîne d’analyse temporelle pour vérifier si une heure se situe dans une plage. Cependant, cela ne va pas très bien; J'ai des problèmes béants. Je posterai ça ici juste pour le plaisir, mais j'espère qu'il y a une meilleure façon de comparer les temps.

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
}

Donc, TLDR, j’ai écrit une fonction insideTimeRange (range, time) mais elle ne fonctionne pas tout à fait correctement. (En fait, la plupart du temps, il ne s'agit que du second cas, où une plage de temps croisée est fractionnée. La pièce d'origine fonctionnait, je venais juste de réaliser que je devais en tenir compte lorsque je procédais à des conversions de l'heure locale à UTC.)

S'il y a un meilleur moyen (de préférence intégré), j'aimerais en entendre parler!

NOTE: À titre d’exemple, j’ai résolu ce problème en Javascript avec cette fonction:

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;
}

Cependant, je veux vraiment faire ce filtre côté serveur.

63
eatonphil

Utilisez le paquet time pour travailler avec les informations de temps dans Go.

Jouer exemple:

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, ".")
    }
}
69
andybalholm

Pour comparaison entre deux fois, utilisez 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)

Le programme génère:

Lifespan is 3h0m0s

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

17
Charney Kaye

Pour les cas où votre intervalle se termine, il s'agit d'une date sans heures comme "Du 2017-01-01 au jour entier du 2017-01-16" il est préférable d'ajuster l'intervalle à 23 heures 59 minutes et 59 secondes, comme suit:

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) {
    ...
}
8
Oleg Neumyvakin

Des protocoles récents préfèrent utiliser RFC3339 pour la documentation du paquetage temporel golang

En général, RFC1123Z devrait être utilisé à la place de RFC1123 pour les serveurs qui insistent sur ce format, et RFC3339 devrait être préféré pour les nouveaux protocoles. RFC822, RFC822Z, RFC1123 et RFC1123Z sont utiles pour le formatage; lorsqu'ils sont utilisés avec time.Parse, ils n'acceptent pas tous les formats d'heure autorisés par les 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
deepakssn

Ce qui suit a résolu mon problème de conversion de chaîne en date 

paquet principal

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"

Merci à paul adam smith

0
suryakrupa