1. ホーム
  2. datetime

[解決済み] 日付/時刻比較の方法

2022-09-29 23:58:18

質問

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
}

つまり、私はwithinTimeRange(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;
}

しかし、私は本当にこのフィルタをサーバサイドで行いたいのです。

どのように解決するのですか?

この場合 時間 パッケージを使って、Go で時間情報を扱います。

<ブロッククオート

時間のインスタントを比較するには、Before, After, Equal メソッドを使って比較できます。Subメソッドは2つのインスタントを減算し、Durationを生成します。 AddメソッドはTimeとDurationを加算し、Timeを生成します。

再生 の例です。

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