LoginSignup
1
0

More than 5 years have passed since last update.

Goで今月の第4土曜日を計算する

Last updated at Posted at 2018-12-18

PHPerだったので、これで済んでいた計算をGoに置き換えようとして、ぱっとライブラリが無さそうだったので真面目に実装した。

<?php
echo date_create("fourth saturday of this month")->format("c");

使う素材は公式のtimeパッケージのみとする。

考えたアルゴリズム

  1. 今月の1日を取得する
  2. 1日の曜日を調べて、土曜日までの日数を出す
  3. 最初の土曜日を計算
  4. 7日 * 3 = 21日うしろが第4土曜日のはず
package main

import (
    "errors"
    "fmt"
    "time"
)

func main() {
    jst := time.FixedZone("Asia/Tokyo", 9*60*60)
    fmt.Println(NthSaturday(4, jst))
}

func NthSaturday(n int, loc *time.Location) (time.Time, error) {
    now := time.Now().In(loc)

    if n <= 0 || 4 < n {
        return now, errors.New("there is no 5th saturday.")
    }

    year, month, _ := now.Date()
    firstDay := time.Date(year, month, 1, 0, 0, 0, 0, loc)
    firstSaturday := int(time.Saturday-firstDay.Weekday()) + 1
    nthSaturday := firstSaturday + (n-1)*7

    return time.Date(year, month, nthSaturday, 0, 0, 0, 0, loc), nil
}

汎用化して、任意の曜日で計算できるようにすると、こんな感じかな。

package main

import (
    "errors"
    "fmt"
    "time"
)

func main() {
    jst := time.FixedZone("Asia/Tokyo", 9*60*60)
    fmt.Println(NthWeekday(4, time.Monday, jst))
}

func NthWeekday(n int, wd time.Weekday, loc *time.Location) (time.Time, error) {
    now := time.Now().In(loc)

    if n <= 0 || 4 < n {
        return now, errors.New("there is no 5th weekday.")
    }

    year, month, _ := now.Date()
    firstDay := time.Date(year, month, 1, 0, 0, 0, 0, loc)
    first := int(wd-firstDay.Weekday()) + 1
    if first <= 0 {
        first += 7
    }
    nth := first + (n-1)*7

    return time.Date(year, month, nth, 0, 0, 0, 0, loc), nil
}

第5曜日を計算しようと思ったら、月によっては存在しない可能性があるので、エラーチェックがもう少し必要になる。

1
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
1
0