2013/06/20

Recent entries from same category

  1. gRPC のサービスが簡単に作れるライブラリ「lile」
  2. CreateFile で FILE_SHARE_DELETE を指定するとどうなるか
  3. Visual Studio Code で ssh 先のファイルを編集する方法
  4. 虫が入り込むその瞬間
  5. ダウンロードの進捗プログレスバー実装は可能か

元ネタ: 誰もが一度は陥る日付処理。各種プログラミング言語における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言語童貞が許されるのは小学生までだよね」
「キモーイ」
「キャハハハハハハ」