任意の年月を表示してみる

投稿者: | 2015年7月26日

1, 3, 12ヶ月表示ができるようになったので、今度は任意の年または月のカレンダーを表示できるようにします。

“-y”に続けて年を指定すると任意の年のカレンダーを、”-m”に続けて月を指定すると任意の月のカレンダーを表示するため、オプションに”-m”を追加しました。

#! /usr/bin/swift
import Foundation
// Date型の引数を受け取り、DateComponents型を返す関数
func getCalComp(date: Date) -> DateComponents {
    let cal: NSCalendar = NSCalendar(calendarIdentifier: NSCalendar.Identifier.gregorian)!
    let components: DateComponents = cal.components([.year, .month, .day, .weekday], from:date)
    return components
}
// 一日始まりのDateComponents型の引数を受け取り、その月の配列を返す関数
func getCalendar(components: DateComponents) -> [String] {
    var cal_seq: [String] = ["日","月","火","水","木","金","土"]
    var endofmonth: [Int] = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    if (components.year! % 4) == 0 && (components.year! % 100) != 0 || (components.year! % 400) == 0 {
        endofmonth[2]+=1
    }
    for _ in 0..<42 {
        cal_seq.append("  ")
    }
    var datestring: String
    for var i in 1..<endofmonth[components.month!]+1 {
        if i < 10 {
            datestring = " \(i)"
        } else {
            datestring = "\(i)"
        }
        cal_seq[ (6 + i) + (components.weekday! - 1) ] = datestring
    }
    return cal_seq
}
// 実質プログラムの始まり
var flag_y: Int = 1
var flag_m: Int = 1
var spec_y: Int = 0
var spec_m: Int = 0
let arguments: [String] = CommandLine.arguments
if arguments.count != 1 {
    switch arguments[1] {
    case "-y":
        flag_y = 4
        flag_m = 3
        if arguments.count == 3 {
            spec_y = Int(arguments[2])!
        }
    case "-3":
        flag_m = 3
    case "-m":
        if arguments.count == 3 {
            spec_m = Int(arguments[2])!
        }
    default:
        break
    }
}
let je_flag = 1
let now: Date = Date()
var cal_comp: DateComponents = getCalComp(date:now)
if flag_y == 4 {
    cal_comp.month = 1
    if spec_y != 0 {
        cal_comp.year = spec_y
    }
} else if flag_y == 1 && flag_m == 3 {
    cal_comp.month!-=1
}
if spec_m != 0 {
    cal_comp.month = spec_m
}
cal_comp.day = 1
var sequence: [String] = []
var header: String = ""
var header_y: String = ""
var header_m: [String] = ["", "", "", "", "", "", "", "", "", "", "", ""]
for var i in 0..<12 {
    var calen: Date = Calendar.current.date(from:cal_comp)!
    cal_comp = getCalComp(date:calen)
    sequence += getCalendar(components:cal_comp)
    if i == 1 { header_y += "\(cal_comp.year!)" }
    header_m[i] = "\(cal_comp.month!)月"
    cal_comp.month!+=1
}
var length: Int
if flag_m == 3 {
    length = (65 - header_y.characters.count) / 2
    for var i in 0..<length+1 {
        header_y = " " + header_y
    }
    print("\(header_y)\n")
}
for var l in 0..<flag_y {
    if flag_m == 3 {
        for var i in 0..<flag_m {
            length = (21 - (header_m[i + 3 * l].characters.count + je_flag)) / 2
            for var j in 0..<length {
                header_m[i + 3 * l] = " " + header_m[i + 3 * l]
            }
            length = 22 - (header_m[i + 3 * l].characters.count + je_flag)
            for var j in 0..<length {
                header_m[i + 3 * l] = header_m[i + 3 * l] + " "
            }
            header += header_m[i + 3 * l]
        }
    } else {
    header = "\(header_m[0]) \(header_y)"
    length = (21 - (header.characters.count + je_flag)) / 2
    for var j in 0..<length {
        header = " " + header
    }
}
    print(header)
    header = ""
    for var i in 0..<7 {
        for var j in 0..<flag_m {
            for var k in 0..<7 {
                print("\(sequence[i * 7 + ((j + 3 * l) * 49 + k)]) ", terminator:"")
            }
            print(" ", terminator:"")
        }
        print("")
    }
}

33, 34行目に指定する年月のデータを格納する変数を用意します。そして41から43行目または47から49行目で指定する年または月を代入します。このとき引数の型は文字列になっているので、これを”Int()!”で整数型に変換しています。

最後に59から61行目および65から67行目で条件判定し、0以外の値が指定されていれば年または月を強制的に書き換えて任意のカレンダーを表示できるようにしています。

calendar2.swift実行結果

ただし、以下の2点の不具合があります。

  1. 現時点より263年前の計算結果がcalのものと異なる
  2. 月指定が1から12以外でも計算してしまう

1番目の内容はNSCalendarの制約と思われます。2番目のものは今年の1月を起点に指定された月数を進んだり戻ったりした結果を返すので、計算自体は正しいんですが、感覚的に変です。他にもエラー処理を怠っているので、そのうち何とかしましょう。