github.com/diamondburned/arikawa/v2@v2.1.0/discord/time.go (about) 1 package discord 2 3 import ( 4 "encoding/json" 5 "strconv" 6 "strings" 7 "time" 8 ) 9 10 // Timestamp has a valid zero-value, which can be checked using the IsValid() 11 // method. This is useful for optional timestamps such as EditedTimestamp. 12 type Timestamp time.Time 13 14 const TimestampFormat = time.RFC3339 // same as ISO8601 15 16 var ( 17 _ json.Unmarshaler = (*Timestamp)(nil) 18 _ json.Marshaler = (*Timestamp)(nil) 19 ) 20 21 func NewTimestamp(t time.Time) Timestamp { 22 return Timestamp(t) 23 } 24 25 func NowTimestamp() Timestamp { 26 return NewTimestamp(time.Now()) 27 } 28 29 // UnmarshalJSON parses a nullable RFC3339 string into time. 30 func (t *Timestamp) UnmarshalJSON(v []byte) error { 31 str := strings.Trim(string(v), `"`) 32 if str == "null" { 33 return nil 34 } 35 36 r, err := time.Parse(TimestampFormat, str) 37 if err != nil { 38 return err 39 } 40 41 *t = Timestamp(r) 42 return nil 43 } 44 45 // MarshalJSON returns null if Timestamp is not valid (zero). It returns the 46 // time formatted in RFC3339 otherwise. 47 func (t Timestamp) MarshalJSON() ([]byte, error) { 48 if !t.IsValid() { 49 return []byte("null"), nil 50 } 51 52 return []byte(`"` + t.Format(TimestampFormat) + `"`), nil 53 } 54 55 func (t Timestamp) IsValid() bool { 56 return !t.Time().IsZero() 57 } 58 59 func (t Timestamp) Format(fmt string) string { 60 return t.Time().Format(fmt) 61 } 62 63 func (t Timestamp) Time() time.Time { 64 return time.Time(t) 65 } 66 67 // 68 69 type UnixTimestamp int64 70 71 func (t UnixTimestamp) String() string { 72 return t.Time().String() 73 } 74 75 func (t UnixTimestamp) Time() time.Time { 76 return time.Unix(int64(t), 0) 77 } 78 79 // 80 81 type UnixMsTimestamp int64 82 83 func TimeToMilliseconds(t time.Time) UnixMsTimestamp { 84 return UnixMsTimestamp(t.UnixNano() / int64(time.Millisecond)) 85 } 86 87 func (t UnixMsTimestamp) String() string { 88 return t.Time().String() 89 } 90 91 func (t UnixMsTimestamp) Time() time.Time { 92 return time.Unix(0, int64(t)*int64(time.Millisecond)) 93 } 94 95 // 96 97 type Seconds int 98 99 // NullSecond is used in cases where null should be used instead of a number or 100 // omitted. This is similar to NullSnowflake. 101 const NullSecond = -1 102 103 func DurationToSeconds(dura time.Duration) Seconds { 104 return Seconds(dura.Seconds()) 105 } 106 107 func (s Seconds) MarshalJSON() ([]byte, error) { 108 if s < 1 { 109 return []byte("null"), nil 110 } else { 111 return []byte(strconv.Itoa(int(s))), nil 112 } 113 } 114 115 func (s Seconds) String() string { 116 return s.Duration().String() 117 } 118 119 func (s Seconds) Duration() time.Duration { 120 return time.Duration(s) * time.Second 121 } 122 123 // 124 125 // Milliseconds is in float64 because some Discord events return time with a 126 // trailing decimal. 127 type Milliseconds float64 128 129 func DurationToMilliseconds(dura time.Duration) Milliseconds { 130 return Milliseconds(dura.Milliseconds()) 131 } 132 133 func (ms Milliseconds) String() string { 134 return ms.Duration().String() 135 } 136 137 func (ms Milliseconds) Duration() time.Duration { 138 const f64ms = Milliseconds(time.Millisecond) 139 return time.Duration(ms * f64ms) 140 }