github.com/andersfylling/snowflake/v5@v5.0.1/snowflake.go (about) 1 package snowflake 2 3 import ( 4 "errors" 5 "strconv" 6 "time" 7 ) 8 9 const ( 10 EpochDiscord uint64 = 1420070400000 11 ) 12 13 // NewID creates a new Snowflake Snowflake from a uint64. 14 func NewSnowflake(id uint64) Snowflake { 15 return Snowflake(id) 16 } 17 18 // Snowflake twitter snowflake design 19 type Snowflake uint64 20 21 type ID = Snowflake 22 23 // IsZero since snowflake exists of several parts, including a timestamp, 24 // I assume a valid snowflake Snowflake is never 0. 25 func (s Snowflake) IsZero() bool { 26 return uint64(s) == 0 27 } 28 29 // Valid makes sure the snowflake is after the fixed epoch 30 func (s Snowflake) Valid() bool { 31 return (s >> 22) >= 1 // older than 1 millisecond 32 } 33 34 // String returns the decimal representation of the snowflake Snowflake. 35 func (s Snowflake) String() string { 36 return strconv.FormatUint(uint64(s), 10) 37 } 38 39 // HexString converts the Snowflake into a hexadecimal string 40 func (s Snowflake) HexString() string { 41 return strconv.FormatUint(uint64(s), 16) 42 } 43 44 // HexPrettyString converts the Snowflake into a hexadecimal string with the hex prefix 0x 45 func (s Snowflake) HexPrettyString() string { 46 return "0x" + strconv.FormatUint(uint64(s), 16) 47 } 48 49 // MarshalBinary create a binary literal representation as a string 50 func (s Snowflake) MarshalBinary() (data []byte, err error) { 51 return []byte(strconv.FormatUint(uint64(s), 2)), nil 52 } 53 54 func (s *Snowflake) UnmarshalBinary(text []byte) (err error) { 55 id, err := strconv.ParseUint(string(text), 2, 64) 56 if err != nil { 57 return 58 } 59 *s = Snowflake(id) 60 61 return 62 } 63 64 func (s *Snowflake) UnmarshalJSON(data []byte) (err error) { 65 *s = 0 66 length := len(data) 67 if length == 0 { 68 // Blank value. 69 return 70 } 71 if length == 4 && string(data) == "null" { 72 // This is a zero value. 73 return 74 } 75 76 // if the snowflake is passed as a string, we account for the double quote wrap 77 start := 0 78 if data[0] == '"' { 79 start++ 80 length-- 81 } 82 if signed := data[start] == '-'; signed { 83 start++ 84 *s |= 1 << 63 85 } 86 87 var c byte 88 var tmp uint64 89 for i := start; i < length; i++ { 90 c = data[i] - '0' 91 if c < 0 || c > 9 { 92 err = errors.New("cannot parse non-integer symbol:" + string(data[i])) 93 return 94 } 95 tmp = tmp*10 + uint64(c) 96 } 97 98 *s |= Snowflake(tmp) 99 return 100 } 101 102 func (s Snowflake) MarshalJSON() (data []byte, err error) { 103 if s == 0 { 104 data = []byte(`null`) 105 } else { 106 data = []byte(`"` + s.String() + `"`) 107 } 108 return 109 } 110 111 func (s Snowflake) MarshalText() (text []byte, err error) { 112 text = []byte(s.String()) 113 err = nil 114 115 return 116 } 117 118 func (s *Snowflake) UnmarshalText(text []byte) (err error) { 119 id, err := strconv.ParseUint(string(text), 10, 64) 120 if err != nil { 121 return 122 } 123 *s = Snowflake(id) 124 125 return 126 } 127 128 func (s Snowflake) Date() time.Time { 129 epoch := (uint64(s) >> uint64(22)) + EpochDiscord 130 return time.Unix(int64(epoch)/1000, 0) 131 }