Hello~! ミョウガですっ!
Twitterでタイムラインを眺めていたら、「プロ生ちゃん #カレンダープログラミング プチコンテスト 2014」の記事を見つけ、内容に興味が湧いてきたので、わたしもそれに参加することにしました。
1. 言語は何にしよう
応募要件は
- プログラミング言語は自由(既に応募がある言語でも OK)
- コードを実行した当月の日曜始まりのカレンダーを出力する
- 出力形式はサンプルを参考に、細かい点は自由
の3つなので、わたしはよく使っているC#でやってみることにしました。プロジェクトはコンソールアプリでいきます。
2. C#でカレンダーを出力してみよう
C#には、日付と時刻を扱うDateTime型という便利な構造体が.NET Frameworkの標準ライブラリとして用意されています。これを使ってコーディングしてみます。
using System;
namespace Myoga1012_Cal {
class Program {
static void Main( string[] args ) {
// 現在の日付を取得し、当月1日を表すインスタンスを生成します。
DateTime now = DateTime.Today;
DateTime day = new DateTime( now.Year, now.Month, 1 );
// 1日の曜日に合わせてオフセットします。
for( int i = 0; i < ( int )day.DayOfWeek; i++ ) Console.Write( " " );
// カレンダーを出力します。
do {
// 日付を出力します(最大2桁なので、最小フィールド幅を3と指定し、右寄せかつ日付間にスペースを開けます)。
Console.Write( "{0, 3}", day.Day );
// dayが土曜日または月末日であれば、改行します。
if( day.DayOfWeek == DayOfWeek.Saturday ||
day.Day == DateTime.DaysInMonth( now.Year, now.Month ) ) Console.WriteLine();
// dayを1日分進めて、月が変わるまで繰り返します。
} while( ( day = day.AddDays( 1.0 ) ).Month == now.Month );
}
}
}
なお、このプログラムはhttps://gist.github.com/Nia-TN1012/51c59f7cb6661544eee6549f454851b9でも公開されています(※GitHubアカウントの統合のため、ニア側のGistに移動しました)。
(追記:最新版は「Calendar.csを繰り返し文を1つに纏めてみました」にある「Calendar2.cs(GitHub内: Calendar.cs)」です。)
手順としては、DateTime.Todayプロパティで現在の日付を取得し、そこから当月1日を表すインスタンスを生成して、1日の位置のオフセットを行い、AddDaysメソッドで1日進めつつ、コンソール画面に日付を出力します。
※AddDaysメソッドは現在のインスタンス自体の値を変更するのではなく、結果を新しいインスタンスとして返します。従ってdayを1日進めるには、dayにday.AddDays( 1.0 )の戻り値を代入します。
参考 : DateTime.Addメソッド | MSDNライブラリ
12行目の繰り返し条件判定に指定しているDayOfWeekプロパティの戻り値は、DayOfWeek列挙体なのでint型にキャストします。なお、DayOfWeekの列挙子は日曜日が0、月曜日が1、・・・と定義されています(例えば2014年10月1日は水曜日、すなわち3です)。
17行目のコンソール画面への出力で、最小3桁のフィールド幅になるように書式指定しています。日付の値が最大2桁なので、1文字スペースを空けつつ、1~9日は1の位の位置に右寄せすることができます。
19~20行目の条件式で、dayが土曜日または月末日の時に改行されます。月末日の取得には指定した年月の日数を取得するDaysInMonthメソッドを利用します。
このソースコードを実行すると、以下のような結果になります。
3. おわりに
今回は1日からAddDaysメソッドで進めつつ、Monthプロパティで繰り返し条件判定を行いました。
他にも1日目のDayOfWeekプロパティの値とDayInMonthメソッドの戻り値を併用して、for文などで日付を出力する手もあります。
わたしとしては、せっかくの機会だから、他の言語でもチャレンジしてみようと思います。
Extra
Calendar.csにて、23行目の繰り返し条件判定を以下の式にすると、正しく動作しません。
( day = day.AddDays( 1.0 ) ).Day <= DateTime.DaysInMonth( now.Year, now.Month )
dayが月末の時にAddDaysメソッドで1日進めると、翌月1日を表すインスタンスが返ってくるため、代入後のday.Dayの値はDaysInMonthメソッドの戻り値を超えず、無限ループになってしまいます。
但し、現在の月が2、4、6、9、11月の時は、翌月の28・29日(2月)、30日(4、6、9、11月)の出力後の判定でday.Dayの値はDaysInMonthメソッドの戻り値を超えるため、約2か月分つながったカレンダーが出力されます。
[END]
コメント