github.com/gdubicki/ets@v0.2.3-0.20240420195337-e89d6a2fdbda/timestamper.go (about)

     1  package main
     2  
     3  import (
     4  	"bytes"
     5  	"log"
     6  	"math"
     7  	"strconv"
     8  	"time"
     9  
    10  	"github.com/lestrrat-go/strftime"
    11  )
    12  
    13  type TimestampMode int
    14  
    15  const (
    16  	AbsoluteTimeMode TimestampMode = iota
    17  	ElapsedTimeMode
    18  	IncrementalTimeMode
    19  )
    20  
    21  type Timestamper struct {
    22  	Mode           TimestampMode
    23  	TZ             *time.Location
    24  	Formatter      *strftime.Strftime
    25  	StartTimestamp time.Time
    26  	LastTimestamp  time.Time
    27  }
    28  
    29  func NewTimestamper(format string, mode TimestampMode, timezone *time.Location) (*Timestamper, error) {
    30  	formatter, err := strftime.New(format,
    31  		strftime.WithMilliseconds('L'),
    32  		strftime.WithUnixSeconds('s'),
    33  		strftime.WithSpecification('f', microseconds))
    34  	if err != nil {
    35  		return nil, err
    36  	}
    37  	now := time.Now()
    38  	return &Timestamper{
    39  		Mode:           mode,
    40  		TZ:             timezone,
    41  		Formatter:      formatter,
    42  		StartTimestamp: now,
    43  		LastTimestamp:  now,
    44  	}, nil
    45  }
    46  
    47  func (t *Timestamper) CurrentTimestampString() string {
    48  	now := time.Now()
    49  	var s string
    50  	switch t.Mode {
    51  	case AbsoluteTimeMode:
    52  		s = t.Formatter.FormatString(time.Now().In(t.TZ))
    53  	case ElapsedTimeMode:
    54  		s = formatDuration(t.Formatter, now.Sub(t.StartTimestamp))
    55  	case IncrementalTimeMode:
    56  		s = formatDuration(t.Formatter, now.Sub(t.LastTimestamp))
    57  	default:
    58  		log.Panic("unknown mode ", t.Mode)
    59  	}
    60  	t.LastTimestamp = now
    61  	return s
    62  }
    63  
    64  func formatDuration(formatter *strftime.Strftime, duration time.Duration) string {
    65  	return formatter.FormatString(time.Unix(0, duration.Nanoseconds()).UTC())
    66  }
    67  
    68  var microseconds strftime.Appender
    69  
    70  func init() {
    71  	microseconds = strftime.AppendFunc(func(b []byte, t time.Time) []byte {
    72  		microsecond := int(t.Nanosecond()) / int(time.Microsecond)
    73  		if microsecond == 0 {
    74  			return append(b, "000000"...)
    75  		} else {
    76  			length := int(math.Log10(float64(microsecond))) + 1
    77  			b = append(b, bytes.Repeat([]byte("0"), 6-length)...)
    78  			return append(b, strconv.Itoa(microsecond)...)
    79  		}
    80  	})
    81  }