it-swarm.com.de

Abrufen des ersten und letzten Tages eines Monats mit einem bestimmten DateTime-Objekt

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

Wenn ich einen Time Picker verwende, 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 bekomme ich den ersten Tag und den letzten Tag des Monats von dt?

149
CAD

DateTime structure speichert nur einen Wert, nicht einen Wertebereich. MinValue und MaxValue sind statische Felder, die einen Bereich möglicher Werte für Instanzen von DateTime Struktur enthalten. Diese Felder sind statisch und beziehen sich nicht auf eine bestimmte Instanz von DateTime. Sie beziehen sich auf den DateTime-Typ selbst.

Vorgeschlagene Lektüre: static (C # Reference)

UPDATE: Monatsbereich abrufen:

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

Dies ist mehr ein langer Kommentar zu den Antworten von @Sergey und @ Steffen. Nachdem ich in der Vergangenheit einen ähnlichen Code selbst geschrieben hatte, beschloss ich, das zu überprüfen, was am meisten performant war, während ich daran erinnerte, dass Klarheit auch wichtig ist.

Ergebnis

Hier ein Beispiel für einen Testlauf 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 Compiler-Optimierung auszuführen. Hier ist der getestete Code aus Gründen der Übersichtlichkeit und Benutzerfreundlichkeit als Erweiterungsmethoden zusammengefasst:

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 dabei ist, war FirstDayOfMonth_AddMethod in den meisten Testläufen etwas schneller als FirstDayOfMonth_NewMethod. Ich denke jedoch, dass letzteres eine etwas klarere Absicht hat, und deshalb habe ich eine Vorliebe dafür.

LastDayOfMonth_AddMethod war ein klarer Verlierer gegen LastDayOfMonth_AddMethodWithDaysInMonth, LastDayOfMonth_NewMethod und LastDayOfMonth_NewMethodWithReuseOfExtMethod. Zwischen den schnellsten Drei ist nicht viel drin und so hängt es von Ihren persönlichen Vorlieben ab. Ich wähle die Klarheit von LastDayOfMonth_NewMethodWithReuseOfExtMethod mit der Wiederverwendung einer anderen nützlichen Erweiterungsmethode. IMHO ist seine Absicht klarer und ich bin bereit, die geringen Leistungskosten zu akzeptieren.

In LastDayOfMonth_SpecialCase wird davon ausgegangen, dass Sie in dem speziellen Fall, in dem Sie dieses Datum möglicherweise bereits berechnet haben, den ersten Monat angeben und die Methode add mit DateTime.DaysInMonth verwendet, um das Ergebnis zu erhalten. Das ist schneller als die anderen Versionen, wie Sie es erwarten würden, aber wenn Sie nicht unbedingt Geschwindigkeit brauchen, sehe ich nicht den Sinn, diesen speziellen Fall 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, vielen Dank für die Zeit! Es hat Spaß gemacht: ¬). Bitte kommentieren Sie, wenn Sie andere Vorschläge für diese Algorithmen haben.

71
WooWaaBob

Monatsumfang mit .Net API erhalten (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));
12
Steffen Mangold

"Last day of month" ist eigentlich "First day of *next* month, minus 1". Hier ist was ich verwende, 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, aus dem ich AddMinutes(-1) und nicht AddDays(-1) benutze, ist hier, weil Sie diese Datumsfunktionen normalerweise für reporting für einen bestimmten Zeitraum benötigen und wenn Sie einen Bericht für einen bestimmten Zeitraum erstellen, das "Enddatum" Eigentlich etwas wie Oct 31 2015 23:59:59, damit Ihr Bericht korrekt funktioniert - einschließlich aller Daten vom letzten Tag des Monats.

Das heißt Sie erhalten hier tatsächlich den "letzten Moment des Monats". Nicht letzter Tag.

OK, ich werde jetzt den Mund halten.

4
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

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

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

Wenn Sie sich nur für das Datum interessieren 

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 wollen 

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

Die hier akzeptierte Antwort berücksichtigt nicht die Art der DateTime-Instanz. Wenn Ihre ursprüngliche DateTime-Instanz beispielsweise eine UTC-Kind-Instanz war, erstellen Sie eine neue DateTime-Instanz, die eine Unknown-Kind-Instanz erstellt, die dann als Ortszeit basierend auf den Servereinstellungen behandelt wird. Daher ist der richtige Weg, um das erste und letzte Datum des Monats zu ermitteln, Folgendes:

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.

1
Marko

Ich habe dies in meinem Skript verwendet (funktioniert für mich), aber ich brauchte ein vollständiges Datum, ohne es auf das Datum und keine Uhrzeit einstellen 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);
}
1
Maarten Frouws

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

Probier diese:

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