Tarih / saat karşılaştırması nasıl yapılır


102

Go'da tarih karşılaştırması yapmak için herhangi bir seçenek var mı? Verileri tarih ve saate göre - bağımsız olarak sıralamak zorundayım. Bu nedenle, bir zaman aralığı içinde de meydana geldiği sürece, bir tarih aralığı içinde oluşan bir nesneye izin verebilirim. Bu modelde, en eski tarihi, en genç saati / en son tarihi, en son saati ve Unix () saniyeleri karşılaştırmakla yetinemezdim. Herhangi bir öneriyi gerçekten takdir ediyorum.

Sonuçta, bir zamanın bir aralık içinde olup olmadığını kontrol etmek için bir zaman ayrıştırma dizesi karşılaştırma modülü yazdım. Ancak, bu pek de uzak değil; Bazı boşluk sorunlarım var. Bunu sadece eğlence için buraya göndereceğim, ama umarım zaman karşılaştırması yapmanın daha iyi bir yolu vardır.

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
}

Bu yüzden TLDR, bir insideTimeRange (aralık, zaman) işlevi yazdım, ancak tam olarak doğru çalışmıyor. (Aslında, çoğunlukla bir zaman aralığının günler boyunca kesiştiği ikinci durumdur. Orijinal parça işe yaradı, yerelden UTC'ye dönüştürme yaparken bunu hesaba katmam gerektiğini fark ettim.)

Daha iyi (tercihen yerleşik) bir yol varsa, bunu duymak isterim!

NOT: Örnek olarak, bu sorunu Javascript'te şu fonksiyonla çözdüm:

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

Ancak bu filtreyi sunucu tarafında gerçekten yapmak istiyorum.

Yanıtlar:


117

Go'da zaman bilgileriyle çalışmak için zaman paketini kullanın .

Zaman anları Before, After ve Equal yöntemleri kullanılarak karşılaştırılabilir. Sub yöntemi, bir Süre üreterek iki anı çıkarır. Add yöntemi, Time ve Duration ekleyerek bir Time oluşturur.

Örnek oyna :

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

2
Belki okuyamıyorum ama orada zaman karşılaştırmaları hakkında hiçbir şey görmedim. Eğer oradaysa, beni tam bir makaleye yönlendirebilir misin?
eatonphil

12
Deneyin godoc.org/time#Time.Equal veya godoc.org/time#Time.After basit karşılaştırma için veya godoc.org/time#Time.Sub iki zaman arasındaki farkı bulmak için.
andybalholm

1
"t zamanının u'dan sonra olup olmadığını bildirir." ürkütücü
Damien Roche

25

İçin iki kat arasında karşılaştırma kullanımı ) (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)

Programın çıktısı:

Lifespan is 3h0m0s

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


2
Bu en iyi cevap.
MithunS

15

Aralığınızın sonu "2017-01-01'den 2017-01-16'nın tam gününe" gibi saat içermeyen bir tarih olduğunda, aralığı 23 saat 59 dakika 59 saniyeye ayarlamak daha iyidir. Örneğin:

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
Depolanan bir TimeStamp'ı Geçerli Saat ile karşılaştırmak için tam olarak ihtiyacım olan şey.
PGP_Protector

1

Son protokoller her golang zamanı paketi dokümantasyonu için RFC3339 kullanımını tercih ediyor .

Genelde bu formatta ısrar eden sunucular için RFC1123 yerine RFC1123Z kullanılmalı ve yeni protokoller için RFC3339 tercih edilmelidir. RFC822, RFC822Z, RFC1123 ve RFC1123Z biçimlendirme için kullanışlıdır; Zamanla birlikte kullanıldığında.Parse, RFC'lerin izin verdiği tüm zaman biçimlerini kabul etmezler.

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).

-2

Aşağıdaki, dizeyi tarihe dönüştürme sorunumu çözdü

ana paket

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"

Paul adam smith'e teşekkürler


1
Hepsi güzel ama soru ile pek ilgisi yok, deos it?
matthias krull

Haklısın @matthiaskrull. Tarihleri ​​karşılaştırma sorusuna cevap vermez, ancak tarihleri ​​kolaylıkla ayrıştırmaya kısmen yardımcı olur.
suryakrupa

Yani bunu bu ve diğer bir çift. Sadece yorumlardaki bir şeyi birbirine bağlamanın, rastgele faydalı bitlerle cevap vermekten daha uygun olacağını söylüyorum.
matthias krull
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.