地平線に行く

2017-04-19

各言語での「翌月1日」の求め方

02:13 |

C# で「翌月1日」の DateTime を作るのに、こんなコードを書いてしまいました。

DateTime today = DateTime.Today;
DateTime nextMonth =
    new DateTime(today.Year, today.Month + 1, 1);

結果、12月1日になったら new DateTime(2017, 13, 1) となってしまい、「System.ArgumentOutOfRangeException: Year、Month および Day パラメーターが表現できない DateTime を示しています。」 で落ちました。

適当なツールだったからよかったものの、本番のコードだったらと思うとぞっとします。

(日付のバグはテストで見つけにくいです…)


そこで、復習を兼ねて各言語ごとの「翌月1日の求め方」を確認してみました。

もっといい方法があるよ!って場合は教えてください\(^o^)/


C#の場合

AddMonths メソッドを使います。

DateTime today = DateTime.Today;
DateTime nextMonth =
    new DateTime(today.Year, today.Month, 1).AddMonths(1);

ちなみに、これを new DateTime(DateTime.Today.Year, DateTime.Today.Month, 1) って書くのはアウトです。

ほとんど起こらないぐらい極めててまれな確率ですが、第一引数の評価時と、第二引数の評価時で年をまたいだら日付がおかしくなるというバグになります。

現在時刻を処理するときは、変数に代入しておいたほうが安全です。


Java の場合

Date and Time API を使うと便利です。

 LocalDateTime nextMonth = 
     LocalDateTime.now()
                  .truncatedTo(ChronoUnit.DAYS)
                  .withDayOfMonth(1)
                  .plusMonths(1);

ちなみに、年月までで切り捨てる処理を truncatedTo(ChronoUnit.MONTHS) って書いたら、 ''java.time.temporal.UnsupportedTemporalTypeException: Unit is too large to be used for truncation'' でした。


JavaScript の場合

C#Java と異なり、範囲外の値を入れると繰り越し・繰り下げしてくれます。

なので、単純に加算するだけでオーケー。

let now = new Date();
let nextMonth =
    new Date(now.getFullYear(), now.getMonth() + 1, 1);

一番わかりやすいですが、最初にも書いたように C#Java ではだめなので要注意ですね…。

トラックバック - http://d.hatena.ne.jp/chiheisen/20170419/1492622015