❄️

[discordgo] Snowflake ID からメッセージ作成日時を逆算する

に公開

はじめに

discordgo でメッセージを取得した際に Timestamp を使わず、ID を SnowflakeTimestamp() に渡してタイムスタンプを取得したほうがいいかもしれないね、という話です。

ある bot の実装を行っているとき、「指定した日時のメッセージをすべて取得する」という処理を実装する必要がありました。メッセージの取得は discordgo.Session.ChannelMessages() を使うことができますが、これは指定した2つのメッセージID間のメッセージを取得する機能しかなく、指定した日付のメッセージかどうかを確認する処理は別に実装する必要がありました。
discordgo.Session.ChannelMessages() が返す Message 構造体には Timestamp フィールドが含まれており、一見するとこれをそのまま使えばいいように見えました...が、公式ドキュメントを確認したところこれは推奨されないようです。

https://pkg.go.dev/github.com/bwmarrin/discordgo@v0.29.0#Message

	// The time at which the messsage was sent.
	// CAUTION: this field may be removed in a
	// future API version; it is safer to calculate
	// the creation time via the ID.
	Timestamp time.Time `json:"timestamp"`

意訳すると「このフィールドはいつか消すから、代わりにIDから逆算してな」ということらしいです。
「IDから逆算する」とはなんでしょうか?

Snowflake ID

調べたところ、discord の ID 採番は Snowflake ID という採番形態をとっているみたいでした。
https://ja.wikipedia.org/wiki/Snowflake_ID

「雪片はすべて固有の構造を持っていると信じられている」ことに由来する名前で、ID内に生成時刻を含むのが特徴みたいです。ここから逆算しろってことみたいですね。

やってみる

便利なことに、discordgo には Snowflake ID から作成時刻を取り出す関数 SnowflakeTimestamp があります。

https://pkg.go.dev/github.com/bwmarrin/discordgo@v0.29.0#SnowflakeTimestamp

使うときは ID をそのまま突っ込むだけで大丈夫です。time.Time 型でタイムスタンプが返されます。

// discord Snowflake ID からメッセージの作成時間を逆算
ts, err := discordgo.SnowflakeTimestamp(msg.ID)
if err != nil {
  ts = m.Timestamp
}
GitHubで編集を提案

Discussion