2013/06/20

Recent entries from same category

  1. Go 言語プログラミングエッセンスという本を書きました。
  2. errors.Join が入った。
  3. unsafe.StringData、unsafe.String、unsafe.SliceData が入った。
  4. Re: Go言語で画像ファイルか確認してみる
  5. net/url に JoinPath が入った。

元ネタ: 誰もが一度は陥る日付処理。各種プログラミング言語におけるDateTime型/TimeStamp型の変換方法のまとめ
Go言語が無かったので書いてみた。

現在時刻の取得

package main

import (
    "fmt"
    "time"
)

func main() {
    fmt.Println(time.Now())
}
2013-06-19 21:46:14.186298 +0900 +0900

Time => Unix時刻変換

package main

import (
    "fmt"
    "time"
)

func main() {
    fmt.Println(time.Now().Unix())
}
1371646123

Unix時刻 => Time変換

package main

import (
    "fmt"
    "time"
)

func main() {
    fmt.Println(time.Unix(13716461230))
}
ここからが面白くて、通常日付のフォーマットやパースは殆どの言語では %Y%m%d といった表記を使います。 しかしGo言語では、ある固定の数値を用いて表現する事で、いかにも日付らしく表現出来る手法を取っています。 package main

import (
    "fmt"
    "log"
    "time"
)

func main() {
    t, err := time.Parse(
        "2006-01-02 15:04:05 -0700",    // スキャンフォーマット
        "2013-06-19 21:54:23 +0900")    // パースしたい文字列
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(t)
}
Formatも同じく package main

import (
    "fmt"
    "time"
)

func main() {
    fmt.Println(time.Now().Format("2006/01/02 15:04:05 MST"))
}
2013/06/19 22:01:01 +0900 この数値とタイムゾーン文字列で構成された文字列を、定数として提供しています。 const (
    ANSIC       = "Mon Jan _2 15:04:05 2006"
    UnixDate    = "Mon Jan _2 15:04:05 MST 2006"
    RubyDate    = "Mon Jan 02 15:04:05 -0700 2006"
    RFC822      = "02 Jan 06 15:04 MST"
    RFC822Z     = "02 Jan 06 15:04 -0700" // RFC822 with numeric zone
    RFC850      = "Monday, 02-Jan-06 15:04:05 MST"
    RFC1123     = "Mon, 02 Jan 2006 15:04:05 MST"
    RFC1123Z    = "Mon, 02 Jan 2006 15:04:05 -0700" // RFC1123 with numeric zone
    RFC3339     = "2006-01-02T15:04:05Z07:00"
    RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00"
    Kitchen     = "3:04PM"
    // Handy time stamps.
    Stamp      = "Jan _2 15:04:05"
    StampMilli = "Jan _2 15:04:05.000"
    StampMicro = "Jan _2 15:04:05.000000"
    StampNano  = "Jan _2 15:04:05.000000000"
)
この手法を使う事で、ちょっとした日付フォーマットの差異も自分のプログラムで吸収する事が出来る様になっています。
初めてこの実装を見た時は戸惑いましたが、慣れると非常に心地よくなります。

おまけでもう少し。

Go言語では、timeパッケージを使って経過時間(Duration)も表す事が出来ます。 time.Sleep(1 * time.Second) // 1秒
time.Sleep(2 * time.Minute) // 2分
time.Sleep(3 * time.Hour)   // 3時間
1時間と61秒は、61分 (1 * time.Hour + 61 * time.Second).Minutes()
日付の加算も出来る。閏年も完璧。 package main

import (
    "fmt"
    "time"
)

func main() {
    fmt.Println(time.Date(20122281213140, time.UTC).AddDate(001))
    // 2012-02-29 12:13:14 +0000 UTC
    fmt.Println(time.Date(20122291213140, time.UTC).AddDate(001))
    // 2012-03-01 12:13:14 +0000 UTC
}
このDurationを使って、数秒後に発動するイベント(channel)も作れます。例えば、3秒以内に CTRL-C を押すかのイベントループ package main

import (
    "fmt"
    "os"
    "os/signal"
    "syscall"
    "time"
)

func main() {
    s := make(chan os.Signal)
    signal.Notify(s, syscall.SIGINT)

    select {
    case <- time.After(3 * time.Second):
        fmt.Println("Timeout")
        break
    case <- s:
        fmt.Println("Pressed CTRL-C")
        break
    }
}
3秒後にコールバック package main

import (
    "fmt"
    "os"
    "time"
)

func main() {
    time.AfterFunc(3 * time.Second, func() {
        fmt.Println("Timeout")
        os.Exit(0)
    })

    select {}
}
とまぁ、とても便利になっています。Go言語触った事ないとか、かなりヤバいです。

「えーマジGo言語童貞!?」
「Go言語童貞が許されるのは小学生までだよね」
「キモーイ」
「キャハハハハハハ」
Posted at by