如何在 Go 中获取 time.Time 的单调部分

How to get monotonic part of time.Time in Go

我目前正在处理时间戳,我想将单调时钟读取部分存储在一个变量中。

假设我有这个:2022-03-31 10:20:26.370463 +0200 CEST m=+0.007725255 然后我想在不同的 var 中获得 m=+0.007725255,或者至少在 +0.007725255 部分。 Go 中惯用的获取方式是什么?

A Go time.Time 存储 2 个时间戳:

  • 挂钟
  • 自进程启动以来的单调持续时间(可选,通过 time.Now

m=+0.007725255 表示自进程开始以来的单调持续时间(当出现在 time.Time 中时)。

Go 通过在初始化期间记录 time.startNano 时间戳(而不是 public)来计算此偏移量。 time.Now 使用 startNano 计算存储在 time.Time 中的单调持续时间。没有简单的 public API 可以直接检索此值,因为永远不需要它。

实际上,您应该简单地减去当前过程中通过 time.Now 生成的 2 个时间戳,结果将是单调持续时间。如果您需要知道自进程启动以来的持续时间,您应该在初始化期间记录启动时间戳。

示例:

package main

import (
    "errors"
    "fmt"
    "math"
    "strconv"
    "strings"
    "time"
)

func main() {
    t0 := time.Now()
    fmt.Println("...example event...")
    time.Sleep(time.Millisecond)
    t1 := time.Now()
    fmt.Println("Event start:", t0)
    fmt.Println("Event completed:", t1)

    fmt.Println("=== Not recommended ===")
    offsetT0, _ := monoOffset(t0)
    fmt.Println("Parsed start offset:", offsetT0)
    startNano, _ := calculateStartNano()
    fmt.Println("Calculate start offset via startNano: ", t0.Sub(startNano))

    fmt.Println("=== Recommended ===")
    fmt.Println("Example event duration:", t1.Sub(t0))
    fmt.Println("Time since startup", time.Since(t0))
}

// You should never need anything below here (code smell).

func monoOffset(t time.Time) (time.Duration, error) {
    // Recommend strings.Cut on Go1.18+.
    parts := strings.Split(t.String(), " m=")
    if len(parts) != 2 {
        return 0, errors.New("missing monotonic offset")
    }

    seconds, err := strconv.ParseFloat(parts[1], 64)
    if err != nil {
        return 0, err
    }

    nanos := math.Round(seconds * 1e9)
    return time.Duration(nanos), nil
}

func calculateStartNano() (time.Time, error) {
    now := time.Now()
    offset, err := monoOffset(now)
    if err != nil {
        return time.Time{}, err
    }
    return now.Add(-offset), nil
}

输出:

...example event...
Event start: 2022-04-16 16:54:25.088159496 +1000 AEST m=+0.000079273
Event completed: 2022-04-16 16:54:25.089438935 +1000 AEST m=+0.001358685
=== Not recommended ===
Parsed start offset : 79.273µs
Calculate start offset via startNano:  79.273µs
=== Recommended ===
Example event duration: 1.279412ms
Time since startup 2.016789ms