はじめに
DateTimeのAddMonthsで月末の日に月を加算すると、
- 加算後の日付が月内を超える場合は月末の日に丸められ、(1/31(月末)→2/28(丸め)等)
- 月内を超えない場合は加算前と同日を維持するように、(2/28(月末)→3/28(同日、非月末)等)
月が加算されます。
C#のDateTime型のAddMonthsの動作を実測した結果:
ここでは、C#のDateTime型のAddMonthsに代えて、月末の日から月を加算した時に、加算後も月末となるように月を加算する関数を自作してみます。
処理方法
- ExtensionMethodsとして、
AddMonths
関数を自作。public static DateTime AddMonths(this DateTime t1, int n_M, bool keep_last = false)
- 引数
keep_last
にtrue
を指定すると、月末の日から月を加算した時に、加算後も月末となる。 - 1日進めることで月末かどうかを判定して、(
t1.AddDays(1).Day == 1
)、月末の時は、1日進めた状態で月を加算し、最後に1日戻す。(t1.AddDays(1).AddMonths(n_M).AddDays(-1)
)
コード:
// 月を加算(月末の日であれば加算後も月末となるような加算)
public static DateTime AddMonths(this DateTime t1, int n_M,
bool keep_last = true) { // T:月末の日であれば次の月末までを1ヵ月として月数を算出
if (!keep_last)
return t1.AddMonths(n_M); // 標準の月加算
var t_1d = t1.AddDays(1);
var is_last = t_1d.Day == 1; // 月末か?
if (!is_last)
return t1.AddMonths(n_M); // 標準の月加算
// if: 月末の時
return t_1d.AddMonths(n_M).AddDays(-1); // 月末を維持して月加算
}
テストコード
Program 2301-2 AddMonthsの月末丸め動作テスト.cs
using System;
namespace ConsoleApp1 {
class Program {
static void Main(string[] args) {
// sec: DateTimeのAddMonths
/* 結果:
DateTimeのAddMonthsで月末の日にNヵ月を加算すると、
加算後の日付が月内を超える場合は月末の日に丸められ(1/31(月末)→2/28(丸め)等)、
月内を超えない場合は加算前と同日を維持する(2/28(月末)→3/28(同日、非月末)等)
2023/02/28 0:00:00
2023/03/31 0:00:00
2023/03/28 0:00:00
2023/05/30 0:00:00
2023/05/31 0:00:00
*/
Func<string, DateTime> DT = DateTime.Parse;
Console.WriteLine($"{DT("2023/01/31").AddMonths(1)}");
Console.WriteLine($"{DT("2023/01/31").AddMonths(2)}");
Console.WriteLine($"{DT("2023/02/28").AddMonths(1)}");
Console.WriteLine($"{DT("2023/04/30").AddMonths(1)}");
Console.WriteLine($"{DT("2023/01/31").AddMonths(4)}");
// sec: AddMonthsを拡張
/* 結果:
月末の日であれば加算後も月末となるように月を加算(1/31(月末)→2/28(丸め)、2/28(月末)→3/31(月末)等)
2023/02/28 0:00:00
2023/03/31 0:00:00
2023/03/31 0:00:00
2023/05/31 0:00:00
2023/05/31 0:00:00
*/
Console.WriteLine($"{DT("2023/01/31").AddMonths(1, keep_last: true)}");
Console.WriteLine($"{DT("2023/01/31").AddMonths(2, keep_last: true)}");
Console.WriteLine($"{DT("2023/02/28").AddMonths(1, keep_last: true)}");
Console.WriteLine($"{DT("2023/04/30").AddMonths(1, keep_last: true)}");
Console.WriteLine($"{DT("2023/01/31").AddMonths(4, keep_last: true)}");
}
}
public static class ExtensionMethods {
// 月を加算(月末の日であれば加算後も月末となるような加算)
public static DateTime AddMonths(this DateTime t1, int n_M,
bool keep_last = false) { // T:月末の日であれば月加算後も月末となる
if (!keep_last)
return t1.AddMonths(n_M); // 標準の月加算
var t_1d = t1.AddDays(1);
var is_last = t_1d.Day == 1; // 月末か?
if (!is_last)
return t1.AddMonths(n_M); // 標準の月加算
// if: 月末の時
return t_1d.AddMonths(n_M).AddDays(-1); // 月末を維持して月加算
}
}
}
環境
Microsoft Visual Studio Community 2019 Version 16.11.22
VisualStudio.16.Release
Microsoft .NET Framework
Version 4.8.04084