LoginSignup
0
0

More than 1 year has passed since last update.

C#のDateTime型のAddMonthsで、月末の日から月を加算した時に、加算後も月末となるように月を加算する

Last updated at Posted at 2023-01-29

はじめに

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_lasttrueを指定すると、月末の日から月を加算した時に、加算後も月末となる。
  • 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
image.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0