Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
3
Help us understand the problem. What is going on with this article?
@Sekky0905

Go言語で今月から標準入力で受けたyyyy-mmまでの各月の月初と月末を一覧表示する簡単なコマンドラインアプリを作ってみた

More than 3 years have passed since last update.

Go言語で今月から標準入力で受けたyyyy-mmまでの各月の月初と月末を一覧表示する簡単なコマンドラインアプリを作ってみた

Goで標準入力と time packageを用いて、日付に関する簡単なコマンドラインアプリを作ってみた。
月初や月末を求めるようなことは日々の業務でも割と出くわすのではないだろうか。

「ここんところ、こうした方が良いだろ」というアドバイスがあれば、コメントをいただけると幸いです。

流れ

main

  1. 標準入力を受け取る
  2. 標準入力で受け取った値が不適切だったら、再度入力させる処理を行う
  3. 標準入力から受け取った文字列をyyyyとmmに分割
  4. 標準入力から受け取った文字列をyyyyとmmを引数にShowSpecificTermListを呼び出し

ShowSpecificTermList

  1. 現在の時刻を取得
  2. 現在の時刻を元に基準となるDateを作成
  3. 標準入力から受け取った文字列をyyyyとmmを元に終了の条件となるDateを設定
  4. for文で月初は、基準となるDateからループごとに-1月する
  5. for文で月末は、基準となるDateからループごとに-1月&&-1日する
  6. 終了条件の日付以前の日にちまで遡ったら、breakしてループを抜ける

月末で、基準日(日付が1日)から1日を引いていることがポイント

実装してみた

各処理の詳細はコード中にコメントとして記述しています。

package main

import (
    "fmt"
    "log"
    "regexp"
    "strconv"
    "strings"
    "time"
)

func main() {
    // 遡る日付をyyyy-mmで入力を受け付ける
    fmt.Println("いつまで遡りますか?\nyyyy-mmで入力してください。(現在と同じかそれよりも前を指定してください。)")

    var input string

    var limitYear int

    var limitMonth int

    // 適切な入力がなされない限りループ
    for {
        // 標準入力をスキャン
        fmt.Scan(&input)

        // 正規表現のチェック
        if b, err := regexp.MatchString(`^(\d{4})-(0[1-9]|1[0-2])$`, input); !b || err != nil {
            fmt.Println("入力いただいた文字列が不適切です。 yyyy-mmで入力してください。")
        } else {
            // 入力された文字列を"-"で分割
            s := strings.Split(input, "-")
            // 遡る西暦の限界値
            limitYear, err = strconv.Atoi(s[0])
            if err != nil {
                log.Printf("can not strconv.Atoi :%v \n", err)
            }

            // 遡る月の限界値
            limitMonth, err = strconv.Atoi(s[1])
            if err != nil {
                log.Printf("can not strconv.Atoi :%v \n", err)
            }

            // 入力で受け付けた日付をDateに変換
            inputDate := time.Date(limitYear, time.Month(limitMonth), 0, 0, 0, 0, 0, time.UTC)

            // 現在よりも未来の日付にならないようにする
            if !inputDate.After(time.Now()) {
                // 適切な値が入力されたら、ループを抜ける
                break
            }

            fmt.Println("現在と同じかそれよりも前を指定してください。")
        }
    }

    ShowSpecificTermList(limitYear, limitMonth)
}

// 現在の時刻から指定した日付まで遡った月初と月末の日付の一覧を表示する
func ShowSpecificTermList(limitYear, limitMonth int) {
    // 現在の時刻を取得
    now := time.Now()
    // 基準となる日付を設定
    criterionDate := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, time.UTC)

    // 終了の条件となる日付を設定
    finDate := time.Date(limitYear, time.Month(limitMonth), 30, 0, 0, 0, 0, time.UTC)

    i := 0
    for {
        // 月初を設定
        beginningOfTheMonth := criterionDate.AddDate(0, -i, 0)
        // 月末を設定
        endOfTheMonth := criterionDate.AddDate(0, -i+1, -1)

        fmt.Printf("月初:%v", beginningOfTheMonth)
        fmt.Printf("月末:%v\n", endOfTheMonth)

        // 終了条件の日付以前の日にちまで遡ったら、breakしてループを抜ける
        if beginningOfTheMonth.Before(finDate) {
            fmt.Println("終了")
            break
        }

        // インクリメント
        i++
    }
}

実行結果

いつまで遡りますか?
yyyy-mmで入力してください。(現在と同じかそれよりも前を指定してください。)
2020-03 // <= 入力
現在と同じかそれよりも前を指定してください
2016-01 // 入力
月初:2017-06-01 12:00:00 +0000 UTC月末:2017-06-30 12:00:00 +0000 UTC
月初:2017-05-01 12:00:00 +0000 UTC月末:2017-05-31 12:00:00 +0000 UTC
月初:2017-04-01 12:00:00 +0000 UTC月末:2017-04-30 12:00:00 +0000 UTC
月初:2017-03-01 12:00:00 +0000 UTC月末:2017-03-31 12:00:00 +0000 UTC
月初:2017-02-01 12:00:00 +0000 UTC月末:2017-02-28 12:00:00 +0000 UTC
月初:2017-01-01 12:00:00 +0000 UTC月末:2017-01-31 12:00:00 +0000 UTC
月初:2016-12-01 12:00:00 +0000 UTC月末:2016-12-31 12:00:00 +0000 UTC
月初:2016-11-01 12:00:00 +0000 UTC月末:2016-11-30 12:00:00 +0000 UTC
月初:2016-10-01 12:00:00 +0000 UTC月末:2016-10-31 12:00:00 +0000 UTC
月初:2016-09-01 12:00:00 +0000 UTC月末:2016-09-30 12:00:00 +0000 UTC
月初:2016-08-01 12:00:00 +0000 UTC月末:2016-08-31 12:00:00 +0000 UTC
月初:2016-07-01 12:00:00 +0000 UTC月末:2016-07-31 12:00:00 +0000 UTC
月初:2016-06-01 12:00:00 +0000 UTC月末:2016-06-30 12:00:00 +0000 UTC
月初:2016-05-01 12:00:00 +0000 UTC月末:2016-05-31 12:00:00 +0000 UTC
月初:2016-04-01 12:00:00 +0000 UTC月末:2016-04-30 12:00:00 +0000 UTC
月初:2016-03-01 12:00:00 +0000 UTC月末:2016-03-31 12:00:00 +0000 UTC
月初:2016-02-01 12:00:00 +0000 UTC月末:2016-02-29 12:00:00 +0000 UTC
月初:2016-01-01 12:00:00 +0000 UTC月末:2016-01-31 12:00:00 +0000 UTC
終了


time.AddDate(years int, months int, days int) Timeの使い方

time.AddDateでは、引数にyearsを与えれば「年」が、monthを与えれば「月」が、daysを与えれば「日」が加算されたTimeを返してくれる。
今回は、これをちょっと応用して、monthやdaysの引数にマイナスの値を与えることで、過去のTimeを作成している。

 参考にさせていただいたサイト

time package
regexp package
http://qiita.com/peketamin/items/ccc881b46f4cc56e4aa9

※ ブログでも同一記事を投稿している
Go言語で今月から標準入力で受けたyyyy-mmまでの各月の月初と月末を一覧表示する簡単なコマンドラインアプリを作ってみた

3
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Sekky0905
最近GoとGCPに戻ってきました。 以前は、GAE/Go、AWS、TypeScript、Angular、Vueをやっていました。
hrbrain
人事評価クラウドHRBrainを開発・運営するスタートアップ

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
3
Help us understand the problem. What is going on with this article?