timestamp.go raw

   1  // Package timestamp is a set of helpers for working with timestamps including
   2  // encoding and conversion to various integer forms, from time.Time and varints.
   3  package timestamp
   4  
   5  import (
   6  	"encoding/binary"
   7  	"time"
   8  	"unsafe"
   9  
  10  	"next.orly.dev/pkg/nostr/encoders/ints"
  11  	"next.orly.dev/pkg/lol/chk"
  12  	"next.orly.dev/pkg/lol/errorf"
  13  )
  14  
  15  // T is a convenience type for UNIX 64 bit timestamps of 1 second
  16  // precision.
  17  type T struct{ V int64 }
  18  
  19  // New creates a new timestamp.T, as zero or optionally from the first variadic
  20  // parameter as int64.
  21  func New(x ...int64) (t *T) {
  22  	t = &T{}
  23  	if len(x) > 0 {
  24  		t.V = x[0]
  25  	}
  26  	return
  27  }
  28  
  29  // Now returns the current UNIX timestamp of the current second.
  30  func Now() *T {
  31  	tt := T{time.Now().Unix()}
  32  	return &tt
  33  }
  34  
  35  // U64 returns the current UNIX timestamp of the current second as uint64.
  36  func (t *T) U64() uint64 {
  37  	if t == nil {
  38  		return 0
  39  	}
  40  	return uint64(t.V)
  41  }
  42  
  43  // I64 returns the current UNIX timestamp of the current second as int64.
  44  func (t *T) I64() int64 {
  45  	if t == nil {
  46  		return 0
  47  	}
  48  	return t.V
  49  }
  50  
  51  // Time converts a timestamp.Time value into a canonical UNIX 64 bit 1 second
  52  // precision timestamp.
  53  func (t *T) Time() time.Time { return time.Unix(t.V, 0) }
  54  
  55  // Int returns the timestamp as an int.
  56  func (t *T) Int() int {
  57  	if t == nil {
  58  		return 0
  59  	}
  60  	return int(t.V)
  61  }
  62  
  63  // Bytes returns a timestamp as an 8 byte thing.
  64  func (t *T) Bytes() (b []byte) {
  65  	b = make([]byte, 8)
  66  	binary.BigEndian.PutUint64(b, uint64(t.V))
  67  	return
  68  }
  69  
  70  // FromTime returns a T from a time.Time
  71  func FromTime(t time.Time) *T { return &T{t.Unix()} }
  72  
  73  // FromUnix converts from a standard int64 unix timestamp.
  74  func FromUnix(t int64) *T { return &T{t} }
  75  
  76  func (t *T) FromInt(i int) { *t = T{int64(i)} }
  77  
  78  // FromBytes converts from a string of raw bytes.
  79  func FromBytes(b []byte) *T { return &T{int64(binary.BigEndian.Uint64(b))} }
  80  
  81  // FromVarint decodes a varint and returns the remainder of the bytes and the encoded
  82  // timestamp.T.
  83  func FromVarint(b []byte) (t *T, rem []byte, err error) {
  84  	n, read := binary.Varint(b)
  85  	if read < 1 {
  86  		err = errorf.E("failed to decode varint timestamp %v", b)
  87  		return
  88  	}
  89  	t = &T{n}
  90  	rem = b[:read]
  91  	return
  92  }
  93  
  94  // String renders a timestamp.T as a string.
  95  func (t *T) String() (s string) {
  96  	b := make([]byte, 0, 20)
  97  	tt := ints.New(t.U64())
  98  	b = tt.Marshal(b)
  99  	return unsafe.String(&b[0], len(b))
 100  }
 101  
 102  // Marshal a timestamp.T into bytes and append to a provided byte slice.
 103  func (t *T) Marshal(dst []byte) (b []byte) { return ints.New(t.U64()).Marshal(dst) }
 104  
 105  // Unmarshal a byte slice with an encoded timestamp.T value and append it to a provided byte
 106  // slice.
 107  func (t *T) Unmarshal(b []byte) (r []byte, err error) {
 108  	n := ints.New(0)
 109  	if r, err = n.Unmarshal(b); chk.E(err) {
 110  		return
 111  	}
 112  	*t = T{n.Int64()}
 113  	return
 114  }
 115  
 116  // MarshalJSON marshals a timestamp.T using the json MarshalJSON interface.
 117  func (t *T) MarshalJSON() ([]byte, error) {
 118  	return ints.New(t.U64()).Marshal(nil), nil
 119  }
 120