首頁  >  文章  >  後端開發  >  如何標準化時間範圍內數組的元素?

如何標準化時間範圍內數組的元素?

PHPz
PHPz轉載
2024-02-08 21:30:35746瀏覽

如何標準化時間範圍內數組的元素?

php小編新一為您介紹如何在時間範圍內標準化陣列的元素。在開發中,我們經常需要處理時間序列數據,而這些數據可能會出現時間跳躍或缺失的情況。為了確保資料的準確性和完整性,我們需要對數組中的元素進行標準化。標準化可以使陣列的元素按照時間順序排列,並填滿缺少的時間點。下面,我們將詳細介紹如何實現這項功能。

問題內容

我正在嘗試標準化一個時間範圍內的元素陣列。假設您有 20 筆銀行交易發生在 2022 年 1 月 1 日

transaction  1 - 2022/01/01
transaction  2 - 2022/01/01
...
transaction 20 - 2022/01/01

除了它們發生的日期之外,我們沒有其他數據,但我們仍然希望為它們分配一天中的一個小時,因此它們結束為:

transaction  1 - 2022/01/01 00:00
transaction  2 - 2022/01/01 ??:??
...
transaction 20 - 2022/01/01 23:59

在 go 中,我有一個函數嘗試計算元素數組中索引的一天中某個時間的標準化:

func normal(start, end time.time, arraysize, index float64) time.time {
    delta := end.sub(start)
    minutes := delta.minutes()

    duration := minutes * ((index+1) / arraysize)

    return start.add(time.duration(duration) * time.minute)
}

但是,我在2022/1/1 00:00 到2022/1/1 23:59 的時間範圍內意外計算出4 個元素數組中索引0 的2022/1/1 05:59 ,相反,我希望看到2022/1/1 00:00。在這些條件下唯一能正常運作的是索引 3。

那麼,我的標準化做錯了什麼?

編輯:

這是由 @icza 修復的函數

func timeindex(min, max time.time, entries, position float64) time.time {
    delta := max.sub(min)
    minutes := delta.minutes()

    if position < 0 {
        position = 0
    }

    duration := (minutes * (position / (entries - 1)))

    return min.add(time.duration(duration) * time.minute)
}

有一個例子:假設我們的開始和結束日期是2022/01/01 00:00 - 2022/01/01 00:03,我們的銀行交易數組中有3 個條目,我們希望取得第3 號交易的標準化時間(數組中的2):

result := timeindex(time.date(2022, time.january, 1, 0, 0, 0, 0, time.utc), time.date(2022, time.january, 1, 0, 3, 0, 0, time.utc), 3, 2)

由於開始時間和結束時間之間只有4 分鐘(從00:0000:03),並且想要尋找陣列(大小3)中最後一個條目(索引2)的標準化時間,結果應該是:

fmt.Printf("%t", result.Equal(time.Date(2022, time.January, 1, 0, 3, 0, 0, time.UTC))
// prints "true"

或範圍內的最後一分鐘,即 00:03

這是一個可重現的範例:https://go.dev/play/p/ezwkqanv1at

解決方法

n 點之間有n-1 段。這意味著,如果您想在插值中包含startend,則時間段數(即delta)為arraysize - 1

此外,如果將1 加到index,則結果不可能是start (您將跳過00:00 )。

所以正確的演算法是這樣的:

func normal(start, end time.time, arraysize, index float64) time.time {
    minutes := end.sub(start).minutes()

    duration := minutes * (index / (arraysize - 1))

    return start.add(time.duration(duration) * time.minute)
}

go playground 上嘗試。

另請注意,如果您有很多交易(按照一天中的分鐘數排列,大約一千次),您可能很容易最終會出現多個具有相同時間戳(相同小時和分鐘)的交易。如果您想避免這種情況,請使用比分鐘更小的精度,例如秒或毫秒:

func normal(start, end time.time, arraysize, index float64) time.time {
    sec := end.sub(start).seconds()

    duration := sec * (index / (arraysize - 1))

    return start.add(time.duration(duration) * time.second)
}

是的,這將導致時間戳的秒數也不一定為零,但將確保更高的交易數量具有不同的、唯一的時間戳。

如果您的交易數量級接近一天的秒數(即 86400),那麼您可以完全刪除此「單位」並使用 time.duration 本身(即奈秒)。即使對於最大數量的事務,這也將保證時間戳的唯一性:

func normal(start, end time.time, arraysize, index float64) time.time {
    delta := float64(end.sub(start))

    duration := delta * (index / (arraysize - 1))

    return start.add(time.duration(duration))
}

用 100 萬筆交易對此進行測試,以下是前 15 個時間部分(它們僅在亞秒部分延遲):

0 - 00:00:00.00000
1 - 00:00:00.08634
2 - 00:00:00.17268
3 - 00:00:00.25902
4 - 00:00:00.34536
5 - 00:00:00.43170
6 - 00:00:00.51804
7 - 00:00:00.60438
8 - 00:00:00.69072
9 - 00:00:00.77706
10 - 00:00:00.86340
11 - 00:00:00.94974
12 - 00:00:01.03608
13 - 00:00:01.12242
14 - 00:00:01.20876
15 - 00:00:01.29510
16 - 00:00:01.38144
17 - 00:00:01.46778
18 - 00:00:01.55412
19 - 00:00:01.64046

go playground 上嘗試這個。

以上是如何標準化時間範圍內數組的元素?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:stackoverflow.com。如有侵權,請聯絡admin@php.cn刪除