日付/時刻比較を行う方法


97

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で、insideTimeRange(range、time)関数を記述しましたが、完全に正しく機能していません。(実際、ほとんどの場合、時間範囲が日をまたぐ2番目のケースだけが壊れています。元の部分は機能しましたが、ローカルから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;
}

ただし、このフィルターをサーバー側で実行したいのですが。

回答:


109

Goの時間情報を操作するには、timeパッケージを使用します。

時刻は、Before、After、Equalメソッドを使用して比較できます。Subメソッドは2つの瞬間を減算し、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を使用して2つの時間の違いを調べてください。
アンディバルホルム2014年

1
"時刻tがuの後かどうかを報告します。" 不気味な
Damien Roche

22

以下のために2時間の間の比較が使用)(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
保存されたTimeStampを現在の時刻と比較するために必要なもの。
PGP_Protector 2018年

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"

ポールアダムスミスのおかげで


1
それはすべていいですが、質問とはあまり関係ありません、それを元に戻しますか?
matthias krull 2015年

あなたは正しい@matthiaskrullです。日付を比較するという質問には答えませんが、部分的に日付を簡単に解析するのに役立ちます。
スリヤクルパ2015年

だから、これと他のいくつかを行います。私はコメントで何かをリンクすることはランダムな有用なビットで答えるより良いフィットになると言っているだけです。
matthias krull 2015年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.