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

huangapple go评论74阅读模式
英文:

How to get monotonic part of time.Time in Go

问题

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

假设我有这样的时间戳:2022-03-31 10:20:26.370463 +0200 CEST m=+0.007725255,我想要获取m=+0.007725255部分并存储在一个不同的变量中,或者至少获取+0.007725255部分。在Go语言中,有什么惯用的方法可以实现这个目标?

英文:

am currently working with timestamps and I would like to store in a variable the monotonic clock reading section.

Let's say that I have this: 2022-03-31 10:20:26.370463 +0200 CEST m=+0.007725255 then I would like to get m=+0.007725255 in a different var, or at least the +0.007725255 section. What is the idiomatic way in Go to get it?

答案1

得分: 2

Go的time.Time类型存储了两个时间戳:

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

m=+0.007725255表示自进程启动以来的单调持续时间(当它存在于time.Time中时)。

Go通过在初始化期间记录time.startNano时间戳(非公开)来计算这个偏移量。time.Now使用startNano来计算存储在time.Time中的单调持续时间。由于通常不需要直接检索此值,因此没有简单的公共API可用。

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

示例代码中展示了如何使用time.Now来计算时间间隔和自进程启动以来的持续时间。

输出结果如下:

...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
英文:

A Go time.Time stores 2 timestamps:

  • Wall clock
  • Monotonic duration since process start (optional, via time.Now)

m=+0.007725255 represents the monotonic duration since the start of the process (when present in a time.Time).

Go calculates this offset by recording time.startNano timestamp during initialisation (not public). time.Now uses startNano to calculate the monotonic duration stored in time.Time. There is no simple public API to directly retrieve this value since it should never be needed.

In practice, you should simply subtract 2 timestamps generated via time.Now in your current process and the result will be the monotonic duration. If you need to know the duration since process startup you should record a startup timestamp during initalisation.

Example:

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
}

Outputs:

...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

答案2

得分: 0

单调时钟仅用于计算时间差。单调时钟的绝对值是未定义的,你不应该尝试获取它。我认为你真正想要的是从基准时间开始的持续时间。

func init() {
	baseTime = time.Now()
}

// NowTimestamp 实际上返回的是从基准时间开始的持续时间
func NowTimestamp() time.Duration {
	return time.Now().Sub(baseTime)
}
英文:

The monotonic clock is just used for differences between times. The absolute value of the monotonic clock is undefined and you should not try to get it. I think what you really want for your timestamp is the duration from a base time.

func init() {
baseTime = time.Now()
}
// NowTimestamp returns really just the duration from the base time
func NowTimestamp() time.Duration {
return time.Now().Sub(baseTime)
}

huangapple
  • 本文由 发表于 2022年3月31日 16:28:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/71689285.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定