m_shige1979のときどきITブログ

プログラムの勉強をしながら学習したことや経験したことをぼそぼそと書いていきます

Github(変なおっさんの顔でるので気をつけてね)

https://github.com/mshige1979

golangでjsonのデータを出力する

一気に気温が上がったり、下がったり大変

安定せんかな〜

jsonでデータを出力する

まあ、今回は単純にjsonを出す

実装1(シンプルな構造体)

main1.go
package main

import (
	"fmt"
	"net/http"
	"log"
	"github.com/gorilla/mux"
	"encoding/json"
)

// 単純な構造体
type Data1 struct {
	Title    string `json:"title"`
	Message  string `json:"message"`
	Status   int    `json:"status"`
}

func main(){

	// ルーティング
	router := mux.NewRouter()

	// URL別設定
	router.HandleFunc("/sample1", func(w http.ResponseWriter, r  *http.Request){

		// 構造体を定義
		var data1 = Data1{}
		data1.Title = "sample1"
		data1.Message = "hello, sample1"
		data1.Status = 100

		// jsonエンコード
		outputJson, err := json.Marshal(&data1)
		if err != nil {
			panic(err)
		}

		// jsonヘッダーを出力
		w.Header().Set("Content-Type", "application/json")

		// jsonデータを出力
		fmt.Fprint(w, string(outputJson))

		// log
		log.Print(r.URL.Path)
	})

	// ハンドル割当
	http.Handle("/", router)

	// log
	log.Print("localhost:9001")

	// ポート
	http.ListenAndServe(":9001", nil)

}

f:id:m_shige1979:20160216215650p:plain

実装2(構造体に配列を含む)

main2.go
package main

import (
	"fmt"
	"net/http"
	"log"
	"github.com/gorilla/mux"
	"encoding/json"
)

// 配列を含む構造体
type Data2 struct {
	Title    string `json:"title"`
	Message  string `json:"message"`
	Status   int    `json:"status"`
	List	 map[string]Item `json:"list"`
}

// 構造体の配列Item
type Item struct {
	Name     string `json:"name"`
	Age      int    `json:"age"`
}

func main(){

	// ルーティング
	router := mux.NewRouter()

	// URL別設定
	router.HandleFunc("/sample2", func(w http.ResponseWriter, r  *http.Request){

		// 構造体を定義
		var data2 = Data2{}
		data2.Title = "sample2"
		data2.Message = "hello, sample2"
		data2.Status = 200
		data2.List = map[string]Item{}
		data2.List["test1"] = Item{Name:"taro", Age: 10}
		data2.List["test2"] = Item{Name:"hanako", Age: 18}
		data2.List["test3"] = Item{Name:"pochi", Age: 50}

		// jsonエンコード
		outputJson, err := json.Marshal(&data2)
		if err != nil {
			panic(err)
		}

		// jsonヘッダーを出力
		w.Header().Set("Content-Type", "application/json")

		// jsonデータを出力
		fmt.Fprint(w, string(outputJson))

		// log
		log.Print(r.URL.Path)
	})

	// ハンドル割当
	http.Handle("/", router)

	// log
	log.Print("localhost:9001")

	// ポート
	http.ListenAndServe(":9001", nil)

}

f:id:m_shige1979:20160216215705p:plain

なんとかできました。
RSSの場合にもあったけど

type Data2 struct {
	Title    string `json:"title"`
	Message  string `json:"message"`
	Status   int    `json:"status"`
	List	 map[string]Item `json:"list"`
}

右の方にjsonとか指定したらその名前になるので小文字にしたい場合などは役に立ちます…というかきまりみたいな感じかな…
テキトーにググったけどそれっぽいパッケージが見つからなかったのでこれでいいはず

golangでRSS2のデータを取得して表示

XMLを取得してパースする

RSSを取得して一覧を表示するサンプルを作成する

参考

[Golang] XML Parsing Example (7) - Parse RSS 2.0
Atomや両方対応のパターンもあります

静的ファイルも参照したい

jsとかcssとか使用したいけどどうやって参照するか
web applications - Serving static content with a root URL with the Gorilla toolkit - Stack Overflow

実装

構成
.
├── main.go
├── static
│   ├── css
│   │   ├── bootstrap-theme.css
│   │   ├── bootstrap-theme.css.map
│   │   ├── bootstrap-theme.min.css
│   │   ├── bootstrap-theme.min.css.map
│   │   ├── bootstrap.css
│   │   ├── bootstrap.css.map
│   │   ├── bootstrap.min.css
│   │   └── bootstrap.min.css.map
│   ├── fonts
│   │   ├── glyphicons-halflings-regular.eot
│   │   ├── glyphicons-halflings-regular.svg
│   │   ├── glyphicons-halflings-regular.ttf
│   │   ├── glyphicons-halflings-regular.woff
│   │   └── glyphicons-halflings-regular.woff2
│   └── js
│       ├── bootstrap.js
│       ├── bootstrap.min.js
│       ├── jquery-2.2.0.min.js
│       ├── jquery-2.2.0.min.map
│       └── npm.js
└── templates
    └── index.html
main.go
package main

// インポート
import (
	"log"
	"net/http"
	"html/template"
	"github.com/gorilla/mux"
	"io/ioutil"
	"encoding/xml"
)

// RSS2用の構造体
type Rss2 struct {
	XMLName		xml.Name	`xml:"rss"`
	Version		string		`xml:"version,attr"`
	// Required
	Title		string		`xml:"channel>title"`
	Link		string		`xml:"channel>link"`
	Description	string		`xml:"channel>description"`
	// Optional
	PubDate		string		`xml:"channel>pubDate"`
	ItemList	[]Item		`xml:"channel>item"`
}

// RSS2の各記事の部分(Item)
type Item struct {
	// Required
	Title		string		`xml:"title"`
	Link		string		`xml:"link"`
	Description	template.HTML	`xml:"description"`
	// Optional
	Content		template.HTML	`xml:"encoded"`
	PubDate		string		`xml:"pubDate"`
	Comments	string		`xml:"comments"`
}

// 主処理
func main(){

	// ルーティング初期化
	r := mux.NewRouter()

	// 静的ファイルをサポート
	r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))

	// url別処理
	r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request){
		// httpよりRSS取得
		_rssURL := "http://m-shige1979.hatenablog.com/rss"
		res, err := http.Get(_rssURL)
		if err != nil {
			panic(err)
		}

		// text形式で読み込む
		asText, err2 := ioutil.ReadAll(res.Body)
		if err2 != nil {
			panic(err2)
		}

		// rss2構造体を定義
		rssData := Rss2{}

		// パースして格納
		err3 := xml.Unmarshal(asText, &rssData)
		if err3 != nil {
			panic(err3)
		}

		// テンプレート生成
		tmpl := template.Must(template.New("index").ParseFiles("templates/index.html"))
		// 変数を設定
		tmpl.Execute(w, struct{
			RssItemList []Item
		}{
			RssItemList: rssData.ItemList,
		})

		// url
		log.Println(r.URL.Path)
	})

	// ルーティング設定
	http.Handle("/", r)

	// ポート待ち
	log.Println(":9001")
	http.ListenAndServe(":9001", nil)
}
templates/index.html
{{ define "index" }}
<!DOCType html>
<html>
<head>
	<meta charset="utf-8" />
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<title>websample3</title>
	<link rel="stylesheet" href="/static/css/bootstrap.min.css" />
</head>
<body>
	<div class="container-fluid">
		<div class="row">
			<div class="col-xs-12">
				<h3>RSSリスト</h3>
			</div>
		</div>
		<div class="row">
			<div class="col-xs-12">
				{{ range .RssItemList }}
				<div>
					<blockquote>
						<p>{{ .PubDate }}</p>
						<p>{{ .Title }}</p>
						<footer>
							<a href="{{ .Link }}" target="_blank">{{ .Link }}</a>
						</footer>
					</blockquote>
				</div>
				{{ end }}
			</div>
		</div>
	</div>
	<script src="/static/js/jquery-2.2.0.min.js"></script>
	<script src="/static/js/bootstrap.min.js"></script>
</body>
</html>
{{ end }}

結果

f:id:m_shige1979:20160211183714p:plain

所感

xmlの解析がなんかいい感じにやってくれたので助かる。
atomなどと一緒にやる場合は多少手間がかかるみたいですけど
構造体の仕組みをちょっと調べないと…

golangでgorillaとかいうのを使ってみる(sessions)

セッションを使用してみる

値を入れること自体はそんなに難しく無い感じですけど取り出すときになんかいろいろ手間取る感じ
基本的には構造体などで管理したほうがいい感じです

インストール

go get github.com/gorilla/sessions

実装

main.go
package main

import (
	"encoding/gob"
	"github.com/gorilla/mux"
	"github.com/gorilla/sessions"
	"net/http"
	"fmt"
	"time"
	"html/template"
	"crypto/rand"
	"encoding/base32"
	"io"
	"strings"
)

// セッション名
var session_name string = "gsid"

// Cookie型のstore情報
var store *sessions.CookieStore

// セッションオブジェクト
var session *sessions.Session

// 構造体
type Data1 struct {
	Count    int
	Msg      string
}

// 主処理
func main(){

	// 構造体を登録
	gob.Register(&Data1{})

	// セッション初期処理
	sessionInit()

	// ルーティング生成
	r := mux.NewRouter()

	// URL別の処理
	r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request){

		// セッションオブジェクトを取得
		session, _ := store.Get(r, session_name)

		data1, ok := session.Values["data1"].(*Data1)
		if data1 != nil {
			data1.Count++
			data1.Msg = fmt.Sprintf("%d件カウント", data1.Count)
		} else {
			data1 = &Data1{0, "データ無し"}
		}
		fmt.Println(ok)
		fmt.Println(data1)
		session.Values["data1"] = data1

		// 保存
		sessions.Save(r, w)

		// テンプレートを指定
		tmpl := template.Must(template.New("index").ParseFiles("templates/index.html"))
		tmpl.Execute(w, struct {
			Detail *Data1
		}{
			Detail: data1,
		})

		// logの代わり
		fmt.Print(time.Now())
		fmt.Println(" url = " + r.URL.Path)
	})

	r.HandleFunc("/clear", func(w http.ResponseWriter, r *http.Request){

		// セッション初期化
		sessionInit()

		// logの代わり
		fmt.Print(time.Now())
		fmt.Println(" url = " + r.URL.Path)

		// redirect
		http.Redirect(w, r, "/", http.StatusFound)

	})

	// rを割当
	http.Handle("/", r)

	// ポートを割当
	fmt.Println("localhost:9001")
	http.ListenAndServe(":9001", nil)
}

// セッション用の初期処理
func sessionInit(){

	// 乱数生成
	b := make([]byte, 48)
	_, err := io.ReadFull(rand.Reader, b)
	if err != nil {
		panic(err)
	}
	str := strings.TrimRight(base32.StdEncoding.EncodeToString(b), "=")

	// 新しいstoreとセッションを準備
	store = sessions.NewCookieStore([]byte(str))
	session = sessions.NewSession(store, session_name)

	// セッションの有効範囲を指定
	store.Options = &sessions.Options{
		Domain:     "localhost",
		Path:       "/",
		MaxAge:     0,
		Secure:     false,
		HttpOnly:   true,
	}

	// log
	fmt.Println("key     data --")
	fmt.Println(str)
	fmt.Println("")
	fmt.Println("store   data --")
	fmt.Println(store)
	fmt.Println("")
	fmt.Println("session data --")
	fmt.Println(session)
	fmt.Println("")

}
templates/index.html
{{ define "index" }}
<!DOCType html>
<html>
	<head>
		<meta charset="utf-8" />
		<title>websample2</title>
	</head>
	<body>
		count = {{ .Detail.Count }}<br />
		msg = {{ .Detail.Msg }}<br />
		<br />
		<a href="/clear">クリア<a/>
	</body>
</html>
{{ end }}


セッションのデータ管理は?

store = sessions.NewCookieStore([]byte(str))

これで"store"とかいう変数にCookie形式の形っぽいデータをどっかに管理するみたい
ちなみにローカルファイル内に配置したい場合は

store = sessions.NewFilesystemStore("", []byte(str))

こうなる
第1引数はセッションファイルの配置場所で空文字の場合は規定の場所を指定centosとかでは"/tmp"みたい…

byteで渡す値でデータを管理しているのでデータを初期化するという意味では一度別の名前にするのが良いかと
Valuesの値を消したりしてもいいかもしれないけど面倒な感じもあるので乱数を生成してから消すのも手かと思われる

所感

なんか遅い…
手動でログを出力しているせいかもしれないけどなんか応答が結構遅い感じがする
ルーティングとセッションをとりあえずだけど対応したのでちょっと他のこともやってみる

うーんやることが増えてきたのでソースがでかくなってきた\(^o^)/

golangでgorillaとかいうのを使ってみる(mux)

ゴリラ?

Gorilla, the golang web toolkit
まあ、http関連のやつでルーティングとかセッションとかを"net/http"よりは柔軟に使える感じのもの
なんか適当に調べたけど"net/http"ではセッションは使えないとかなんとか

ちょっと今回はルーティングの"gorilla/mux"を使用する

マニュアル

http://www.gorillatoolkit.org/pkg/mux

今回はさわりだけ…

インストール

go get github.com/gorilla/mux

実装

今回の構成
.
├── main.go
└── templates
    ├── index.html
    └── save.html
main.go
package main

import (
	"net/http"
	"github.com/gorilla/mux"
	"fmt"
	"time"
	"html/template"
)

func main(){

	// 生成
	r := mux.NewRouter()

	// "/"の場合の処理
	r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

		// テンプレート
		tmpl := template.Must(template.New("index").ParseFiles("templates/index.html"))
		err := tmpl.Execute(w, nil)
		if err != nil {
			panic(err)
		}

		// logの代わり
		fmt.Print(time.Now())
		fmt.Printf(" path: " + r.URL.Path + "\n")
	}).Methods("GET")

	// "/save"の場合の処理
	r.HandleFunc("/save", func(w http.ResponseWriter, r *http.Request) {

		// formの値を取得
		r.ParseForm()
		data1 := r.FormValue("aaa")
		data2 := r.FormValue("bbb")

        // テンプレート
        tmpl := template.Must(template.New("save").ParseFiles("templates/save.html"))
        err := tmpl.Execute(w, struct {
			Data1 string
			Data2 string
		}{
			Data1: data1,
			Data2: data2,
		})
		if err != nil {
			panic(err)
		}

		// logの代わり
		fmt.Print(time.Now())
		fmt.Printf(" path: " + r.URL.Path + "\n")
	}).Methods("POST")

	// 可変URL1
	r.HandleFunc("/test1/{sample1}/", func(w http.ResponseWriter, r *http.Request) {
		// 画面サンプル
		fmt.Fprintf(w, "sample1\n")

		// logの代わり
		fmt.Print(time.Now())
		fmt.Printf(" path: " + r.URL.Path + "\n")
	})

	// 可変URL2
	r.HandleFunc("/test2/{sample1}/{id:[0-9]{1,6}}/", func(w http.ResponseWriter, r *http.Request) {
		// 画面サンプル
		fmt.Fprintf(w, "sample2\n")

		// logの代わり
		fmt.Print(time.Now())
		fmt.Printf(" path: " + r.URL.Path + "\n")
	})

	// handing
	http.Handle("/", r)

	// 設定
	http.ListenAndServe(":9001", nil)
}

※POST、GETだけを指定したい場合など、また一部のURLが可変になる場合は楽できます。

templates/index.html
{{ define "index" }}
<!DOCType html>
<html>
<head>
	<meta charaset="utf-8" />
	<title>websample1</title>
</head>
<body>
	<h3>なんかいれて送信してみて</h3>
	<form method="post" action="/save">
		<input type="text" name="aaa" value="" /><br />
		<input type="text" name="bbb" value="" /><br />
		<input type="submit" value="送信" />
	</form>
</body>
</html>
{{ end }}
templates/save.html
{{ define "save" }}
<!DOCType html>
<html>
<head>
	<meta charaset="utf-8" />
	<title>websample1</title>
</head>
<body>
	<h3>送信されたものは以下</h3>
	<div>
		aaa = {{ .Data1 }}<br />
		bbb = {{ .Data2 }}<br />
	</div>
	<a href="/">top</a>
</body>
</html>
{{ end }}

画面

f:id:m_shige1979:20160209223846p:plain

f:id:m_shige1979:20160209223856p:plain

f:id:m_shige1979:20160209223907p:plain

所感

このツールキットを使用することでネットワーク関連のコードを書くのに結構便利になる感じかと
web アプリを作成するとしたらルーティングとセッションは必須なのできちんとやっておく必要がありそうです。

golangでtemplate(html)の確認

ページを表示する際はテンプレートを使用する

標準では"text/template"と"html/template"が存在する
※他にもあるかもしれないけどあとでやる

シンプルなテンプレート

構造
$ tree
.
├── main.go
└── templates
    └── index.tpl

$
templates/index.tpl
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>golang template test</title>
</head>
<body>
    <h1>Golang Template Sample</h1>
    <p>Title --[{{.Title}}]</p>
    <p>Message--[{{.Message}}] </p>
    <div>
        <h3>Items</h3>
        {{range .List}}
        <p>{{.}}</p>
        {{end}}
    </div>
    <div>
        Link: {{.Link}}
    </div>
</body>
</html>

※テンプレートは中括弧("{}")で挟むようです

main.go
package main

import (
	"fmt"
	"net/http"
	"html/template"
	"time"
)

func main(){
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

		fmt.Println(time.Now().Format("2006/01/02 15:04:05") + " " + r.URL.Path)

		// テンプレート用のファイルを読み込む
		tpl, err1 := template.ParseFiles("templates/index.tpl")
		if err1 != nil {
			panic(err1)
		}

		// テンプレートを出力
		err2 := tpl.Execute(w, struct {
			Title string
			Message string
			List []string
			Link string
		}{
			Title: "Hello",
			Message: "World",
			List: []string{
				"Item1",
				"Item2",
				"Item3",
			},
			Link: "<a href=\"/\">hoge</a>",
		})
		if err2 != nil {
			panic(err2)
		}

	})
	http.ListenAndServe(":9001", nil)
}
ページをひらくとこうなる

f:id:m_shige1979:20160126223113p:plain

一部のデータを加工する

templates/index.tpl
<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8" />
	<title>golang template test</title>
</head>
<body>
	<h1>Golang Template Sample</h1>
	<p>Title --[{{.Title}}]</p>
	<p>Message--[{{.Message}}] </p>
	<div>
		<h3>Items</h3>
		{{range .List}}
		<p>{{.}}</p>
		{{end}}
	</div>
	<div>
		Link: {{.Link | safe}}
	</div>
	<div>
        Link: {{.Link | lock}}
    </div>
</body>
</html>
main.go
package main

import (
	"fmt"
	"net/http"
	"html/template"
	"time"
)

func main(){
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

		fmt.Println(time.Now().Format("2006/01/02 15:04:05") + " " + r.URL.Path)

		// 独自関数でエスケープを解除
		funcMap := template.FuncMap{
			"safe": func(text string) template.HTML { return template.HTML(text) },
			"lock": func(text string) string { return "@@[" + text + "]@@" },
		}

		// テンプレート用のファイルを読み込む
		tpl, _:= template.New("index.tpl").Funcs(funcMap).ParseFiles("templates/index.tpl")

		// テンプレートを出力
		err2 := tpl.Execute(w, struct {
			Title string
			Message string
			List []string
			Link string
		}{
			Title: "Hello",
			Message: "World",
			List: []string{
				"Item1",
				"Item2",
				"Item3",
			},
			Link: "<a href=\"/\">hoge</a>",
		})
		if err2 != nil {
			panic(err2)
		}

	})
	http.ListenAndServe(":9001", nil)
}
結果

f:id:m_shige1979:20160126225319p:plain

複数のテンプレートをファイルを使用する

構成
.
├── main.go
└── templates
    ├── base.tpl
    └── contents.tpl
templates/base.tpl
{{ define "base" }}
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>golang template test</title>
</head>
<body>
    <h1>Golang Template Sample</h1>
    <p>Title --[{{.Title}}]</p>
    <p>Message--[{{.Message}}] </p>
    <div>
        {{ template "contents" . }}
    </div>
</body>
</html>
{{ end }}
templates/contents.tpl
{{ define "contents" }}
    <div>
        <h3>Items</h3>
        {{range .List}}
        <p>{{.}}</p>
        {{end}}
    </div>
    <div>
        Link: {{.Link | safe}}
    </div>
    <div>
        Link: {{.Link | lock}}
    </div>
{{ end }}
main.go
package main

import (
	"fmt"
	"net/http"
	"html/template"
	"time"
)

func main(){
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

		fmt.Println(time.Now().Format("2006/01/02 15:04:05") + " " + r.URL.Path)

		// 独自関数でエスケープを解除
		funcMap := template.FuncMap{
			"safe": func(text string) template.HTML { return template.HTML(text) },
			"lock": func(text string) string { return "@@[" + text + "]@@" },
		}

		// テンプレート用のファイルを読み込む
		tpl := template.Must(template.New("hoge").Funcs(funcMap).ParseFiles("templates/base.tpl", "templates/contents.tpl"))

		// テンプレートを出力
		err2 := tpl.ExecuteTemplate(w, "base", struct {
			Title string
			Message string
			List []string
			Link string
		}{
			Title: "Hello",
			Message: "World",
			List: []string{
				"Item1",
				"Item2",
				"Item3",
			},
			Link: "<a href=\"/\">hoge</a>",
		})
		if err2 != nil {
			panic(err2)
		}

	})
	http.ListenAndServe(":9001", nil)
}

頭パンクしそう(´・ω・`)

所感

やり方自体はパターンがあるからそのうち理解出来ていくと思うけどgo言語の書き方に慣れていないことや日本語のマニュアルがないのかエラーの意味をうまく理解できていないことがある。
いろいろ参考になりそうなソースがネットで検索したら出てくるので参考にしながらやっていくしかない

golangで超簡単なサーバ

フレームワークもあるけどまずはこちらから

単純なAPIなどが欲しかったりする場合などはこちらのほうがいいかもしれないので…

実装

sample
package main

import (
    "fmt"
    "net/http"
)

func main(){
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request){
        fmt.Fprint(w, "Golang Http Server")
    })
    http.ListenAndServe(":8080", nil)
}


f:id:m_shige1979:20160119234155p:plain

こんだけ

所感

やり方はnodejsと同じイメージかな…
jsonとかを扱う方法とかもちょっと調べておく

golangの学習(time)

日時に関する情報を制御する

timeパッケージを使用する

現在日時を取得する

sample
package main

import (
    "fmt"
    "time"
)

func main(){
    _now := time.Now()
    fmt.Println(_now)
}

$ go run time1.go
2016-01-19 22:46:07.181469119 +0900 JST
$

日時を任意のフォーマットで表示する

https://golang.org/src/time/format.go
※フォーマットの指定値がややこしいので気をつけないといけない

sample
package main

import (
    "fmt"
    "time"
)

func main(){
    // 現在日時を取得
    _now := time.Now()

    // format
    const YYYYMMDDHHMISS1 = "2006/01/02 15:04:05"
    const YYYYMMDDHHMISS2 = "06-1-2 3:4:5"

    fmt.Println(_now.Format(YYYYMMDDHHMISS1))
    fmt.Println(_now.Format(YYYYMMDDHHMISS2))
    fmt.Println(_now.Format(time.RFC3339))
}

$ go run time2.go
2016/01/19 22:56:21
16-1-19 10:56:21
2016-01-19T22:56:21+09:00
$

Unixタイムスタンプの秒数を取得

ちょっと意味は違うかも…

sanmple
package main

import (
    "fmt"
    "time"
)

func main(){
    _now := time.Now()
    fmt.Println(_now.Unix())
    fmt.Println(_now.UnixNano())
}

$ go run time3.go
1453212000
1453212000553662868
$

日付加算

日数、月数、年数を指定して加算、減算を行う

sample
package main

import (
    "fmt"
    "time"
)

func main(){
    // 現在の日時を取得
    _now := time.Now()
    fmt.Println(_now)
    fmt.Println("")

    // 日付計算
    fmt.Println(_now.AddDate(0, 0, 10).Format(time.RFC3339))
    fmt.Println(_now.AddDate(0, 2, 0).Format(time.RFC3339))
    fmt.Println(_now.AddDate(5, 0, 0).Format(time.RFC3339))

    fmt.Println("")

    fmt.Println(_now.AddDate(0, 0, -10).Format(time.RFC3339))
    fmt.Println(_now.AddDate(0, -2, 0).Format(time.RFC3339))
    fmt.Println(_now.AddDate(-5, 0, 0).Format(time.RFC3339))
}

$ go run time5.go
2016-01-19 23:06:58.719504358 +0900 JST

2016-01-29T23:06:58+09:00
2016-03-19T23:06:58+09:00
2021-01-19T23:06:58+09:00

2016-01-09T23:06:58+09:00
2015-11-19T23:06:58+09:00
2011-01-19T23:06:58+09:00
$

時間加算

時間を指定して加算、減算を行う

sample
package main

import (
    "fmt"
    "time"
)

func main(){
    // 現在の日時を取得
    _now := time.Now()
    fmt.Println(_now)
    fmt.Println("")

    // 日付計算
    fmt.Println(_now.Add(time.Duration(25) * time.Second).Format(time.RFC3339))
    fmt.Println(_now.Add(time.Duration(12) * time.Minute).Format(time.RFC3339))
    fmt.Println(_now.Add(time.Duration(05) * time.Hour).Format(time.RFC3339))

    fmt.Println("")

    fmt.Println(_now.Add(time.Duration(-25) * time.Second).Format(time.RFC3339))
    fmt.Println(_now.Add(time.Duration(-12) * time.Minute).Format(time.RFC3339))
    fmt.Println(_now.Add(time.Duration(-05) * time.Hour).Format(time.RFC3339))
}

$ go run time6.go
2016-01-19 23:13:56.686245405 +0900 JST

2016-01-19T23:14:21+09:00
2016-01-19T23:25:56+09:00
2016-01-20T04:13:56+09:00

2016-01-19T23:13:31+09:00
2016-01-19T23:01:56+09:00
2016-01-19T18:13:56+09:00
$

文字列を任意のレイアウトより日付に変換

sample
package main

import (
    "fmt"
    "time"
)

func main(){
    _date, _err := time.Parse("2006-01-02 15:04:05", "2001-10-23 15:54:20")
    if _err != nil {
        panic(_err)
    }
    fmt.Println(_date)
}

$ go run time7.go
2001-10-23 15:54:20 +0000 UTC
$

2つの日時より差を取得する

sample
package main

import (
    "fmt"
    "time"
)

func main(){
    // 2つの日時を設定
    _date1, _ := time.Parse("2006-01-02 15:04:05", "2001-10-23 15:54:20")
    _date2, _ := time.Parse("2006-01-02 15:04:05", "2002-10-23 15:54:20")

    // 差を取得する
    _d := _date2.Sub(_date1)

    // 差を出力する
    fmt.Println(_d)
}

$ go run time8.go
8760h0m0s
$

まあ、こんな感じ

所感

使いそうなものをとりあえず、調べてみた。
日付のフォーマットでちょっとつまづきそうだけど基本は抑えた感じ…多分
基本、手続き型言語の仕事が多すぎた分、慣れるのがちょっと大変かも