날짜 / 시간 비교 방법


98

Go에서 날짜 비교를 수행 할 수있는 옵션이 있습니까? 날짜와 시간을 기준으로 독립적으로 데이터를 정렬해야합니다. 따라서 시간 범위 내에서도 발생하는 한 날짜 범위 내에서 발생하는 개체를 허용 할 수 있습니다. 이 모델에서는 단순히 가장 오래된 날짜, 가장 어린 시간 / 최근 날짜, 최신 시간 및 Unix () 초를 선택하여 비교할 수는 없습니다. 어떤 제안이라도 정말 감사하겠습니다.

궁극적으로 시간이 범위 내에 있는지 확인하기 위해 시간 구문 분석 문자열 비교 모듈을 작성했습니다. 그러나 이것은 잘되지 않습니다. 몇 가지 문제가 있습니다. 재미로 여기에 게시 할 것이지만 시간을 비교할 수있는 더 좋은 방법이 있기를 바랍니다.

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
}

그래서 TLDR, withinTimeRange (range, time) 함수를 작성했지만 완전히 올바르게 작동하지 않습니다. (사실, 대부분의 경우 시간 범위가 며칠에 걸쳐 교차하는 두 번째 경우에 불과합니다. 원래 부분은 작동했지만 로컬에서 UTC로 변환 할 때이를 고려해야한다는 것을 깨달았습니다.)

더 나은 (기본적으로 내장 된) 방법이 있다면 그것에 대해 듣고 싶습니다!

참고 : 예를 들어이 함수를 사용하여 Javascript에서이 문제를 해결했습니다.

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

그러나 나는이 필터를 서버 측에서 정말로 원합니다.

답변:


110

시간 패키지를 사용하여 Go에서 시간 정보로 작업하십시오.

시간 순간은 Before, After 및 Equal 방법을 사용하여 비교할 수 있습니다. Sub 메서드는 두 개의 순간을 빼서 Duration을 생성합니다. Add 메서드는 시간과 기간을 추가하여 시간을 생성합니다.

플레이 예 :

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

읽을 수는 없지만 시간 비교에 대해서는 아무것도 보지 못했습니다. 거기에있는 경우 정확한 기사를 알려 주시겠습니까?
eatonphil 2014 년

12
시도 godoc.org/time#Time.Equal 또는 godoc.org/time#Time.After 단순 비교를 위해, 또는 godoc.org/time#Time.Sub을 두 번 사이의 차이를 발견 할 수 있습니다.
andybalholm

1
"시간 순간 t가 u 이후인지 여부를보고합니다." 섬뜩한
Damien Roche 19 년

22

들어 두 번 사이의 비교 사용 ) (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)

프로그램은 다음을 출력합니다.

Lifespan is 3h0m0s

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


이것이 최고의 답변입니다.
MithunS

15

간격이 끝나는 경우 "2017-01-01부터 2017-01-16의 하루 종일"과 같이 시간이없는 날짜 인 경우 간격을 다음과 같이 23 시간 59 분 59 초로 조정하는 것이 좋습니다.

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
저장된 타임 스탬프를 현재 시간과 비교하는 데 정확히 필요한 것입니다.
PGP_Protector 2010 년

1

최근 프로토콜은 golang 시간 패키지 문서 당 RFC3339 사용을 선호합니다 .

일반적으로 해당 형식을 고집하는 서버에는 RFC1123 대신 RFC1123Z를 사용해야하며 새 프로토콜에는 RFC3339를 선호해야합니다. RFC822, RFC822Z, RFC1123 및 RFC1123Z는 형식화에 유용합니다. time.Parse와 함께 사용할 때 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

다음은 문자열을 날짜로 변환하는 문제를 해결했습니다.

패키지 메인

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에게 감사드립니다.


1
그게 다 좋지만 질문과 관련이 많지 않네요.
matthias krull 2015 년

@matthiaskrull 맞습니다. 날짜 비교 문제에 대한 답은 아니지만 날짜를 쉽게 구문 분석하는 데 부분적으로 도움이됩니다.
suryakrupa

그래서 이것 과 몇 가지를하십시오. 나는 단지 코멘트에서 무언가를 연결하는 것이 임의의 유용한 비트로 대답하는 것보다 더 적합 할 것이라고 말하고 있습니다.
matthias krull
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.