質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

Q&A

解決済

1回答

6355閲覧

golangでstructフィールド(time.Time型)をフォーマットして、structに格納し直したい

umino

総合スコア54

Go

Go(golang)は、Googleで開発されたオープンソースのプログラミング言語です。

0グッド

0クリップ

投稿2021/04/05 02:04

編集2021/04/05 02:07

前提・実現したいこと

golang(+gin+gorm)で、webアプリを作成しています。
下記のような構造体PostA(マイグレーション用)のCreatedAtフィールドがあります。

Go

1type PostA struct { 2 ID uint 3 CreatedAt time.Time //2021-04-03T00:16:13.320376Z 4 UpdatedAt time.Time 5}

フィールドCreatedAttime.Time型なので2021-04-03T00:16:13.320376Zの形です。
これをREADしてreturnする前に、
YYYY/MM/DD hh:mmのフォーマットへ整形し、2021/04/03 00:16としたいです。
そして、フィールドCreatedAtに格納し直し、下記のようにsliceにした形でreturnしたいです。

Go

1records := []PostA{} 2...(中略) 3return records

発生している問題・エラーメッセージ

しかし、フィールドCreatedAtをフォーマットするため下記のようにすると、

Go

1records[i].CreatedAt = records[i].CreatedAt.Format("2006/1/2 15:04") //型エラー

time.Formatstring型に変換するので、
PostAのフィールドCreatedAt(time.Time型)に格納し直すことができません。

知見のある方・お詳しい方、このケースで、どのようにすれば良いかを教えていただけませんでしょうか。
以下、私が考えた案です。

案1:
別の構造体PostBを用意して、string型でDBからレコードを取得し、正規表現などでフォーマットする。

Go

1type PostB struct { 2 ID uint 3 CreatedAt string //2021-04-03T00:16:13.320376Z 4} 5 6...(中略) 7records[i].CreatedAt = records[i].CreatedAt.Format("2006/1/2 15:04") //型エラー 8...()

しかし、time.Format()は当然string型には使用できませんので、取得した文字列そのものを正規表現などでフォーマットする必要があります。
(そもそも構造体PostAは「DBテーブルをマイグレーションするために作成」したので、READに使用すべきではないと考え、新しい構造体PostBを使用する方法を考えました)

案2:
別の構造体PostBを用意して、元のtime.Time型とは別にstring型を格納するフィールドを用意し、変換して格納する。

Go

1type PostB struct { 2 ID uint 3 CreatedAt time.Time //2021-04-03T00:16:13.320376Z 4 CreatedAtStr string //2021/04/03 00:16 5} 6...(中略) 7records[i].CreatedAtStr = records[i].CreatedAt.Format("2006/1/2 15:04") 8...()

案3:
その他

実務でgolangおよび構造体の取扱をしたことがなく勘所がわからず、お詳しい方にご教示いただきたく思います。
よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

案3のその他の一例として提案してみます。

JSONにはカスタムデータタイプという仕組みがあります。
以下のようにtime.Timeの実装を参考にしてjson.Marshaler, json.Unmarshalerを備えた独自の時刻型を定義するしかけがあります。

参考コード
https://play.golang.org/p/EjnUzLXvbIU

go

1package main 2 3import ( 4 "encoding/json" 5 "fmt" 6 "os" 7 "time" 8) 9 10type DBTime struct { 11 time.Time 12} 13 14func (t DBTime) MarshalJSON() ([]byte, error) { 15 return []byte(t.Format(`"2006/1/2 15:04"`)), nil 16} 17 18func (t *DBTime) UnmarshalJSON(b []byte) error { 19 tm, err := time.Parse(`"2006/1/2 15:04"`, string(b)) 20 if err != nil { 21 return err 22 } 23 t.Time = tm 24 return nil 25} 26 27type PostA struct { 28 ID uint 29 CreatedAt DBTime 30} 31 32func main() { 33 tm, _ := time.Parse("2006/1/2 15:04", "2021/04/05 13:13") 34 json.NewEncoder(os.Stdout).Encode(PostA{ID: 123, CreatedAt: DBTime{tm}}) 35 var v PostA 36 json.Unmarshal([]byte(`{"ID":123,"CreatedAt":"2021/4/5 13:13"}`), &v) 37 fmt.Println(v) 38}

出力

output

1{"ID":123,"CreatedAt":"2021/4/5 13:13"} 2{123 2021-04-05 13:13:00 +0000 UTC}

GormにもCustum Data Typeを定義する仕掛けがあります。

ValuerとScannerをサポートする独自型を定義すると文字列と独自型の変換方法を定義できます。
以下の情報を参考にしてみましょう。
https://gorm.io/docs/data_types.html

投稿2021/04/05 04:27

編集2021/04/05 04:35
nobonobo

総合スコア3367

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

umino

2021/04/05 14:48 編集

nobonoboさん さっそくのご回答ご教示ありがとうございます。 サンプルコードまで見せていただいて、大変勉強になります。 golandに貼り付けてデバッグモードで動かしてみました。 jsonにパースするのはgin(フレームワーク)のcontrollerで、下記のようにクライアントへ返す直前に行うので、 func FetchPost(c *gin.Context) { postId := c.Query("postId") result := db.FindPost(postId) c.JSON(200, result) //ここでjsonにする ・structに独自time型を定義する ・取得したデータをjson.Marshaler, json.Unmarshalerを用いて独自time型でフォーマットし、変数へ格納する ・(&上記のようにjsonにしてクライアントへ返す) をやってみたいと思います。 jsonのMarshalerについて、今までは難しそうだな...と避けていました。デバッガを追っていてもまだ理解できていないところがあるのですが、これを機に理解できるよう努力します。 丁寧にご教示いただきまして、ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問