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


196

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

タイムピッカーを使用している場合は、

var maxDay = dtpAttendance.MaxDate.Day;

しかし、DateTimeオブジェクトから取得しようとしています。だからこれがあれば...

DateTime dt = DateTime.today;

月の初日と末日を取得する方法はdt


あなたが何を求めているのか明確ではありません。_Date変数には単一の値が格納されています。その値から何を取得しようとしていますか?
David

人々がなぜあなたがそのような考えをしたいのか、そしてあなたがそのようなことをどこで使うのか疑問に思っているので、それは反対投票になっています。あなたはここであなたの最初の問題について何も話していない
Mo Patel

あなたが何をしたいのか尋ねるほうがいいですか?あなたどうしたいですか?他の用途があなたを正しく示唆するかもしれません。
シェル

2
@Chathuranga uは、任意の月の最小日付が何であるかを知っています....しかし、問題は、現在の月の最後の日付は何ですか.. uは、このように取得できます。 date ..今、
シェル

回答:


472

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

推奨される読み物:静的(C#リファレンス)

更新:月の範囲を取得しています:

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

16
私はここでうるさいことを知っていますが、そうすべきではありませlastDayofMonthfirstDayOfMonth.AddMonths(1).AddSeconds(-1);か?
Karl Gjertsen、2016年

36
@KarlGjertsenあなたは十分にうるさくありません:)完璧な解決策はですがAddTicks(-1)、時間の部分を気にせず、日付の部分だけを考えれば、日はうまくいきます
セルゲイベレゾフスキー

7
今はうるさいです!;-)質問は値がどのように使用されるのかを述べていないので、私は防御的にコーディングする傾向があります。
Karl Gjertsen、2016年

@SergeyBerezovskiyこの点を上げるのは嫌いですが、このようなDateTimeを新しく作成すると、タイムゾーン情報が失われませんか?このような新しいインスタンスを作成すると、元のDateTimeインスタンスにアタッチされていたタイムゾーン情報はすべて失われます。
マルコ

2
@KarlGjertsen、あなたはうるさいを見たいです...私は個人的に< firstDayOfNextMonth代わりにしてい<= lastDayOfMonthます。そうすれば、粒度に関係なく常に機能します。(ティックは大丈夫だと確信していますが、未来が何をもたらすのか誰が知っています...ナノティック?)
adam0101

99

これは、@ Sergeyと@Steffenの回答に対するより長いコメントです。過去に自分でも同様のコードを書いたことがあるので、わかりやすさも重要であることを思い出しながら、最もパフォーマンスの高いものを確認することにしました。

結果

以下は、1,000万回の反復のテスト実行結果の例です。

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_AddMethodよりもわずかに高速FirstDayOfMonth_NewMethodでした。ただし、後者の方がやや明確な意図があるため、私はそれを好みます。

LastDayOfMonth_AddMethod明確な敗者だったLastDayOfMonth_AddMethodWithDaysInMonthLastDayOfMonth_NewMethodLastDayOfMonth_NewMethodWithReuseOfExtMethod。最速の3つの間には何もないので、個人の好みによって決まります。LastDayOfMonth_NewMethodWithReuseOfExtMethod別の便利な拡張メソッドを再利用して、の明確さを選択します。私見はその意図がより明確であり、私は小さなパフォーマンスコストを受け入れても構わないと思っています。

LastDayOfMonth_SpecialCase は、その日付をすでに計算している可能性がある特別な場合に月の最初の日を提供し、addメソッドを DateTime.DaysInMonth、結果を取得するために。予想通り、これは他のバージョンよりも高速ですが、スピードを切実に必要としない限り、この特殊なケースを武器に持つ意味はわかりません。

結論

以下は、私の選択を含む拡張メソッドクラスであり、@ 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());
    }
}

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


5
しかし、あなたの努力に対するクレジットは少なすぎます。便利です!
Dion V.

2
@DionVに感謝します。-感謝されてうれしいです!急いでいるときは短い答えがいいですが、私は従うべきいくつかのより深い分析がしばしば役立つと思います。
WooWaaBob

別の選択肢を見逃しました:(LastDayOfMonth_AddMethod_SpecialCaseまたはそのようなもの)。パラメータとして月の最初の日を期待して、私は何が何をすべきかを最も速くすべきだと思いますLastDayOfMonth_AddMethod!:それはのようにシンプルになりそうreturn value.AddMonths(1).AddDays(-1);
アンドリュー

1
@Andrewに感謝し、これを使用した私の結果を次に示します。LastDayOfMonth_SpecialCase()で2835ミリ秒、そして; LastDayOfMonth_AddMethod_SpecialCase()の場合は4685ミリ秒。これは、構造体の作成時間を考慮するとおそらく意味があり、DateTimeの内部表現は、おそらく日を追加することを単純な操作にしますが、月を追加することは、より複雑なアルゴリズムになります。
WooWaaBob 2016

15

.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));

6

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
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));

通常、コードのみの回答は避けてください。descriptionコードの説明に役立つを追加することを検討してください。ありがとう
MickyD 2015年

3

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

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

2

日付だけ気にするなら

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);

12月dudeeeeeeeで完全に失敗します。月「13」の日付時刻を作成し、そのような日付がないという例外をスローします。
Pawel

12月は13日ですか?合計12か月あります。どのカレンダーを使用していますか?
Vitaly

日付が12月の場合、1か月追加され、例外が発生します。新しいDateTime(date.Year、12+ 1、1、0、0、0、date.Kind).AddDays(-1); datetimeが作成された後に1日を減算するため、12月の場合、月「13」の日付を試行すると失敗します。あなたはそれを試すことができます。
Pawel

1

ここで受け入れられた回答は、DateTimeインスタンスの種類を考慮していません。たとえば、元のDateTimeインスタンスがUTCの種類であった場合、新しいDateTimeインスタンスを作成することで、不明な種類のインスタンスを作成し、サーバーの設定に基づいてローカル時間として処理されます。したがって、月の最初と最後の日付を取得するより適切な方法は次のとおりです。

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

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


1

これを試してください:

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

1

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

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

1

これを試してみてください。基本的には、経過した日数を計算し、その日数DateTime.Nowから1を引いて、新しい値を使用して現在の月の最初の日を見つけます。そこからそれを使用し、前の月の最初を取得するためにDateTime使用.AddMonths(-1)します。

先月の最終日を取得することは基本的に同じことですが、月の日数に1を加え、その値をから差し引いて、前月DateTime.Now.AddDaysの最終日を与えます。

int NumberofDays = DateTime.Now.Day;
int FirstDay = NumberofDays - 1;
int LastDay = NumberofDays + 1;
DateTime FirstofThisMonth = DateTime.Now.AddDays(-FirstDay);
DateTime LastDayOfLastMonth = DateTime.Now.AddDays(-LastDay);
DateTime CheckLastMonth = FirstofThisMonth.AddMonths(-1);

0

ペルシャ文化のために

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

できます

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

-1

それを行う簡単な方法

Begin = new DateTime(DateTime.Now.Year, DateTime.Now.Month,1).ToShortDateString();
End = new DataFim.Text = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.DaysInMonth(DateTime.Now.Year, DateTime.Now.Month)).ToShortDateString();

「新しいDataFim.Text」のため、このコードはコンパイルされません。
Wazner

-1
DateTime dCalcDate = DateTime.Now;
var startDate = new DateTime(Convert.ToInt32(Year), Convert.ToInt32(Month), 1);
var endDate = new DateTime(Convert.ToInt32(Year), Convert.ToInt32(Month), DateTime.DaysInMonth((Convert.ToInt32(Year)), Convert.ToInt32(Month)));
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.