Bagaimana melakukan perbandingan tanggal / waktu

99

Apakah ada pilihan dalam melakukan perbandingan tanggal di Go? Saya harus mengurutkan data berdasarkan tanggal dan waktu - secara mandiri. Jadi saya mungkin mengizinkan objek yang muncul dalam rentang tanggal selama itu juga muncul dalam rentang waktu tertentu. Dalam model ini, saya tidak bisa begitu saja memilih tanggal terlama, waktu termuda / tanggal terbaru, waktu terbaru dan detik Unix () membandingkannya. Saya sangat menghargai saran apapun.

Pada akhirnya, saya menulis modul perbandingan string parsing waktu untuk memeriksa apakah suatu waktu berada dalam kisaran. Namun, ini tidak berjalan dengan baik; Saya punya beberapa masalah yang menganga. Saya akan mempostingnya di sini hanya untuk bersenang-senang, tetapi saya berharap ada cara yang lebih baik untuk membandingkan waktu.

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
}

Jadi TLDR, saya menulis fungsi withinTimeRange (rentang, waktu) tetapi tidak bekerja sepenuhnya dengan benar. (Faktanya, sebagian besar hanya kasus kedua, di mana rentang waktu melintasi beberapa hari rusak. Bagian asli berfungsi, saya baru menyadari bahwa saya perlu memperhitungkannya saat membuat konversi ke UTC dari lokal.)

Jika ada cara yang lebih baik (sebaiknya dibangun di dalam), saya ingin sekali mendengarnya!

CATATAN: Hanya sebagai contoh, saya menyelesaikan masalah ini di Javascript dengan fungsi ini:

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

Namun saya sangat ingin melakukan filter ini di sisi server.

eatonphil.dll
sumber

Jawaban:

111

Gunakan paket waktu untuk bekerja dengan informasi waktu di Go.

Instan waktu dapat dibandingkan menggunakan metode Before, After, dan Equal. Metode Sub mengurangi dua saat, menghasilkan Durasi. Metode Tambah menambahkan Waktu dan Durasi, menghasilkan Waktu.

Mainkan contoh:

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, ".")
    }
}
andybalholm
sumber
1
Mungkin saya tidak bisa membaca, tetapi saya tidak melihat apa pun di sana tentang perbandingan waktu. Jika ada, bisakah Anda mengarahkan saya ke artikel yang tepat?
eatonphil
12
Cobalah godoc.org/time#Time.Equal atau godoc.org/time#Time.After untuk perbandingan sederhana, atau godoc.org/time#Time.Sub untuk mengetahui perbedaan antara dua waktu.
andybalholm
1
"melaporkan apakah waktu saat t setelah kamu." menakutkan
Damien Roche
22

Untuk perbandingan antara dua kali gunakan waktu.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)

Keluaran program:

Lifespan is 3h0m0s

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

Charney Kaye
sumber
Ini jawaban terbaik.
MithunS
15

Untuk kasus ketika interval Anda berakhir adalah tanggal tanpa jam seperti "dari 01-01 2017 hingga sepanjang hari 2017-01-16" lebih baik menyesuaikan interval menjadi 23 jam 59 menit dan 59 detik seperti:

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) {
    ...
}
Oleg Neumyvakin
sumber
1
Persis yang saya butuhkan untuk membandingkan Stempel Waktu yang disimpan dengan Waktu Saat Ini.
PGP_Protector
1

Protokol terbaru lebih memilih penggunaan RFC3339 per dokumentasi paket waktu golang .

Secara umum RFC1123Z harus digunakan sebagai pengganti RFC1123 untuk server yang bersikeras pada format tersebut, dan RFC3339 sebaiknya digunakan untuk protokol baru. RFC822, RFC822Z, RFC1123, dan RFC1123Z berguna untuk pemformatan; bila digunakan dengan time.Parse mereka tidak menerima semua format waktu yang diizinkan oleh 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).
deepakssn
sumber
-1

Berikut ini memecahkan masalah saya mengubah string menjadi tanggal

paket utama

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"

Terima kasih untuk paul adam smith

suryakrupa
sumber
1
Itu semua bagus tapi tidak banyak hubungannya dengan pertanyaan, deos itu?
matthias krull
Anda benar @ matthiaskrull. Itu tidak menjawab pertanyaan tentang membandingkan tanggal, tetapi sebagian membantu dalam mengurai tanggal dengan mudah.
suryakrupa
Jadi lakukan ini dan beberapa lainnya. Saya hanya mengatakan bahwa menautkan sesuatu di komentar akan lebih cocok daripada menjawab dengan bit berguna acak.
matthias krull