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