Unterschied in Monaten zwischen zwei Daten


334

Wie berechnet man die Differenz in Monaten zwischen zwei Daten in C #?

Gibt es ein Äquivalent zur VB- DateDiff()Methode in C #? Ich muss einen Unterschied in Monaten zwischen zwei Daten feststellen, die Jahre voneinander entfernt sind. Die Dokumentation sagt, dass ich TimeSpanwie folgt verwenden kann :

TimeSpan ts = date1 - date2;

aber das gibt mir Daten in Tagen. Ich möchte diese Zahl nicht durch 30 teilen, da nicht jeder Monat 30 Tage beträgt und da die beiden Operandenwerte ziemlich weit voneinander entfernt sind, befürchte ich, dass das Teilen durch 30 einen falschen Wert ergibt.

Irgendwelche Vorschläge?


27
Definieren Sie "Unterschied in Monaten". Was ist der Unterschied in Monaten zwischen "1. Mai 2010" und "16. Juni 2010"? 1,5, 1 oder etwas anderes?
Cheng Chen

7
Oder, um diesen Punkt weiter zu betonen, was ist der Unterschied in den Monaten zwischen dem 31. Dezember 2010 und dem 1. Januar 2011? Abhängig von der Tageszeit kann dies eine Differenz von nur 1 Sekunde sein. Würden Sie dies als Differenz von einem Monat betrachten?
stakx - nicht mehr beitragen

Hier ist der einfache und kurze Code für den Fall, dass Sie immer noch keine Antwort erhalten konnten, siehe diesen POST stackoverflow.com/questions/8820603/…
wirol

11
Danny: 1 Monat und 15 Tage. stakx: 0 Monate und 1 Tag. Der Punkt ist, die Monatskomponente zu erhalten . Das scheint mir ziemlich offensichtlich und ist eine gute Frage.
Kirk Woll

Antworten:


462

Angenommen, der Tag des Monats ist irrelevant (dh der Unterschied zwischen 2011.1.1 und 2010.12.31 ist 1), wobei Datum1> Datum2 einen positiven Wert und Datum2> Datum1 einen negativen Wert ergibt

((date1.Year - date2.Year) * 12) + date1.Month - date2.Month

Angenommen, Sie möchten eine ungefähre Anzahl von "durchschnittlichen Monaten" zwischen den beiden Daten, sollte das Folgende für alle außer sehr großen Datumsunterschieden funktionieren.

date1.Subtract(date2).Days / (365.25 / 12)

Wenn Sie die letztere Lösung verwenden, sollten Ihre Komponententests den breitesten Datumsbereich angeben, mit dem Ihre Anwendung arbeiten soll, und die Ergebnisse der Berechnung entsprechend validieren.


Update (danke an Gary )

Bei Verwendung der Methode "Durchschnittliche Monate" beträgt die etwas genauere Zahl für die "durchschnittliche Anzahl der Tage pro Jahr" 365,2425 .


3
@Kurru - 365/12 ist nur ein ungefähres Maß für die durchschnittliche Länge eines Monats in Tagen. Es ist eine ungenaue Maßnahme. Für kleine Datumsbereiche kann diese Ungenauigkeit toleriert werden, für sehr große Datumsbereiche kann diese Ungenauigkeit jedoch erheblich werden.
Adam Ralph

21
Ich denke, es ist notwendig, die Tageskomponente zu berücksichtigen. So etwas in der Art (date1.Year - date2.Year) * 12 + date1.Month - date2.Month + (date1.Day >= date2.Day ? 0 : -1)
DrunkCoder

2
@ DrunkCoder hängt von den Anforderungen eines bestimmten Systems ab. In einigen Fällen kann Ihre Lösung tatsächlich die beste Wahl sein. Zum Beispiel ist es wichtig zu überlegen, was passiert, wenn zwei Daten einen 31-Tage-Monat, einen 30-Tage-Monat, einen 28-Tage-Februar oder einen 29-Tage-Februar umfassen. Wenn die Ergebnisse Ihrer Formel das liefern, was das System benötigt, ist dies eindeutig die richtige Wahl. Wenn nicht, ist etwas anderes erforderlich.
Adam Ralph

6
Um das zu unterstützen, was Adam sagte, schrieb ich jahrelang Code für Acturaries. Einige Berechnungen wurden durch die Anzahl der Tage geteilt und durch 30 aufgerundet, um die monatliche Zahl zu erhalten . Manchmal wird davon ausgegangen, dass jedes Datum am ersten des Monats beginnt. Zählen Sie ganze Monate entsprechend . Es gibt keine beste Methode, um Daten zu berechnen. Wenn Sie nicht der Kunde sind, für den Sie Code schreiben, schieben Sie diesen wieder in die Kette und lassen Sie ihn klären, möglicherweise von Ihrem Kundenbuchhalter.
Binary Worrier

1
365.2425 ist eine etwas genauere Anzahl von Tagen in einem Gregorianischen Kalender, wenn Sie diese verwenden. Nach DateTime.MaxValue (1. Januar 10000) beträgt der Unterschied jedoch nur etwa 59 Tage. Außerdem kann die Definition eines Jahres je nach Ihrer Perspektive sehr unterschiedlich sein . En.wikipedia.org/wiki/Year .
Gary

205

Hier ist eine umfassende Lösung, um a zurückzugeben DateTimeSpan, ähnlich wie aTimeSpan , mit der Ausnahme, dass alle Datumskomponenten zusätzlich zu den Zeitkomponenten enthalten sind.

Verwendungszweck:

void Main()
{
    DateTime compareTo = DateTime.Parse("8/13/2010 8:33:21 AM");
    DateTime now = DateTime.Parse("2/9/2012 10:10:11 AM");
    var dateSpan = DateTimeSpan.CompareDates(compareTo, now);
    Console.WriteLine("Years: " + dateSpan.Years);
    Console.WriteLine("Months: " + dateSpan.Months);
    Console.WriteLine("Days: " + dateSpan.Days);
    Console.WriteLine("Hours: " + dateSpan.Hours);
    Console.WriteLine("Minutes: " + dateSpan.Minutes);
    Console.WriteLine("Seconds: " + dateSpan.Seconds);
    Console.WriteLine("Milliseconds: " + dateSpan.Milliseconds);
}

Ausgänge:

Jahre: 1
Monate: 5
Tage: 27
Stunden: 1
Minuten: 36
Sekunden: 50
Millisekunden: 0

Der Einfachheit halber habe ich die Logik in die DateTimeSpanStruktur integriert, aber Sie können die Methode verschieben, CompareDateswo immer Sie es für richtig halten. Beachten Sie auch, dass es keine Rolle spielt, welches Datum vor dem anderen liegt.

public struct DateTimeSpan
{
    public int Years { get; }
    public int Months { get; }
    public int Days { get; }
    public int Hours { get; }
    public int Minutes { get; }
    public int Seconds { get; }
    public int Milliseconds { get; }

    public DateTimeSpan(int years, int months, int days, int hours, int minutes, int seconds, int milliseconds)
    {
        Years = years;
        Months = months;
        Days = days;
        Hours = hours;
        Minutes = minutes;
        Seconds = seconds;
        Milliseconds = milliseconds;
    }

    enum Phase { Years, Months, Days, Done }

    public static DateTimeSpan CompareDates(DateTime date1, DateTime date2)
    {
        if (date2 < date1)
        {
            var sub = date1;
            date1 = date2;
            date2 = sub;
        }

        DateTime current = date1;
        int years = 0;
        int months = 0;
        int days = 0;

        Phase phase = Phase.Years;
        DateTimeSpan span = new DateTimeSpan();
        int officialDay = current.Day;

        while (phase != Phase.Done)
        {
            switch (phase)
            {
                case Phase.Years:
                    if (current.AddYears(years + 1) > date2)
                    {
                        phase = Phase.Months;
                        current = current.AddYears(years);
                    }
                    else
                    {
                        years++;
                    }
                    break;
                case Phase.Months:
                    if (current.AddMonths(months + 1) > date2)
                    {
                        phase = Phase.Days;
                        current = current.AddMonths(months);
                        if (current.Day < officialDay && officialDay <= DateTime.DaysInMonth(current.Year, current.Month))
                            current = current.AddDays(officialDay - current.Day);
                    }
                    else
                    {
                        months++;
                    }
                    break;
                case Phase.Days:
                    if (current.AddDays(days + 1) > date2)
                    {
                        current = current.AddDays(days);
                        var timespan = date2 - current;
                        span = new DateTimeSpan(years, months, days, timespan.Hours, timespan.Minutes, timespan.Seconds, timespan.Milliseconds);
                        phase = Phase.Done;
                    }
                    else
                    {
                        days++;
                    }
                    break;
            }
        }

        return span;
    }
}

1
@ KirkWoll danke. Aber warum gibt DateTimeSpan 34Tage für diesen Zeitunterschied zurück? Es ist 35 timeanddate.com/date/…
Deeptechtons

@ Deeptechtons, schöner Fang. Es gab ein paar Probleme, auf die Sie mich aufmerksam gemacht haben, sowohl was mit dem Startdatum als auch mit dem Datum zu tun hat, das 31Monate mit weniger Tagen "durchläuft". Ich habe die Logik umgekehrt (so dass sie von früh nach später als umgekehrt geht) und akkumuliere jetzt die Monate, ohne das aktuelle Datum zu ändern (und somit Zwischenmonate mit weniger Tagen zu durchlaufen). Ich bin mir immer noch nicht ganz sicher, was das ideale Ergebnis ist sollte beim Vergleich 10/31/2012mit sein 11/30/2012. Im Moment ist das Ergebnis 1Monat.
Kirk Woll

@ KirkWoll danke für das Update, vielleicht habe ich noch ein paar Fallstricke, lassen Sie mich es nach einigen Tests bestätigen Gute Arbeit :)
Deeptechtons

1
Ich habe eine Antwort stackoverflow.com/a/17537472/1737957 auf eine ähnliche Frage geschrieben, in der die vorgeschlagenen Antworten getestet wurden (und festgestellt wurde, dass die meisten von ihnen nicht funktionieren). Diese Antwort ist eine der wenigen, die funktioniert (laut meiner Testsuite). Link zu Github auf meine Antwort.
JWG

@KirkWoll - Diese Antwort scheint nicht für Randfälle zu funktionieren, in denen das Ab-Datum einen höheren Tageswert als den Monat des Datums hat oder das Quelldatum ein Schalttag ist. Versuchen Sie 2020-02-29es 2021-06-29- es gibt "1y 4m 1d" zurück, aber der Wert sollte "1y 4m 0d" sein, richtig?
Rätselhaftigkeit

37

Du könntest es tun

if ( date1.AddMonths(x) > date2 )

Das ist so einfach und funktioniert perfekt für mich. Ich war angenehm überrascht zu sehen, dass es bei der Berechnung eines Datums vom Ende eines Monats bis zu einem Datum am Ende des nächsten Monats mit weniger Tagen wie beabsichtigt funktioniert. Zum Beispiel .. 1-31-2018 + 1 Monat = 28. Februar 218
Glück.Expert

Dies ist eine der besseren Lösungen.
Barnacle.m

Wirklich einfache und effiziente Lösung! Die beste vorgeschlagene Antwort.
Cedric Arnould

2
Was ist, wenn Datum1 = 2018-10-28 und Datum2 = 2018-12-21? Die Antwort ist 2. Während die richtige Antwort 3 sein sollte. Aufgrund des Datumsbereichs beträgt sie 3 Monate. wenn wir nur Monate zählen und Tage ignorieren. Diese Antwort ist also NICHT richtig.
Tommix

Logischer wäre: if ( date1.AddMonths(x).Month == date2.Month )Dann verwenden Sie einfach x + 1 als
Monatszählung

34

Wenn Sie die genaue Anzahl der vollen Monate wünschen, immer positiv (2000-01-15, 2000-02-14 gibt 0 zurück), wenn Sie berücksichtigen, dass ein voller Monat der gleiche Tag im nächsten Monat ist (so etwas wie die Altersberechnung)

public static int GetMonthsBetween(DateTime from, DateTime to)
{
    if (from > to) return GetMonthsBetween(to, from);

    var monthDiff = Math.Abs((to.Year * 12 + (to.Month - 1)) - (from.Year * 12 + (from.Month - 1)));

    if (from.AddMonths(monthDiff) > to || to.Day < from.Day)
    {
        return monthDiff - 1;
    }
    else
    {
        return monthDiff;
    }
}

Grund bearbeiten: Der alte Code war in einigen Fällen nicht korrekt wie:

new { From = new DateTime(1900, 8, 31), To = new DateTime(1901, 8, 30), Result = 11 },

Test cases I used to test the function:

var tests = new[]
{
    new { From = new DateTime(1900, 1, 1), To = new DateTime(1900, 1, 1), Result = 0 },
    new { From = new DateTime(1900, 1, 1), To = new DateTime(1900, 1, 2), Result = 0 },
    new { From = new DateTime(1900, 1, 2), To = new DateTime(1900, 1, 1), Result = 0 },
    new { From = new DateTime(1900, 1, 1), To = new DateTime(1900, 2, 1), Result = 1 },
    new { From = new DateTime(1900, 2, 1), To = new DateTime(1900, 1, 1), Result = 1 },
    new { From = new DateTime(1900, 1, 31), To = new DateTime(1900, 2, 1), Result = 0 },
    new { From = new DateTime(1900, 8, 31), To = new DateTime(1900, 9, 30), Result = 0 },
    new { From = new DateTime(1900, 8, 31), To = new DateTime(1900, 10, 1), Result = 1 },
    new { From = new DateTime(1900, 1, 1), To = new DateTime(1901, 1, 1), Result = 12 },
    new { From = new DateTime(1900, 1, 1), To = new DateTime(1911, 1, 1), Result = 132 },
    new { From = new DateTime(1900, 8, 31), To = new DateTime(1901, 8, 30), Result = 11 },
};

Um Verwirrung für andere Menschen zu vermeiden, denke ich, dass diese Lösung nicht korrekt ist. Verwenden des Testfalls: new { From = new DateTime(2015, 12, 31), To = new DateTime(2015, 6, 30), Result = 6 } Der Test
Cristian Badila

Fügte eine kurze Zusammenfassung mit dem Fix hinzu, den ich hier
Cristian Badila

Ich bin nicht sicher, ob ich es bekomme, meine Funktion gibt 6 zurück, wie es sollte: dotnetfiddle.net/MRZNnC
Guillaume86

Ich habe den Testfall hier von Hand kopiert und es liegt ein Fehler vor. Die fehlerhafte Spezifikation sollte sein : new { From = new DateTime(2015, 12, 31), To = new DateTime(2016, 06, 30), Result = 6 }. Der "Fehler" liegt im to.Day < from.DayCode, der nicht berücksichtigt, dass Monate an einem anderen "Tag des Monats" enden können. In diesem Fall sind vom 31. Dezember 2015 bis zum 30. Juni 2016 6 vollständige Monate vergangen (da der Juni 30 Tage hat), aber Ihr Code würde 5 zurückgeben.
Cristian Badila

3
Meiner Meinung nach ist es das erwartete Verhalten, oder es ist das Verhalten, das ich zumindest erwarte. Ich habe einen vollständigen Monat angegeben, wenn Sie denselben Tag (oder den nächsten Monat wie in diesem Fall) erreichen.
Guillaume86

22

Ich habe die Verwendung dieser Methode in VB.NET über MSDN überprüft und es scheint, dass sie viele Verwendungen hat. In C # gibt es keine solche integrierte Methode. (Auch wenn es keine gute Idee ist) Sie können VBs in C # aufrufen.

  1. Fügen Sie Microsoft.VisualBasic.dllIhrem Projekt als Referenz hinzu
  2. Verwenden Sie Microsoft.VisualBasic.DateAndTime.DateDiff in Ihrem Code

7
Warum denkst du, ist das keine gute Idee? Intuitiv würde ich vermuten, dass die Bibliothek zur Laufzeit 'nur eine weitere .NET-Bibliothek' ist. Beachten Sie, dass ich hier Devil's Advocate spiele. Ich würde dies auch nicht tun, da es sich einfach "falsch anfühlt" (Art des Betrugs), aber ich frage mich, ob es einen überzeugenden technischen Grund gibt, dies nicht zu tun.
Adam Ralph

3
@ AdamRalph: Kein Grund, es nicht zu tun. Diese Bibliotheken sind in 100% verwaltetem Code implementiert, es ist also alles das Gleiche wie alles andere. Der einzig denkbare Unterschied besteht darin, dass das Microsoft.VisualBasic.dllModul geladen werden muss, aber die dafür erforderliche Zeit ist vernachlässigbar. Es gibt keinen Grund, sich um gründlich getestete und nützliche Funktionen zu betrügen, nur weil Sie sich entschieden haben, Ihr Programm in C # zu schreiben. (Dies gilt auch für Dinge wie My.Application.SplashScreen.)
Cody Gray

3
Würden Sie Ihre Meinung ändern, wenn Sie wüssten, dass es in C # geschrieben ist? Es war. Nach der gleichen Logik betrügt die Verwendung von System.Data und PresentationFramework auch wesentliche Teile davon, die in C ++ / CLI geschrieben wurden.
Hans Passant

3
@AdamRalph: Gibt es irgendwelche besonderen Beispiele für dieses "seltsame Gepäck", das mir in den Sinn kommt? Oder sagst du das rein hypothetisch? Und ja, es könnte die Gedanken einiger Ihrer C # -Freunde verwirren, die eine epische Menge Code geschrieben haben, um etwas zu tun, das Sie in einer Zeile mit der richtigen usingAussage tun können , aber ich bezweifle, dass es ernsthaften Schaden geben wird.
Cody Gray

1
@Cody Gray: Einverstanden, das Beispiel ist trivial, wie Sie veranschaulichen. Es ist der zusätzliche Code 'Noise', der durch das Aufrufen einer so ungewöhnlichen (von einem C # POV) Methode eingeführt wird, die ich unbedingt vermeiden möchte. In einem gut organisierten Team würden solche Dinge sowieso in der Codeüberprüfung aufgegriffen und können leicht vermieden werden. Übrigens - ich versuche nicht, VB6 / VB.NET anzugreifen. Ich habe solche Methoden nur deshalb als "seltsam" beschrieben, weil es aus einem .NET-POV keinen Grund DateAndTime.Year()gibt, zu existieren, da dies DateTimeeine YearEigenschaft hat. Es existiert nur, um VB.NET eher wie VB6 erscheinen zu lassen. Als ehemaliger VB6-Programmierer kann ich das schätzen ;-)
Adam Ralph

10

Um einen Unterschied in Monaten zu erhalten (sowohl Anfang als auch Ende), unabhängig von den Daten:

DateTime start = new DateTime(2013, 1, 1);
DateTime end = new DateTime(2014, 2, 1);
var diffMonths = (end.Month + end.Year * 12) - (start.Month + start.Year * 12);

4
Stellen Sie sich vor startund endsind identisch. Dann erhalten Sie ein Ergebnis von 1. Wie ist das richtig? Warum addieren Sie 1 zum Ergebnis? Wer stimmt dieser Antwort zu: - /?
Paul

Bei identischen Daten wird die Ausgabe mit 1 angegeben. Grundsätzlich werden alle Monate einschließlich der Start- und Endmonate gezählt.
Chirag

3
klingt für mich nicht nach dem Unterschied zwischen zwei Gegenständen. Was ist der Unterschied zwischen 2 und 2? Ist es wirklich 1? Ich würde vorschlagen, dass der Unterschied 0 ist.
Paul

8

Verwenden Noda Zeit :

LocalDate start = new LocalDate(2013, 1, 5);
LocalDate end = new LocalDate(2014, 6, 1);
Period period = Period.Between(start, end, PeriodUnits.Months);
Console.WriteLine(period.Months); // 16

(Beispielquelle)


7

Ich brauchte nur etwas Einfaches, um z. B. Beschäftigungsdaten zu berücksichtigen, bei denen nur der Monat / das Jahr eingegeben wurde, und wollte daher unterschiedliche Jahre und Monate, in denen gearbeitet wurde. Dies ist das, was ich hier nur aus Gründen der Nützlichkeit verwende

public static YearsMonths YearMonthDiff(DateTime startDate, DateTime endDate) {
    int monthDiff = ((endDate.Year * 12) + endDate.Month) - ((startDate.Year * 12) + startDate.Month) + 1;
    int years = (int)Math.Floor((decimal) (monthDiff / 12));
    int months = monthDiff % 12;
    return new YearsMonths {
        TotalMonths = monthDiff,
            Years = years,
            Months = months
    };
}

.NET Geige


4

Sie können die DateDiff- Klasse der Time Period Library für .NET verwenden :

// ----------------------------------------------------------------------
public void DateDiffSample()
{
  DateTime date1 = new DateTime( 2009, 11, 8, 7, 13, 59 );
  DateTime date2 = new DateTime( 2011, 3, 20, 19, 55, 28 );
  DateDiff dateDiff = new DateDiff( date1, date2 );

  // differences
  Console.WriteLine( "DateDiff.Months: {0}", dateDiff.Months );
  // > DateDiff.Months: 16

  // elapsed
  Console.WriteLine( "DateDiff.ElapsedMonths: {0}", dateDiff.ElapsedMonths );
  // > DateDiff.ElapsedMonths: 4

  // description
  Console.WriteLine( "DateDiff.GetDescription(6): {0}", dateDiff.GetDescription( 6 ) );
  // > DateDiff.GetDescription(6): 1 Year 4 Months 12 Days 12 Hours 41 Mins 29 Secs
} // DateDiffSample

2

Hier ist mein Beitrag, um einen Unterschied in Monaten zu erzielen, den ich für richtig befunden habe:

namespace System
{
     public static class DateTimeExtensions
     {
         public static Int32 DiffMonths( this DateTime start, DateTime end )
         {
             Int32 months = 0;
             DateTime tmp = start;

             while ( tmp < end )
             {
                 months++;
                 tmp = tmp.AddMonths( 1 );
             }

             return months;
        }
    }
}

Verwendungszweck:

Int32 months = DateTime.Now.DiffMonths( DateTime.Now.AddYears( 5 ) );

Sie können eine andere Methode namens DiffYears erstellen und genau dieselbe Logik wie oben und AddYears anstelle von AddMonths in der while-Schleife anwenden.


2

Dies funktionierte für das, wofür ich es brauchte. Der Tag des Monats spielte in meinem Fall keine Rolle, da es immer der letzte Tag des Monats ist.

public static int MonthDiff(DateTime d1, DateTime d2){
    int retVal = 0;

    if (d1.Month<d2.Month)
    {
        retVal = (d1.Month + 12) - d2.Month;
        retVal += ((d1.Year - 1) - d2.Year)*12;
    }
    else
    {
        retVal = d1.Month - d2.Month;
        retVal += (d1.Year - d2.Year)*12;
    }
    //// Calculate the number of years represented and multiply by 12
    //// Substract the month number from the total
    //// Substract the difference of the second month and 12 from the total
    //retVal = (d1.Year - d2.Year) * 12;
    //retVal = retVal - d1.Month;
    //retVal = retVal - (12 - d2.Month);

    return retVal;
}

2

Der genaueste Weg ist der, der die Differenz in Monaten nach Bruchteilen zurückgibt:

private double ReturnDiffereceBetweenTwoDatesInMonths(DateTime startDateTime, DateTime endDateTime)
{
    double result = 0;
    double days = 0;
    DateTime currentDateTime = startDateTime;
    while (endDateTime > currentDateTime.AddMonths(1))
    {
        result ++;

        currentDateTime = currentDateTime.AddMonths(1);
    }

    if (endDateTime > currentDateTime)
    {
        days = endDateTime.Subtract(currentDateTime).TotalDays;

    }
    return result + days/endDateTime.GetMonthDays;
}

2

Hier ist eine einfache Lösung, die zumindest für mich funktioniert. Es ist wahrscheinlich nicht das schnellste, da es die AddMonth-Funktion von cool DateTime in einer Schleife verwendet:

public static int GetMonthsDiff(DateTime start, DateTime end)
{
    if (start > end)
        return GetMonthsDiff(end, start);

    int months = 0;
    do
    {
        start = start.AddMonths(1);
        if (start > end)
            return months;

        months++;
    }
    while (true);
}

1
Public Class ClassDateOperation
    Private prop_DifferenceInDay As Integer
    Private prop_DifferenceInMonth As Integer
    Private prop_DifferenceInYear As Integer


    Public Function DayMonthYearFromTwoDate(ByVal DateStart As Date, ByVal DateEnd As Date) As ClassDateOperation
        Dim differenceInDay As Integer
        Dim differenceInMonth As Integer
        Dim differenceInYear As Integer
        Dim myDate As Date

        DateEnd = DateEnd.AddDays(1)

        differenceInYear = DateEnd.Year - DateStart.Year

        If DateStart.Month <= DateEnd.Month Then
            differenceInMonth = DateEnd.Month - DateStart.Month
        Else
            differenceInYear -= 1
            differenceInMonth = (12 - DateStart.Month) + DateEnd.Month
        End If


        If DateStart.Day <= DateEnd.Day Then
            differenceInDay = DateEnd.Day - DateStart.Day
        Else

            myDate = CDate("01/" & DateStart.AddMonths(1).Month & "/" & DateStart.Year).AddDays(-1)
            If differenceInMonth <> 0 Then
                differenceInMonth -= 1
            Else
                differenceInMonth = 11
                differenceInYear -= 1
            End If

            differenceInDay = myDate.Day - DateStart.Day + DateEnd.Day

        End If

        prop_DifferenceInDay = differenceInDay
        prop_DifferenceInMonth = differenceInMonth
        prop_DifferenceInYear = differenceInYear

        Return Me
    End Function

    Public ReadOnly Property DifferenceInDay() As Integer
        Get
            Return prop_DifferenceInDay
        End Get
    End Property

    Public ReadOnly Property DifferenceInMonth As Integer
        Get
            Return prop_DifferenceInMonth
        End Get
    End Property

    Public ReadOnly Property DifferenceInYear As Integer
        Get
            Return prop_DifferenceInYear
        End Get
    End Property

End Class

1

Dies ist aus meiner eigenen Bibliothek, wird die Differenz der Monate zwischen zwei Daten zurückgeben.

public static int MonthDiff(DateTime d1, DateTime d2)
{
    int retVal = 0;

    // Calculate the number of years represented and multiply by 12
    // Substract the month number from the total
    // Substract the difference of the second month and 12 from the total
    retVal = (d1.Year - d2.Year) * 12;
    retVal = retVal - d1.Month;
    retVal = retVal - (12 - d2.Month);

    return retVal;
}

1
Funktioniert das? Ich bekomme immer 11 auf Papier für Jan-31-2014undDec-31-2013
Dave Cousineau

1

Sie können eine Funktion wie diese haben.

Zum Beispiel wird von 2012/12/27 bis 2012/12/29 3 Tage. Ebenso wird von 2012/12/15 bis 2013/01/15 2 Monate, weil es bis 2013/01/14 1 Monat ist. Ab dem 15. beginnt der 2. Monat.

Sie können das "=" in der zweiten if-Bedingung entfernen, wenn Sie nicht beide Tage in die Berechnung einbeziehen möchten. Das heißt, von 2012/12/15 bis 2013/01/15 beträgt 1 Monat.

public int GetMonths(DateTime startDate, DateTime endDate)
{
    if (startDate > endDate)
    {
        throw new Exception("Start Date is greater than the End Date");
    }

    int months = ((endDate.Year * 12) + endDate.Month) - ((startDate.Year * 12) + startDate.Month);

    if (endDate.Day >= startDate.Day)
    {
        months++;
    }

    return months;
}

1

Sie können die folgende Erweiterung verwenden: Code

public static class Ext
{
    #region Public Methods

    public static int GetAge(this DateTime @this)
    {
        var today = DateTime.Today;
        return ((((today.Year - @this.Year) * 100) + (today.Month - @this.Month)) * 100 + today.Day - @this.Day) / 10000;
    }

    public static int DiffMonths(this DateTime @from, DateTime @to)
    {
        return (((((@to.Year - @from.Year) * 12) + (@to.Month - @from.Month)) * 100 + @to.Day - @from.Day) / 100);
    }

    public static int DiffYears(this DateTime @from, DateTime @to)
    {
        return ((((@to.Year - @from.Year) * 100) + (@to.Month - @from.Month)) * 100 + @to.Day - @from.Day) / 10000;
    }

    #endregion Public Methods
}

Implementierung !

int Age;
int years;
int Months;
//Replace your own date
var d1 = new DateTime(2000, 10, 22);
var d2 = new DateTime(2003, 10, 20);
//Age
Age = d1.GetAge();
Age = d2.GetAge();
//positive
years = d1.DiffYears(d2);
Months = d1.DiffMonths(d2);
//negative
years = d2.DiffYears(d1);
Months = d2.DiffMonths(d1);
//Or
Months = Ext.DiffMonths(d1, d2);
years = Ext.DiffYears(d1, d2); 

1

Hier ist eine viel präzisere Lösung, bei der VB.Net DateDiff nur für Jahr, Monat und Tag verwendet wird. Sie können die DateDiff-Bibliothek auch in C # laden.

Datum1 muss <= Datum2 sein

VB.NET

Dim date1 = Now.AddDays(-2000)
Dim date2 = Now
Dim diffYears = DateDiff(DateInterval.Year, date1, date2) - If(date1.DayOfYear > date2.DayOfYear, 1, 0)
Dim diffMonths = DateDiff(DateInterval.Month, date1, date2) - diffYears * 12 - If(date1.Day > date2.Day, 1, 0)
Dim diffDays = If(date2.Day >= date1.Day, date2.Day - date1.Day, date2.Day + (Date.DaysInMonth(date1.Year, date1.Month) - date1.Day))

C #

DateTime date1 = Now.AddDays(-2000);
DateTime date2 = Now;
int diffYears = DateDiff(DateInterval.Year, date1, date2) - date1.DayOfYear > date2.DayOfYear ? 1 : 0;
int diffMonths = DateDiff(DateInterval.Month, date1, date2) - diffYears * 12 - date1.Day > date2.Day ? 1 : 0;
int diffDays = date2.Day >= date1.Day ? date2.Day - date1.Day : date2.Day + (System.DateTime.DaysInMonth(date1.Year, date1.Month) - date1.Day);

1

Dies ist eine Antwort auf die Antwort von Kirk Woll. Ich habe noch nicht genügend Reputationspunkte, um auf einen Kommentar zu antworten ...

Ich mochte Kirks Lösung und wollte sie schamlos abreißen und in meinem Code verwenden, aber als ich sie durchgesehen habe, wurde mir klar, dass sie viel zu kompliziert ist. Unnötiges Umschalten und Schleifen sowie ein öffentlicher Konstruktor, dessen Verwendung sinnlos ist.

Hier ist mein Umschreiben:

public class DateTimeSpan {
    private DateTime _date1;
    private DateTime _date2;
    private int _years;
    private int _months;
    private int _days;
    private int _hours;
    private int _minutes;
    private int _seconds;
    private int _milliseconds;

    public int Years { get { return _years; } }
    public int Months { get { return _months; } }
    public int Days { get { return _days; } }
    public int Hours { get { return _hours; } }
    public int Minutes { get { return _minutes; } }
    public int Seconds { get { return _seconds; } }
    public int Milliseconds { get { return _milliseconds; } }

    public DateTimeSpan(DateTime date1, DateTime date2) {
        _date1 = (date1 > date2) ? date1 : date2;
        _date2 = (date2 < date1) ? date2 : date1;

        _years = _date1.Year - _date2.Year;
        _months = (_years * 12) + _date1.Month - _date2.Month;
        TimeSpan t = (_date2 - _date1);
        _days = t.Days;
        _hours = t.Hours;
        _minutes = t.Minutes;
        _seconds = t.Seconds;
        _milliseconds = t.Milliseconds;

    }

    public static DateTimeSpan CompareDates(DateTime date1, DateTime date2) {
        return new DateTimeSpan(date1, date2);
    }
}

Verwendung1, so ziemlich das Gleiche:

void Main()
{
    DateTime compareTo = DateTime.Parse("8/13/2010 8:33:21 AM");
    DateTime now = DateTime.Parse("2/9/2012 10:10:11 AM");
    var dateSpan = new DateTimeSpan(compareTo, now);
    Console.WriteLine("Years: " + dateSpan.Years);
    Console.WriteLine("Months: " + dateSpan.Months);
    Console.WriteLine("Days: " + dateSpan.Days);
    Console.WriteLine("Hours: " + dateSpan.Hours);
    Console.WriteLine("Minutes: " + dateSpan.Minutes);
    Console.WriteLine("Seconds: " + dateSpan.Seconds);
    Console.WriteLine("Milliseconds: " + dateSpan.Milliseconds);
}

Verwendung2, ähnlich:

void Main()
{
    DateTime compareTo = DateTime.Parse("8/13/2010 8:33:21 AM");
    DateTime now = DateTime.Parse("2/9/2012 10:10:11 AM");
    Console.WriteLine("Years: " + DateTimeSpan.CompareDates(compareTo, now).Years);
    Console.WriteLine("Months: " + DateTimeSpan.CompareDates(compareTo, now).Months);
    Console.WriteLine("Days: " + DateTimeSpan.CompareDates(compareTo, now).Days);
    Console.WriteLine("Hours: " + DateTimeSpan.CompareDates(compareTo, now).Hours);
    Console.WriteLine("Minutes: " + DateTimeSpan.CompareDates(compareTo, now).Minutes);
    Console.WriteLine("Seconds: " + DateTimeSpan.CompareDates(compareTo, now).Seconds);
    Console.WriteLine("Milliseconds: " + DateTimeSpan.CompareDates(compareTo, now).Milliseconds);
}

1

In meinem Fall ist es erforderlich, den gesamten Monat vom Startdatum bis zum Tag vor diesem Tag im nächsten Monat oder vom Anfang bis zum Monatsende zu berechnen.


Beispiel: vom 01.01.2008 bis zum 31.01.2008 ist ein vollständiger Monat
Beispiel2: vom 01.05.2008 bis zum 02.04.2008 ist ein vollständiger Monat

Auf dieser Grundlage ist hier meine Lösung:

public static DateTime GetMonthEnd(DateTime StartDate, int MonthsCount = 1)
{
    return StartDate.AddMonths(MonthsCount).AddDays(-1);
}
public static Tuple<int, int> CalcPeriod(DateTime StartDate, DateTime EndDate)
{
    int MonthsCount = 0;
    Tuple<int, int> Period;
    while (true)
    {
        if (GetMonthEnd(StartDate) > EndDate)
            break;
        else
        {
            MonthsCount += 1;
            StartDate = StartDate.AddMonths(1);
        }
    }
    int RemainingDays = (EndDate - StartDate).Days + 1;
    Period = new Tuple<int, int>(MonthsCount, RemainingDays);
    return Period;
}

Verwendungszweck:

Tuple<int, int> Period = CalcPeriod(FromDate, ToDate);

Hinweis: In meinem Fall war es erforderlich, die verbleibenden Tage nach den vollständigen Monaten zu berechnen. Wenn dies nicht der Fall ist, können Sie das Ergebnis der Tage ignorieren oder sogar die Methodenrückgabe von Tupel in Ganzzahl ändern.


1
public static int PayableMonthsInDuration(DateTime StartDate, DateTime EndDate)
{
    int sy = StartDate.Year; int sm = StartDate.Month; int count = 0;
    do
    {
        count++;if ((sy == EndDate.Year) && (sm >= EndDate.Month)) { break; }
        sm++;if (sm == 13) { sm = 1; sy++; }
    } while ((EndDate.Year >= sy) || (EndDate.Month >= sm));
    return (count);
}

Diese Lösung ist für die Berechnung von Vermietungen / Abonnements vorgesehen, bei denen Differenz nicht Subtraktion bedeutet, sondern die Zeitspanne innerhalb dieser beiden Daten.


1

Es gibt 3 Fälle: dasselbe Jahr, vorheriges Jahr und andere Jahre.

Wenn der Tag des Monats keine Rolle spielt ...

public int GetTotalNumberOfMonths(DateTime start, DateTime end)
{
    // work with dates in the right order
    if (start > end)
    {
        var swapper = start;
        start = end;
        end = swapper;
    }

    switch (end.Year - start.Year)
    {
        case 0: // Same year
            return end.Month - start.Month;

        case 1: // last year
            return (12 - start.Month) + end.Month;

        default:
            return 12 * (3 - (end.Year - start.Year)) + (12 - start.Month) + end.Month;
    }
}

1

Ich habe eine Funktion geschrieben, um dies zu erreichen, weil die anderen Wege für mich nicht funktionierten.

public string getEndDate (DateTime startDate,decimal monthCount)
{
    int y = startDate.Year;
    int m = startDate.Month;

    for (decimal  i = monthCount; i > 1; i--)
    {
        m++;
        if (m == 12)
        { y++;
            m = 1;
        }
    }
    return string.Format("{0}-{1}-{2}", y.ToString(), m.ToString(), startDate.Day.ToString());
}

Bitte antworten Sie auf Englisch (gegen jede erfundene Sprache ...)
kleopatra

Warum nicht einfach startDate.AddMonths (monthCount) .ToShortDateString () ausführen? Dies beantwortet nicht die ursprüngliche Frage, die sowieso gestellt wurde!
TabbyCool

Oh, sorry @TabbyCool, dieser Code funktioniert gut in meinem Programm! Die Programmiererregel lautet: Erst Code funktioniert und dann Optimierung! tanx für ur Kommentar :)
reza akhlaghi

1

Mein Verständnis der gesamten Monatsdifferenz zwischen zwei Daten hat einen integralen und einen gebrochenen Teil (das Datum ist wichtig).

Der integrale Bestandteil ist die volle Monatsdifferenz.

Der Bruchteil ist für mich die Differenz des Prozentsatzes des Tages (zu den vollen Tagen des Monats) zwischen dem Start- und dem Endmonat.

public static class DateTimeExtensions
{
    public static double TotalMonthsDifference(this DateTime from, DateTime to)
    {
        //Compute full months difference between dates
        var fullMonthsDiff = (to.Year - from.Year)*12 + to.Month - from.Month;

        //Compute difference between the % of day to full days of each month
        var fractionMonthsDiff = ((double)(to.Day-1) / (DateTime.DaysInMonth(to.Year, to.Month)-1)) -
            ((double)(from.Day-1)/ (DateTime.DaysInMonth(from.Year, from.Month)-1));

        return fullMonthsDiff + fractionMonthsDiff;
    }
}

Mit dieser Erweiterung sind dies die Ergebnisse:

2/29/2000 TotalMonthsDifference 2/28/2001 => 12
2/28/2000 TotalMonthsDifference 2/28/2001 => 12.035714285714286
01/01/2000 TotalMonthsDifference 01/16/2000 => 0.5
01/31/2000 TotalMonthsDifference 01/01/2000 => -1.0
01/31/2000 TotalMonthsDifference 02/29/2000 => 1.0
01/31/2000 TotalMonthsDifference 02/28/2000 => 0.9642857142857143
01/31/2001 TotalMonthsDifference 02/28/2001 => 1.0

1

Es gibt nicht viele klare Antworten darauf, weil Sie immer Dinge annehmen.

Diese Lösung berechnet zwischen zwei Daten die Monate zwischen der Annahme, dass Sie den Tag des Monats zum Vergleich speichern möchten (dh, der Tag des Monats wird bei der Berechnung berücksichtigt).

Wenn Sie beispielsweise ein Datum vom 30. Januar 2012 haben, ist der 29. Februar 2012 kein Monat, sondern der 1. März 2013.

Es wurde ziemlich gründlich getestet, wird es wahrscheinlich später bereinigen, wenn wir es verwenden, aber hier:

private static int TotalMonthDifference(DateTime dtThis, DateTime dtOther)
{
    int intReturn = 0;
    bool sameMonth = false;

    if (dtOther.Date < dtThis.Date) //used for an error catch in program, returns -1
        intReturn--;

    int dayOfMonth = dtThis.Day; //captures the month of day for when it adds a month and doesn't have that many days
    int daysinMonth = 0; //used to caputre how many days are in the month

    while (dtOther.Date > dtThis.Date) //while Other date is still under the other
    {
        dtThis = dtThis.AddMonths(1); //as we loop, we just keep adding a month for testing
        daysinMonth = DateTime.DaysInMonth(dtThis.Year, dtThis.Month); //grabs the days in the current tested month

        if (dtThis.Day != dayOfMonth) //Example 30 Jan 2013 will go to 28 Feb when a month is added, so when it goes to march it will be 28th and not 30th
        {
            if (daysinMonth < dayOfMonth) // uses day in month max if can't set back to day of month
                dtThis.AddDays(daysinMonth - dtThis.Day);
            else
                dtThis.AddDays(dayOfMonth - dtThis.Day);
        }
        if (((dtOther.Year == dtThis.Year) && (dtOther.Month == dtThis.Month))) //If the loop puts it in the same month and year
        {
            if (dtOther.Day >= dayOfMonth) //check to see if it is the same day or later to add one to month
                intReturn++;
            sameMonth = true; //sets this to cancel out of the normal counting of month
        }
        if ((!sameMonth)&&(dtOther.Date > dtThis.Date))//so as long as it didn't reach the same month (or if i started in the same month, one month ahead, add a month)
            intReturn++;
    }
    return intReturn; //return month
}

1

Basierend auf der hervorragenden DateTimeSpan-Arbeit, die oben ausgeführt wurde, habe ich den Code ein wenig normalisiert. das scheint ziemlich gut zu funktionieren:

public class DateTimeSpan
{
  private DateTimeSpan() { }

  private DateTimeSpan(int years, int months, int days, int hours, int minutes, int seconds, int milliseconds)
  {
    Years = years;
    Months = months;
    Days = days;
    Hours = hours;
    Minutes = minutes;
    Seconds = seconds;
    Milliseconds = milliseconds;
  }

  public int Years { get; private set; } = 0;
  public int Months { get; private set; } = 0;
  public int Days { get; private set; } = 0;
  public int Hours { get; private set; } = 0;
  public int Minutes { get; private set; } = 0;
  public int Seconds { get; private set; } = 0;
  public int Milliseconds { get; private set; } = 0;

  public static DateTimeSpan CompareDates(DateTime StartDate, DateTime EndDate)
  {
    if (StartDate.Equals(EndDate)) return new DateTimeSpan();
    DateTimeSpan R = new DateTimeSpan();
    bool Later;
    if (Later = StartDate > EndDate)
    {
      DateTime D = StartDate;
      StartDate = EndDate;
      EndDate = D;
    }

    // Calculate Date Stuff
    for (DateTime D = StartDate.AddYears(1); D < EndDate; D = D.AddYears(1), R.Years++) ;
    if (R.Years > 0) StartDate = StartDate.AddYears(R.Years);
    for (DateTime D = StartDate.AddMonths(1); D < EndDate; D = D.AddMonths(1), R.Months++) ;
    if (R.Months > 0) StartDate = StartDate.AddMonths(R.Months);
    for (DateTime D = StartDate.AddDays(1); D < EndDate; D = D.AddDays(1), R.Days++) ;
    if (R.Days > 0) StartDate = StartDate.AddDays(R.Days);

    // Calculate Time Stuff
    TimeSpan T1 = EndDate - StartDate;
    R.Hours = T1.Hours;
    R.Minutes = T1.Minutes;
    R.Seconds = T1.Seconds;
    R.Milliseconds = T1.Milliseconds;

    // Return answer. Negate values if the Start Date was later than the End Date
    if (Later)
      return new DateTimeSpan(-R.Years, -R.Months, -R.Days, -R.Hours, -R.Minutes, -R.Seconds, -R.Milliseconds);
    return R;
  }
}

Beim Vergleich mit CompareDates(x, y)dem x={01/02/2019 00:00:00}und y={01/05/2020 00:00:00}dann Monthsgibt mir2
Bassie

1

Diese einfache statische Funktion berechnet den Bruchteil von Monaten zwischen zwei Datumszeiten, z

  • 1.1. bis 31.1. = 1,0
  • 1.4. bis 15.4. = 0,5
  • 16.4. bis 30.4. = 0,5
  • 1.3. bis 1.4. = 1 + 1/30

Die Funktion geht davon aus, dass das erste Datum kleiner als das zweite Datum ist. Um mit negativen Zeitintervallen umzugehen, kann man die Funktion leicht ändern, indem man am Anfang ein Vorzeichen und einen Variablentausch einführt.

public static double GetDeltaMonths(DateTime t0, DateTime t1)
{
     DateTime t = t0;
     double months = 0;
     while(t<=t1)
     {
         int daysInMonth = DateTime.DaysInMonth(t.Year, t.Month);
         DateTime endOfMonth = new DateTime(t.Year, t.Month, daysInMonth);
         int cutDay = endOfMonth <= t1 ? daysInMonth : t1.Day;
         months += (cutDay - t.Day + 1) / (double) daysInMonth;
         t = new DateTime(t.Year, t.Month, 1).AddMonths(1);
     }
     return Math.Round(months,2);
 }

0

Die Differenz zwischen zwei Daten in Monaten berechnen zu können, ist völlig logisch und wird in vielen Geschäftsanwendungen benötigt. Die verschiedenen Programmierer hier, die Kommentare abgegeben haben wie - Was ist der Unterschied in den Monaten zwischen "Mai 1.2010" und "Juni 16.2010, Was ist der Unterschied in den Monaten zwischen dem 31. Dezember 2010 und dem 1. Januar 2011?" - haben es nicht verstanden die Grundlagen von Geschäftsanwendungen.

Hier ist die Antwort auf die obigen 2 Kommentare: Die Anzahl der Monate zwischen dem 1. Mai 2010 und dem 16. Juni 2010 beträgt 1 Monat, die Anzahl der Monate zwischen dem 31. Dezember 2010 und dem 1. Januar 2011 beträgt 0. Es Es wäre sehr dumm, sie als 1,5 Monate und 1 Sekunde zu berechnen, wie die obigen Codierer vorgeschlagen haben.

Personen, die an Kreditkarten-, Hypotheken-, Steuer-, Miet-, monatlichen Zinsberechnungen und einer Vielzahl anderer Geschäftslösungen gearbeitet haben, würden dem zustimmen.

Das Problem ist, dass eine solche Funktion in C # oder VB.NET nicht enthalten ist. Datediff berücksichtigt nur Jahre oder die Monatskomponente und ist daher eigentlich nutzlos.

Hier sind einige Beispiele aus der Praxis, wo Sie Monate benötigen und korrekt berechnen können:

Sie lebten in einer Kurzzeitmiete vom 18. Februar bis 23. August. Wie viele Monate bist du dort geblieben? Die Antwort ist einfach - 6 Monate

Sie haben ein Bankkonto, auf dem die Zinsen am Ende eines jeden Monats berechnet und gezahlt werden. Sie zahlen am 10. Juni Geld ein und nehmen es am 29. Oktober (im selben Jahr) heraus. Für wie viele Monate bekommen Sie Interesse? Sehr einfache Antwort - 4 Monate (wieder spielen die zusätzlichen Tage keine Rolle)

In Geschäftsanwendungen liegt die meiste Zeit, wenn Sie Monate berechnen müssen, daran, dass Sie "volle" Monate basierend auf der Berechnung der Zeit durch Menschen kennen müssen. nicht basierend auf einigen abstrakten / irrelevanten Gedanken.


5
Dies ist einer der Gründe, warum Buchhaltung keine Mathematik ist. Bei der Buchhaltung hängt das Ergebnis von der Art und Weise ab, wie Sie es berechnen. Ich kenne Ihre Punkte und kenne die "allgemeine Geschäftsansicht" dazu, aber diese Erklärung ist eindeutig falsch. Zwischen 2012.11.30 und 2012.12.01 gibt es entweder 0 oder 1/30 oder 1/31 oder 1 oder 2 Monate, je nachdem, wonach Sie gefragt haben . Waren die Daten exklusiv oder inklusive? Haben Sie nach der Anzahl der Monate gefragt, die gekreuzt, berührt oder vergangen sind? Wollten Sie aufrunden, abrunden oder genau?
Quetzalcoatl

3
Erklären Sie es jetzt einem Geschäftsmann oder einem Buchhalter und er wird Sie verwirrt ansehen. Es ist immer "so offensichtlich für sie, dass sie natürlich X und Y und Z bedeuteten, wie könnten Sie anders denken?" Holen Sie sich jetzt mehrere Geschäftsleute und versuchen Sie, sie dazu zu bringen, sich auf das Thema zu einigen. Buchhalter sind sich eher einig, da sie irgendwann mithilfe von Mathematik prüfen, mit welchen Optionen sie versehentlich denselben Zeitraum zweimal zusammenfassen könnten usw. Selbst Ihre Berechnungsbeispiele sind umstritten und regionabhängig oder eindeutig ungültig, wie sie annehmen zusätzliche Geschäftsregeln wie das Ignorieren zusätzlicher Tage.
Quetzalcoatl

2
-1 Sie gehen davon aus, dass die gesamte Software eine "Geschäftsanwendung" ist. Der Zweck des betreffenden Codes wird nicht erwähnt. Sie gehen auch davon aus, dass alle "Geschäftsanwendungen" dieselben Regeln haben, was definitiv nicht stimmt.
Jesse Webb

0

Erweiterte Kirks-Struktur mit ToString (Format) und Duration (lange ms)

 public struct DateTimeSpan
{
    private readonly int years;
    private readonly int months;
    private readonly int days;
    private readonly int hours;
    private readonly int minutes;
    private readonly int seconds;
    private readonly int milliseconds;

    public DateTimeSpan(int years, int months, int days, int hours, int minutes, int seconds, int milliseconds)
    {
        this.years = years;
        this.months = months;
        this.days = days;
        this.hours = hours;
        this.minutes = minutes;
        this.seconds = seconds;
        this.milliseconds = milliseconds;
    }

    public int Years { get { return years; } }
    public int Months { get { return months; } }
    public int Days { get { return days; } }
    public int Hours { get { return hours; } }
    public int Minutes { get { return minutes; } }
    public int Seconds { get { return seconds; } }
    public int Milliseconds { get { return milliseconds; } }

    enum Phase { Years, Months, Days, Done }


    public string ToString(string format)
    {
        format = format.Replace("YYYY", Years.ToString());
        format = format.Replace("MM", Months.ToString());
        format = format.Replace("DD", Days.ToString());
        format = format.Replace("hh", Hours.ToString());
        format = format.Replace("mm", Minutes.ToString());
        format = format.Replace("ss", Seconds.ToString());
        format = format.Replace("ms", Milliseconds.ToString());
        return format;
    }


    public static DateTimeSpan Duration(long ms)
    {
        DateTime dt = new DateTime();
        return CompareDates(dt, dt.AddMilliseconds(ms));
    }


    public static DateTimeSpan CompareDates(DateTime date1, DateTime date2)
    {
        if (date2 < date1)
        {
            var sub = date1;
            date1 = date2;
            date2 = sub;
        }

        DateTime current = date1;
        int years = 0;
        int months = 0;
        int days = 0;

        Phase phase = Phase.Years;
        DateTimeSpan span = new DateTimeSpan();

        while (phase != Phase.Done)
        {
            switch (phase)
            {
                case Phase.Years:
                    if (current.AddYears(years + 1) > date2)
                    {
                        phase = Phase.Months;
                        current = current.AddYears(years);
                    }
                    else
                    {
                        years++;
                    }
                    break;
                case Phase.Months:
                    if (current.AddMonths(months + 1) > date2)
                    {
                        phase = Phase.Days;
                        current = current.AddMonths(months);
                    }
                    else
                    {
                        months++;
                    }
                    break;
                case Phase.Days:
                    if (current.AddDays(days + 1) > date2)
                    {
                        current = current.AddDays(days);
                        var timespan = date2 - current;
                        span = new DateTimeSpan(years, months, days, timespan.Hours, timespan.Minutes, timespan.Seconds, timespan.Milliseconds);
                        phase = Phase.Done;
                    }
                    else
                    {
                        days++;
                    }
                    break;
            }
        }

        return span;
    }
}

0
  var dt1 = (DateTime.Now.Year * 12) + DateTime.Now.Month;
  var dt2 = (DateTime.Now.AddMonths(-13).Year * 12) + DateTime.Now.AddMonths(-13).Month;
  Console.WriteLine(dt1);
  Console.WriteLine(dt2);
  Console.WriteLine((dt1 - dt2));
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.