Abrufen des ersten und letzten Tages eines Monats mithilfe eines bestimmten DateTime-Objekts

196

Ich möchte den ersten und letzten Tag des Monats abrufen, an dem ein bestimmtes Datum liegt. Das Datum stammt von einem Wert in einem UI-Feld.

Wenn ich einen Zeitwähler benutze, könnte ich sagen

var maxDay = dtpAttendance.MaxDate.Day;

Aber ich versuche es von einem DateTime-Objekt zu bekommen. Also wenn ich das habe ...

DateTime dt = DateTime.today;

Wie komme ich zum ersten und letzten Tag des Monats dt?

CAD
quelle
Es ist nicht klar, was Sie fragen. In der _DateVariablen ist ein einzelner Wert gespeichert . Welche "Min und Max" versuchen Sie von diesem Wert zu bekommen?
David
Es wird herabgestimmt, weil sich die Leute fragen, warum Sie so etwas denken wollen und wo Sie so etwas verwenden würden. Sie erzählen uns hier nichts über Ihre erste Ausgabe
Mo Patel
Es ist besser zu fragen, was du machen willst? nicht so Wie willst du das machen? Möglicherweise kann eine andere Verwendung Sie richtig vorschlagen.
Shell
2
@Chathuranga Du weißt, was das Mindestdatum eines jeden Monats sein wird ... aber die Frage ist, was das letzte Datum des aktuellen Monats ist. Du kannst so werden. Addiere 1 Monat zum aktuellen Datum und minus 1 Tag davon Datum .. jetzt erhalten Sie das letzte Datum Ihres aktuellen Monats
Shell

Antworten:

472

DateTimeStruktur speichert nur einen Wert, keinen Wertebereich. MinValueund MaxValuesind statische Felder, die einen Bereich möglicher Werte für Instanzen der DateTimeStruktur enthalten. Diese Felder sind statisch und beziehen sich nicht auf eine bestimmte Instanz von DateTime. Sie beziehen sich auf den DateTimeTyp selbst.

Empfohlene Lektüre: statisch (C # -Referenz)

UPDATE: Monatsspanne abrufen:

DateTime date = ...
var firstDayOfMonth = new DateTime(date.Year, date.Month, 1);
var lastDayOfMonth = firstDayOfMonth.AddMonths(1).AddDays(-1);
Sergey Berezovskiy
quelle
16
Ich weiß, dass ich hier wählerisch bin, sollte es aber nicht lastDayofMonthsein firstDayOfMonth.AddMonths(1).AddSeconds(-1);?
Karl Gjertsen
36
@KarlGjertsen Sie sind nicht wählerisch genug :) Perfekte Lösung wird sein AddTicks(-1), aber wenn wir uns nicht um Zeitteil kümmern und nur um Datumsteil denken, dann funktionieren Tage gut
Sergey Berezovskiy
7
Das ist wählerisch! ;-) Die Frage sagt nicht aus, wie die Werte verwendet werden sollen, daher neige ich dazu, defensiv zu codieren.
Karl Gjertsen
@SergeyBerezovskiy Ich würde diesen Punkt gerne ansprechen, aber verlieren Sie nicht die Zeitzoneninformationen, wenn Sie eine solche DateTime neu erstellen? Alle Zeitzoneninformationen, die an die ursprüngliche DateTime-Instanz angehängt wurden, gehen verloren, wenn Sie eine neue Instanz wie diese erstellen.
Marko
2
@KarlGjertsen, du willst wählerisch sehen ... das mache ich persönlich < firstDayOfNextMonthstatt <= lastDayOfMonth. Auf diese Weise funktioniert es immer, unabhängig von der Granularität. (Ich bin sicher, Zecken werden in Ordnung sein, aber wer weiß, was die Zukunft bringt ... Nanoticks?)
Adam0101
99

Dies ist eher ein langer Kommentar zu den Antworten von @Sergey und @ Steffen. Nachdem ich in der Vergangenheit selbst ähnlichen Code geschrieben hatte, entschied ich mich zu überprüfen, was am performantesten war, während ich mich daran erinnerte, dass Klarheit ebenfalls wichtig ist.

Ergebnis

Hier ist ein Beispiel für ein Testergebnis für 10 Millionen Iterationen:

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

Code

Ich habe LINQPad 4 (im C # -Programmmodus) verwendet, um die Tests mit aktivierter Compileroptimierung auszuführen. Hier ist der getestete Code, der aus Gründen der Klarheit und Bequemlichkeit als Erweiterungsmethode berücksichtigt wird:

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

}

Analyse

Einige dieser Ergebnisse haben mich überrascht.

Obwohl nicht viel drin ist, FirstDayOfMonth_AddMethodwar das etwas schneller als FirstDayOfMonth_NewMethodin den meisten Testläufen. Ich denke jedoch, dass Letzteres eine etwas klarere Absicht hat, und deshalb bevorzuge ich das.

LastDayOfMonth_AddMethodwar ein klarer Verlierer gegen LastDayOfMonth_AddMethodWithDaysInMonth, LastDayOfMonth_NewMethodund LastDayOfMonth_NewMethodWithReuseOfExtMethod. Zwischen den schnellsten drei ist nicht viel drin und es kommt auf Ihre persönlichen Vorlieben an. Ich wähle die Klarheit LastDayOfMonth_NewMethodWithReuseOfExtMethodmit der Wiederverwendung einer anderen nützlichen Erweiterungsmethode. IMHO ist seine Absicht klarer und ich bin bereit, die geringen Leistungskosten zu akzeptieren.

LastDayOfMonth_SpecialCaseAngenommen, Sie geben den ersten des Monats in dem speziellen Fall an, in dem Sie dieses Datum möglicherweise bereits berechnet haben, und es verwendet die Add-Methode mit DateTime.DaysInMonth, um das Ergebnis zu erhalten. Dies ist schneller als die anderen Versionen, wie Sie es erwarten würden, aber wenn Sie nicht dringend Geschwindigkeit brauchen, sehe ich keinen Sinn darin, diesen Sonderfall in Ihrem Arsenal zu haben.

Fazit

Hier ist eine Erweiterungsmethodenklasse mit meinen Auswahlmöglichkeiten und in allgemeiner Übereinstimmung mit @Steffen glaube ich:

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

Wenn Sie so weit gekommen sind, danke für die Zeit! Es hat Spaß gemacht: ¬). Bitte kommentieren Sie, wenn Sie weitere Vorschläge für diese Algorithmen haben.

WooWaaBob
quelle
5
Sie haben jedoch viel zu wenig Anerkennung für Ihre Bemühungen. Es ist nützlich!
Dion V.
2
Danke @DionV. - Es ist schön, geschätzt zu werden! Kurze Antworten sind großartig, wenn Sie es eilig haben, aber ich denke, eine tiefere Analyse ist oft nützlich.
WooWaaBob
Sie haben eine andere Alternative verpasst: LastDayOfMonth_AddMethod_SpecialCase(oder so ähnlich). Ich erwarte den ersten Tag des Monats als Parameter und denke, der schnellste sollte sein, was er LastDayOfMonth_AddMethodtut! Das wäre also so einfach wie:return value.AddMonths(1).AddDays(-1);
Andrew
1
Danke @Andrew und hier sind meine Ergebnisse, die das verwenden: 2835 ms für LastDayOfMonth_SpecialCase (), und; 4685 ms für LastDayOfMonth_AddMethod_SpecialCase (). Dies ist wahrscheinlich sinnvoll, wenn man die Erstellungszeit von Strukturen berücksichtigt und die interne Darstellung von DateTime das Hinzufügen von Tagen zu einer einfachen Operation macht, das Hinzufügen von Monaten jedoch zu einem komplexeren Algorithmus.
WooWaaBob
15

Abrufen der Monatsreichweite mit der .Net-API (nur eine andere Möglichkeit):

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));
Steffen Mangold
quelle
6

" Last day of month" ist eigentlich "First day of *next* month, minus 1 ". Also hier ist, was ich benutze, keine Notwendigkeit für "DaysInMonth" -Methode:

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

HINWEIS: Der Grund, den ich hier verwende AddMinutes(-1), AddDays(-1)ist, dass Sie normalerweise diese Datumsfunktionen für benötigen Berichterstellung für einen bestimmten Zeitraum Wenn Sie einen Bericht für einen bestimmten Zeitraum erstellen, sollte das "Enddatum" tatsächlich so etwas wie seinOct 31 2015 23:59:59 damit Ihr Bericht ordnungsgemäß funktioniert - einschließlich aller Daten vom letzten Tag des Monats.

Dh du bekommst tatsächlich den "letzten" Moment des Monats". Nicht am letzten Tag.

OK, ich werde jetzt die Klappe halten.

Jazzkatze
quelle
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));
sphaze
quelle
Vermeiden Sie im Allgemeinen nur Code-Antworten. Fügen Sie ein hinzu description, das Ihnen bei der Erläuterung Ihres Codes hilft. Danke
MickyD
3

Hier können Sie einen Monat für den ersten Tag des aktuellen Monats hinzufügen, als 1 Tag von diesem Tag zu löschen.

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

Wenn Sie sich nur um das Datum kümmern

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

Wenn Sie Zeit sparen möchten

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);
Vitaly
quelle
Es wird im Dezember komplett scheitern, dudeeeeeee. Es wird versucht, datetime mit dem Monat "13" zu erstellen und die Ausnahme auszulösen, dass es kein solches Datum gibt.
Pawel
Seit wann ist der 13. Dezember? Es gibt insgesamt 12 Monate. Welchen Kalender verwenden Sie?
Vitaly
Wenn Ihr Datum Dezember ist, wird versucht, einen Monat hinzuzufügen, was zu einer Ausnahme führt. new DateTime (date.Year, 12+ 1, 1, 0, 0, 0, date.Kind) .AddDays (-1); Das Abziehen eines Tages davon erfolgt nach dem Erstellen von datetime, sodass es im Dezember fehlschlägt, wenn das Datum für den Monat "13" versucht wird. Du kannst es versuchen.
Pawel
1

Die hier akzeptierte Antwort berücksichtigt nicht die Art der DateTime-Instanz. Wenn Ihre ursprüngliche DateTime-Instanz beispielsweise eine UTC-Art war, erstellen Sie durch Erstellen einer neuen DateTime-Instanz eine Instanz unbekannter Art, die dann basierend auf den Servereinstellungen als Ortszeit behandelt wird. Daher ist der richtige Weg, um das erste und letzte Datum des Monats zu erhalten, folgender:

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

Auf diese Weise bleibt die ursprüngliche Art der DateTime-Instanz erhalten.

Marko
quelle
1

Probier diese:

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

Ich habe dies in meinem Skript verwendet (funktioniert für mich), aber ich brauchte ein vollständiges Datum, ohne es nur auf das Datum und keine Uhrzeit zuschneiden zu müssen.

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

Probieren Sie es aus. Es berechnet im Grunde die Anzahl der Tage, die vergangen sind DateTime.Now, subtrahiert dann einen davon und verwendet den neuen Wert, um den ersten des aktuellen Monats zu finden. Von dort verwendet es das DateTimeund verwendet .AddMonths(-1), um den ersten des Vormonats zu erhalten.

Das Abrufen des letzten Tages des letzten Monats bewirkt im Grunde dasselbe, außer dass die Anzahl der Tage im Monat um eins erhöht und dieser Wert abgezogen wird DateTime.Now.AddDays, sodass Sie den letzten Tag des vorherigen Monats erhalten.

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);
Carl Perumal
quelle
0

Für die persische Kultur

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);
Mohammad Daliri
quelle
0

Du kannst es schaffen

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

einfache Möglichkeit, es zu tun

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();
David Ferreira
quelle
Dieser Code wird wegen "new DataFim.Text" nicht kompiliert.
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)));
Shubham Batra
quelle