web-dev-qa-db-ja.com

特定のDateTimeオブジェクトを使用して、月の最初と最後の日を取得する

特定の日付が含まれる月の最初の日と最後の日を取得したい。日付はUIフィールドの値から取得されます。

タイムピッカーを使用しているのであれば、

var maxDay = dtpAttendance.MaxDate.Day;

しかし、DateTimeオブジェクトから取得しようとしています。だから私はこれを持っているなら...

DateTime dt = DateTime.today;

dtから月の最初の日と最後の日を取得するにはどうすればいいですか?

159
CAD

DateTime 構造体は、値の範囲ではなく、値を1つだけ格納します。 MinValueMaxValueは静的フィールドで、DateTime構造体のインスタンスに取り得る値の範囲を保持します。これらのフィールドは静的であり、特定のDateTimeのインスタンスには関連しません。それらはDateTime型そのものに関連しています。

推奨読書: static(C#リファレンス)

更新:月の範囲を取得する:

DateTime date = ...
var firstDayOfMonth = new DateTime(date.Year, date.Month, 1);
var lastDayOfMonth = firstDayOfMonth.AddMonths(1).AddDays(-1);
400

これは@Sergeyと@ Steffenの回答に対するより長いコメントです。過去に自分自身で同じようなコードを書いてきたので、明快さも重要であることを思い出しながら、私は 最もパフォーマンスの高い ものをチェックすることにしました。

結果

これは1000万回の反復のテスト実行結果の例です。

2257 ms for FirstDayOfMonth_AddMethod()
2406 ms for FirstDayOfMonth_NewMethod()
6342 ms for LastDayOfMonth_AddMethod()
4037 ms for LastDayOfMonth_AddMethodWithDaysInMonth()
4160 ms for LastDayOfMonth_NewMethod()
4212 ms for LastDayOfMonth_NewMethodWithReuseOfExtMethod()
2491 ms for LastDayOfMonth_SpecialCase()

コード

私は LINQPad 4 (C#プログラムモードで)を使用して、コンパイラ最適化を有効にしてテストを実行しました。明快さと便利さのために拡張メソッドとして因数分解されたテスト済みのコードは、次のとおりです。

public static class DateTimeDayOfMonthExtensions
{
    public static DateTime FirstDayOfMonth_AddMethod(this DateTime value)
    {
        return value.Date.AddDays(1 - value.Day);
    }

    public static DateTime FirstDayOfMonth_NewMethod(this DateTime value)
    {
        return new DateTime(value.Year, value.Month, 1);
    }

    public static DateTime LastDayOfMonth_AddMethod(this DateTime value)
    {
        return value.FirstDayOfMonth_AddMethod().AddMonths(1).AddDays(-1);
    }

    public static DateTime LastDayOfMonth_AddMethodWithDaysInMonth(this DateTime value)
    {
        return value.Date.AddDays(DateTime.DaysInMonth(value.Year, value.Month) - value.Day);
    }

    public static DateTime LastDayOfMonth_SpecialCase(this DateTime value)
    {
        return value.AddDays(DateTime.DaysInMonth(value.Year, value.Month) - 1);
    }

    public static int DaysInMonth(this DateTime value)
    {
        return DateTime.DaysInMonth(value.Year, value.Month);
    }

    public static DateTime LastDayOfMonth_NewMethod(this DateTime value)
    {
        return new DateTime(value.Year, value.Month, DateTime.DaysInMonth(value.Year, value.Month));
    }

    public static DateTime LastDayOfMonth_NewMethodWithReuseOfExtMethod(this DateTime value)
    {
        return new DateTime(value.Year, value.Month, value.DaysInMonth());
    }
}

void Main()
{
    Random rnd = new Random();
    DateTime[] sampleData = new DateTime[10000000];

    for(int i = 0; i < sampleData.Length; i++) {
        sampleData[i] = new DateTime(1970, 1, 1).AddDays(rnd.Next(0, 365 * 50));
    }

    GC.Collect();
    System.Diagnostics.Stopwatch sw = System.Diagnostics.Stopwatch.StartNew();
    for(int i = 0; i < sampleData.Length; i++) {
        DateTime test = sampleData[i].FirstDayOfMonth_AddMethod();
    }
    string.Format("{0} ms for FirstDayOfMonth_AddMethod()", sw.ElapsedMilliseconds).Dump();

    GC.Collect();
    sw.Restart();
    for(int i = 0; i < sampleData.Length; i++) {
        DateTime test = sampleData[i].FirstDayOfMonth_NewMethod();
    }
    string.Format("{0} ms for FirstDayOfMonth_NewMethod()", sw.ElapsedMilliseconds).Dump();

    GC.Collect();
    sw.Restart();
    for(int i = 0; i < sampleData.Length; i++) {
        DateTime test = sampleData[i].LastDayOfMonth_AddMethod();
    }
    string.Format("{0} ms for LastDayOfMonth_AddMethod()", sw.ElapsedMilliseconds).Dump();

    GC.Collect();
    sw.Restart();
    for(int i = 0; i < sampleData.Length; i++) {
        DateTime test = sampleData[i].LastDayOfMonth_AddMethodWithDaysInMonth();
    }
    string.Format("{0} ms for LastDayOfMonth_AddMethodWithDaysInMonth()", sw.ElapsedMilliseconds).Dump();

    GC.Collect();
    sw.Restart();
    for(int i = 0; i < sampleData.Length; i++) {
        DateTime test = sampleData[i].LastDayOfMonth_NewMethod();
    }
    string.Format("{0} ms for LastDayOfMonth_NewMethod()", sw.ElapsedMilliseconds).Dump();

    GC.Collect();
    sw.Restart();
    for(int i = 0; i < sampleData.Length; i++) {
        DateTime test = sampleData[i].LastDayOfMonth_NewMethodWithReuseOfExtMethod();
    }
    string.Format("{0} ms for LastDayOfMonth_NewMethodWithReuseOfExtMethod()", sw.ElapsedMilliseconds).Dump();

    for(int i = 0; i < sampleData.Length; i++) {
        sampleData[i] = sampleData[i].FirstDayOfMonth_AddMethod();
    }

    GC.Collect();
    sw.Restart();
    for(int i = 0; i < sampleData.Length; i++) {
        DateTime test = sampleData[i].LastDayOfMonth_SpecialCase();
    }
    string.Format("{0} ms for LastDayOfMonth_SpecialCase()", sw.ElapsedMilliseconds).Dump();

}

分析

私はこれらの結果のいくつかに驚きました。

それほど多くはありませんが、テストのほとんどの実行でFirstDayOfMonth_AddMethodFirstDayOfMonth_NewMethodよりわずかに高速でした。しかし、私は後者がやや明確な意図を持っていると思うので、私はそれを好みます。

LastDayOfMonth_AddMethodLastDayOfMonth_AddMethodWithDaysInMonthLastDayOfMonth_NewMethodおよびLastDayOfMonth_NewMethodWithReuseOfExtMethodに対して明らかに敗者となった。最速の3つの間でそれには何もないので、それはあなたの個人的な好みに帰着します。私はLastDayOfMonth_NewMethodWithReuseOfExtMethodの明確さを他の便利な拡張方法の再利用と共に選択します。私見の意図はより明確であり、私は小さな実行費用を受け入れても構わないと思っています。

LastDayOfMonth_SpecialCaseは、あなたがすでにその日付を計算しているかもしれない特別な場合にあなたが月の最初を提供していると仮定します、そしてそれは結果を得るためにDateTime.DaysInMonthでaddメソッドを使います。あなたが予想するように、これは他のバージョンより速いです、しかし、あなたがスピードの絶望的な必要性にいない限り、私はあなたの兵器庫にこの特別なケースを持つという点を見ません。

結論

これは私が選択した拡張メソッドクラスで、@Steffenと一般的に同意したものです。

public static class DateTimeDayOfMonthExtensions
{
    public static DateTime FirstDayOfMonth(this DateTime value)
    {
        return new DateTime(value.Year, value.Month, 1);
    }

    public static int DaysInMonth(this DateTime value)
    {
        return DateTime.DaysInMonth(value.Year, value.Month);
    }

    public static DateTime LastDayOfMonth(this DateTime value)
    {
        return new DateTime(value.Year, value.Month, value.DaysInMonth());
    }
}

ここまで来たら、ありがとうございます。それは楽しかった:¬)。これらのアルゴリズムについて他に何か提案があればコメントしてください。

80
WooWaaBob

.NET APIで月の範囲を取得する(別の方法):

DateTime date = ...
var firstDayOfMonth = new DateTime(date.Year, date.Month, 1);
var lastDayOfMonth = new DateTime(date.Year, date.Month, DateTime.DaysInMonth(date.Year, date.Month));
13
Steffen Mangold

"Last day of month"は実際には "First day of *next* month, minus 1"です。だからここに私が使用しているものです、 "DaysInMonth"メソッドの必要はありません:

public static DateTime FirstDayOfMonth(this DateTime value)
{
    return new DateTime(value.Year, value.Month, 1);
}

public static DateTime LastDayOfMonth(this DateTime value)
{
    return value.FirstDayOfMonth()
        .AddMonths(1)
        .AddMinutes(-1);
}

注:ここではAddMinutes(-1)ではなくAddDays(-1)を使用するのは、通常、レポート作成のためにこれらの日付関数が必要なためです。ある期間のレポートを作成する場合、「終了日」は実際にはOct 31 2015 23:59:59のようにする必要があります。そうすれば、レポートは正しく機能します - 月の末日からのすべてのデータが含まれます。

すなわちあなたは実際にここで "月の最後の瞬間"を得ます。最後の日ではありません。

さて、私は今黙るつもりです。

5
jazzcat
DateTime dCalcDate = DateTime.Now;
dtpFromEffDate.Value = new DateTime(dCalcDate.Year, dCalcDate.Month, 1);
dptToEffDate.Value = new DateTime(dCalcDate.Year, dCalcDate.Month, DateTime.DaysInMonth(dCalcDate.Year, dCalcDate.Month));
4
sphaze

ここでは、当日から1日削除するよりも、今月の最初の日に1ヶ月を追加することができます。

DateTime now = DateTime.Now;
var startDate = new DateTime(now.Year, now.Month, 1);
var endDate = startDate.AddMonths(1).AddDays(-1);
3
Chirag Thakar

日付だけを気にするなら

var firstDay = new DateTime(date.Year, date.Month, 1, 0, 0, 0, date.Kind);
var lastDay = new DateTime(date.Year, date.Month, 1, 0, 0, 0, date.Kind).AddMonths(1).AddDays(-1);

時間を節約したい場合

var firstDay = new DateTime(date.Year, date.Month, 1, date.Hour, date.Minute, date.Second, date.Kind);
var lastDay = new DateTime(date.Year, date.Month, 1, date.Hour, date.Minute, date.Second, date.Kind).AddMonths(1).AddDays(-1);
2
Vitaly

ここで受け入れられている答えはDateTimeインスタンスの種類を考慮に入れていません。たとえば、元のDateTimeインスタンスがUTC Kindだった場合は、新しいDateTimeインスタンスを作成することでUnknown Kindインスタンスを作成し、それをサーバー設定に基づいた現地時間として扱います。したがって、月の最初と最後の日付を取得するためのより適切な方法は次のようになります。

var now = DateTime.UtcNow;
var first = now.Date.AddDays(-(now.Date.Day - 1));
var last = first.AddMonths(1).AddTicks(-1);

このようにして、元の種類のDateTimeインスタンスが保持されます。

1
Marko

私は自分のスクリプトでこれを使用しました(私にはうまくいきます)が、日付と時間なしにトリミングする必要のない完全な日付が必要でした。

public DateTime GetLastDayOfTheMonth()
{
    int daysFromNow = DateTime.DaysInMonth(DateTime.Now.Year, DateTime.Now.Month) - (int)DateTime.Now.Day;
    return DateTime.Now.AddDays(daysFromNow);
}
1
Maarten Frouws

ペルシャ文化のために

PersianCalendar pc = new PersianCalendar();            

var today = pc.GetDayOfMonth(DateTime.Now);
var firstDayOfMonth = pc.GetDayOfMonth(DateTime.Now.AddDays(-(today-1)));
var lastDayOfMonth = pc.GetDayOfMonth(DateTime.Now.AddMonths(1).AddDays(-today));            
Console.WriteLine("First day "+ firstDayOfMonth);
Console.WriteLine("Last day " + lastDayOfMonth);
0
Mohammad Daliri

これを試してください。

string strDate = DateTime.Now.ToString("MM/01/yyyy");
0
marai