0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Go】日付型を扱う時はsql-driverのparseTimeをTrueにしよう

Last updated at Posted at 2024-05-06

はじめに

タイトルの通り、Goでデータベースを使用する際にDSN(Data Source Name)のオプションを適切に設定していなかったため詰まったためメモとして残します。
sql-driverはmysqlを使用しています。

結論

Date型を扱う時はparseTimeをTrueにしよう(誰でも知ってるかも笑)

理由

Todoテーブルからsqlxのselectメソッドでデータを取得した時のこと

	err := db.Select(&todos, "SELECT id,task,due_date, status,created_at,updated_at FROM todos")

sqlxのselectメソッドは構造体のフィールド名、もしくはタグ名と一致していれば自動的にマッピングしてくれます。

type Todo struct {
	Id        int       `json:"id" db:"id"`
	Task      string    `json:"task" db:"task"`
	DueDate   time.Time `json:"due_date" db:"due_date"`
	Status    int       `json:"status" db:"status"`
	CreatedAt time.Time `json:"created_at" db:"created_at"`
	UpdatedAt time.Time `json:"updated_at" db:"updated_at"`
}

とても便利だったので使用したところ以下のようなエラーが発生

Failed to get todos sql: Scan error on column index 2, name "due_date": unsupported Scan, storing driver.Value type []uint8 into type *time.Time

[]uint8を型*time.Timeに入れることはできないよと怒られています。
なぜByte型?
とりあえずtime.Time型にしていたのをuint8型にしてみる

[
    {
        "id": 1,
        "task": "テスト",
        "due_date": "MjAyMy0wOS0wOCAwMDowMDowMA==",
        "status": 0,
        "created_at": "MjAyNC0wNS0wNiAxMjowNTo0Mg==",
        "updated_at": "MjAyNC0wNS0wNiAxMjowNTo0Mg=="
    },
    {
        "id": 2,
        "task": "テスト",
        "due_date": "MjAyNC0wOS0wOCAwMDowMDowMA==",
        "status": 0,
        "created_at": "MjAyNC0wNS0wNiAxMjowNjowMA==",
        "updated_at": "MjAyNC0wNS0wNiAxMjowNjowMA=="
    }
]

正常に処理が行われByte型のデータが返却されてきました
取得時にByte型からTime型に変換して格納しないといけないのか?と思い調べていると以下の情報を発見

parseTime

以下公式ドキュメントより抜粋

parseTime

Type:           bool
Valid Values:   true, false
Default:        false

parseTime=true changes the output type of DATE and DATETIME values to > > > time.Time instead of []byte / string The date or datetime like 0000-00-00 > 00:00:00 is converted into zero value of time.Time.

なんとデフォルトではDATE型は[]Byte型で返却されるようになっていました。

parseTime=trueを設定すると、DATE型とDATETIME型の値の出力型が
[]byte/string型 ⇨ time.Time型に変換してくれるようになるようです。

ということで以下のように変更

変更前
- dbConf := fmt.Sprintf("%s:%s@tcp(%s)/%s", MySqlConf.User, MySqlConf.Pass, MySqlConf.Host, MySqlConf.Name)
- db, err := sqlx.Connect("mysql", dbConf)

変更後
+ dbConf := fmt.Sprintf("%s:%s@tcp(%s)/%s?parseTime=true", MySqlConf.User, MySqlConf.Pass, MySqlConf.Host, MySqlConf.Name)
+ db, err := sqlx.Connect("mysql", dbConf)

mysqlのsqlドライバーでは?の後にオプションを設定します。

sql-driverとは? Go言語では、SQLデータベースと通信するためのdatabase/sql パッケージがある。

ただこのパッケージ自体はデータベースと通信する機能は持っていない。
SQLデータベースとの実際の通信は、専用のドライバーが行う。
SQLドライバー = 特定のデータベースシステム(MySQL、PostgreSQL、SQLiteなど)と通信するためのプログラム

import(
	"github.com/jmoiron/sqlx"  //⇦sqlパッケージを拡張したsqlx
	_ "github.com/go-sql-driver/mysql" //⇦ドライバー
)

こんな感じにドライバーもインストールして読み込まないと使えない。

設定変更後

[
    {
        "id": 1,
        "task": "テスト",
        "due_date": "2023-09-08T00:00:00Z",
        "status": 0,
        "created_at": "2024-05-06T12:05:42Z",
        "updated_at": "2024-05-06T12:05:42Z"
    },
    {
        "id": 2,
        "task": "テスト",
        "due_date": "2024-09-08T00:00:00Z",
        "status": 0,
        "created_at": "2024-05-06T12:06:00Z",
        "updated_at": "2024-05-06T12:06:00Z"
    }
]

正常に返却されるようになりました。

まとめ

最近、Go言語を勉強を始めたのですが、初歩的なところで躓き時間を浪費してしまいました。
同じところで躓く方はいないかも知れませんがメモとして残します笑

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?