Cách so sánh ngày / giờ


97

Có bất kỳ tùy chọn nào để thực hiện so sánh ngày trong Go không? Tôi phải sắp xếp dữ liệu dựa trên ngày và giờ - một cách độc lập. Vì vậy, tôi có thể cho phép một đối tượng xuất hiện trong một phạm vi ngày miễn là nó cũng xuất hiện trong một phạm vi thời gian. Trong mô hình này, tôi không thể chỉ chọn ngày cũ nhất, giờ trẻ nhất / ngày mới nhất, thời gian mới nhất và Unix () giây để so sánh chúng. Tôi thực sự đánh giá cao bất kỳ đề xuất nào.

Cuối cùng, tôi đã viết một mô-đun so sánh chuỗi phân tích cú pháp thời gian để kiểm tra xem thời gian có nằm trong một phạm vi hay không. Tuy nhiên, điều này không tốt chút nào; Tôi có một số vấn đề về lỗ hổng. Tôi sẽ đăng điều đó ở đây chỉ cho vui, nhưng tôi hy vọng có một cách tốt hơn để so sánh thời gian.

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
}

Vì vậy, TLDR, tôi đã viết một hàm withinTimeRange (phạm vi, thời gian) nhưng nó không hoạt động hoàn toàn chính xác. (Trên thực tế, hầu hết chỉ là trường hợp thứ hai, trong đó phạm vi thời gian qua nhiều ngày bị phá vỡ. Phần ban đầu đã hoạt động, tôi chỉ nhận ra rằng tôi cần phải tính đến điều đó khi thực hiện chuyển đổi sang UTC từ địa phương.)

Nếu có một cách tốt hơn (tốt hơn là được tích hợp sẵn), tôi rất muốn nghe về nó!

LƯU Ý: Chỉ là một ví dụ, tôi đã giải quyết vấn đề này trong Javascript với chức năng này:

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

Tuy nhiên, tôi thực sự muốn thực hiện bộ lọc phía máy chủ.

Câu trả lời:


109

Sử dụng gói thời gian để làm việc với thông tin thời gian trong Go.

Các phiên bản thời gian có thể được so sánh bằng cách sử dụng các phương pháp Trước, Sau và Bằng. Phương thức Sub trừ hai phiên bản, tạo ra một Thời lượng. Phương thức Add thêm Thời gian và Khoảng thời gian, tạo ra một Thời gian.

Ví dụ chơi :

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

Có lẽ tôi không thể đọc, nhưng tôi không thấy gì trong đó về những so sánh thời gian. Nếu nó ở đó, bạn có thể chỉ cho tôi một bài báo chính xác không?
eatonphil

12
Hãy thử godoc.org/time#Time.Equal hoặc godoc.org/time#Time.After để so sánh đơn giản, hoặc godoc.org/time#Time.Sub để tìm ra sự khác biệt giữa hai thời điểm.
andybalholm

1
"báo cáo thời gian tức thời t có sau u hay không." kỳ lạ
Damien Roche

22

Để so sánh giữa hai lần sử dụng thời gian.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)

Chương trình xuất ra:

Lifespan is 3h0m0s

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


Đây là câu trả lời tốt nhất.
MithunS

15

Đối với trường hợp khi khoảng thời gian của bạn kết thúc, đó là ngày không có giờ như "từ ngày 1 tháng 1 năm 2017 đến cả ngày của năm 2017-01", tốt hơn nên điều chỉnh khoảng thời gian thành 23 giờ 59 phút và 59 giây như:

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
Chính xác những gì tôi cần để so sánh TimeStamp được lưu trữ với Thời gian hiện tại.
PGP_Protector

1

Các giao thức gần đây thích sử dụng RFC3339 cho mỗi tài liệu gói thời gian golang .

Nói chung, RFC1123Z nên được sử dụng thay vì RFC1123 cho các máy chủ nhấn mạnh vào định dạng đó và RFC3339 nên được ưu tiên cho các giao thức mới. RFC822, RFC822Z, RFC1123 và RFC1123Z hữu ích cho việc định dạng; khi được sử dụng với thời gian. Chúng không chấp nhận tất cả các định dạng thời gian được RFCs cho phép.

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

Phần sau đã giải quyết vấn đề chuyển đổi chuỗi thành ngày tháng của tôi

gói chính

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"

Cảm ơn paul adam smith


1
Đó là tất cả tốt đẹp nhưng không liên quan nhiều đến câu hỏi, deos nó?
matthias krull

Bạn đúng @matthiaskrull. Nó không trả lời câu hỏi so sánh ngày tháng, nhưng một phần giúp phân tích ngày tháng một cách dễ dàng.
suryakrupa

Vì vậy, làm điều này và một vài người khác. Tôi chỉ nói rằng liên kết một cái gì đó trong các nhận xét sẽ phù hợp hơn với việc trả lời bằng các bit hữu ích ngẫu nhiên.
matthias krull
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.