Question

En C # /. Net TimeSpan a TotalDays, TotalMinutes, etc. Mais je ne peux pas trouver une formule pour la différence totale des mois. Des jours variables par mois et des années de saut continuent de me jeter. Comment puis-je avoir Mois total?

Éditer Désolé de ne pas être plus clair: je sais que je ne peux pas vraiment obtenir ça TimeSpan Mais je pensais utiliser TotalDays et TotalMinutes Ce serait un bon exemple pour exprimer ce que je cherchais ... sauf que j'essaie d'obtenir un total de mois.

Exemple: 25 décembre 2009 - 6 octobre 2009 = 2 mois totaux. Le 6 octobre au 5 novembre est égal à 0 mois. Le 6 novembre, 1 mois. Le 6 décembre, 2 mois

Était-ce utile?

La solution

Vous ne pourrez pas obtenir cela à partir d'un TimeSpan, car un "mois" est une unité de mesure variable. Vous devrez le calculer vous-même et vous devrez comprendre comment vous voulez que cela fonctionne.

Par exemple, des dates comme des dates comme July 5, 2009 et August 4, 2009 Rendre un mois ou zéro mois de différence? Si vous dites que cela devrait en donner un, alors qu'en est-il July 31, 2009 et August 1, 2009? Est ce un mois? Est-ce simplement la différence du Month valeurs pour les dates, ou est-elle plus liée à une durée réelle? La logique pour déterminer toutes ces règles est non triviale, vous devrez donc déterminer le vôtre et implémenter l'algorithme approprié.

Si tout ce que vous voulez est simplement une différence dans les mois - sans tenir compte des valeurs de date - vous pouvez utiliser ceci:

public static int MonthDifference(this DateTime lValue, DateTime rValue)
{
    return (lValue.Month - rValue.Month) + 12 * (lValue.Year - rValue.Year);
}

Notez que cela renvoie une différence relative, ce qui signifie que si rValue est supérieur à lValue, alors la valeur de retour sera négative. Si vous voulez une différence absolue, vous pouvez utiliser ceci:

public static int MonthDifference(this DateTime lValue, DateTime rValue)
{
    return Math.Abs((lValue.Month - rValue.Month) + 12 * (lValue.Year - rValue.Year));
}

Autres conseils

(Je me rends compte que c'est une vieille question, mais ...)

C'est relativement Douloureux à faire en .Net pur. Je recommanderais le mien Temps de Noda Bibliothèque, qui est particulièrement conçue pour des choses comme ceci:

LocalDate start = new LocalDate(2009, 10, 6);
LocalDate end = new LocalDate(2009, 12, 25);
Period period = Period.Between(start, end);
int months = period.Months;

(Il y a d'autres options, par exemple si vous ne voulez qu'un compte de mois, même au cours des années, vous utiliseriez Period period = Period.Between(start, end, PeriodUnits.Months);)

Peut-être que vous ne voulez pas connaître les fractions du mois; Et ce code?


public static class DateTimeExtensions
{
    public static int TotalMonths(this DateTime start, DateTime end)
    {
        return (start.Year * 12 + start.Month) - (end.Year * 12 + end.Month);
    }
}

//  Console.WriteLine(
//     DateTime.Now.TotalMonths(
//         DateTime.Now.AddMonths(-1))); // prints "1"


Vous devrez définir ce que vous entendez par des mois totaux pour commencer.
Une définition simple met un mois à 30,4 jours (365.25 / 12).

Au-delà de cela, toute définition incluant des fractions semble inutile, et la valeur entière la plus courante (mois entiers entre les dates) dépend également des règles commerciales non standard.

Vous devez vous élaborer vous-même des DateTimes. La façon dont vous gérez les jours de stub à la fin dépendra de ce pour quoi vous voulez l'utiliser.

Une méthode serait de compter le mois, puis de corriger les jours à la fin. Quelque chose comme:

   DateTime start = new DateTime(2003, 12, 25);
   DateTime end = new DateTime(2009, 10, 6);
   int compMonth = (end.Month + end.Year * 12) - (start.Month + start.Year * 12);
   double daysInEndMonth = (end - end.AddMonths(1)).Days;
   double months = compMonth + (start.Day - end.Day) / daysInEndMonth;

J'ai écrit une méthode d'extension très simple sur DateTime et DateTimeOffset pour faire ça. Je voulais que ça marche exactement comme un TotalMonths propriété TimeSpan fonctionnerait: c'est-à-dire retourner le nombre de mois complets entre deux dates, en ignorant les mois partiels. Parce que c'est basé sur DateTime.AddMonths() Il respecte différentes durées de mois et renvoie ce qu'un humain comprendrait comme une période de mois.

(Malheureusement, vous ne pouvez pas le mettre en œuvre comme une méthode d'extension sur Timespan car cela ne conserve pas la connaissance des dates réelles utilisées, et pendant des mois, ils sont importants.)

Le code et les tests sont les deux Disponible sur github. Le code est très simple:

public static int GetTotalMonthsFrom(this DateTime dt1, DateTime dt2)
{
    DateTime earlyDate = (dt1 > dt2) ? dt2.Date : dt1.Date;
    DateTime lateDate = (dt1 > dt2) ? dt1.Date : dt2.Date;

    // Start with 1 month's difference and keep incrementing
    // until we overshoot the late date
    int monthsDiff = 1;
    while (earlyDate.AddMonths(monthsDiff) <= lateDate)
    {
        monthsDiff++;
    }

    return monthsDiff - 1;
}

Et il passe tous ces cas de test unitaire:

// Simple comparison
Assert.AreEqual(1, new DateTime(2014, 1, 1).GetTotalMonthsFrom(new DateTime(2014, 2, 1)));
// Just under 1 month's diff
Assert.AreEqual(0, new DateTime(2014, 1, 1).GetTotalMonthsFrom(new DateTime(2014, 1, 31)));
// Just over 1 month's diff
Assert.AreEqual(1, new DateTime(2014, 1, 1).GetTotalMonthsFrom(new DateTime(2014, 2, 2)));
// 31 Jan to 28 Feb
Assert.AreEqual(1, new DateTime(2014, 1, 31).GetTotalMonthsFrom(new DateTime(2014, 2, 28)));
// Leap year 29 Feb to 29 Mar
Assert.AreEqual(1, new DateTime(2012, 2, 29).GetTotalMonthsFrom(new DateTime(2012, 3, 29)));
// Whole year minus a day
Assert.AreEqual(11, new DateTime(2012, 1, 1).GetTotalMonthsFrom(new DateTime(2012, 12, 31)));
// Whole year
Assert.AreEqual(12, new DateTime(2012, 1, 1).GetTotalMonthsFrom(new DateTime(2013, 1, 1)));
// 29 Feb (leap) to 28 Feb (non-leap)
Assert.AreEqual(12, new DateTime(2012, 2, 29).GetTotalMonthsFrom(new DateTime(2013, 2, 28)));
// 100 years
Assert.AreEqual(1200, new DateTime(2000, 1, 1).GetTotalMonthsFrom(new DateTime(2100, 1, 1)));
// Same date
Assert.AreEqual(0, new DateTime(2014, 8, 5).GetTotalMonthsFrom(new DateTime(2014, 8, 5)));
// Past date
Assert.AreEqual(6, new DateTime(2012, 1, 1).GetTotalMonthsFrom(new DateTime(2011, 6, 10)));

Je le ferais comme ça:

static int TotelMonthDifference(this DateTime dtThis, DateTime dtOther)
{
    int intReturn = 0;

    dtThis = dtThis.Date.AddDays(-(dtThis.Day-1));
    dtOther = dtOther.Date.AddDays(-(dtOther.Day-1));

    while (dtOther.Date > dtThis.Date)
    {
        intReturn++;     
        dtThis = dtThis.AddMonths(1);
    }

    return intReturn;
}

Il n'y a pas beaucoup de réponses claires à ce sujet parce que vous supposez toujours des choses.

Cette solution calcule entre deux dates les mois entre supposer que vous souhaitez sauver le jour du mois pour la comparaison, (ce qui signifie que le jour du mois est considéré dans le calcul)

Par exemple, si vous avez une date du 30 janvier 2012, 29 février 2012 ne sera pas un mois, mais le 01 mars 2013 le fera.

Il a été testé de manière assez approfondie, le nettoiera probablement plus tard au fur et à mesure que nous l'utiliserons, et prend deux dates au lieu d'un temps de temps, ce qui est probablement mieux. J'espère que cela aide quelqu'un d'autre.

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
}

Vieille question que je sais, mais je pourrais aider quelqu'un. J'ai utilisé @ADAM accepté la réponse ci-dessus, mais j'ai ensuite vérifié si la différence est 1 ou -1, puis vérifiez s'il s'agit d'une différence complète du mois civil. Ainsi, le 21/07/55 et le 20/08/55 ne seraient pas un mois complet, mais le 21/07/55 et le 21/07/55 le seraient.

/// <summary>
/// Amended date of birth cannot be greater than or equal to one month either side of original date of birth.
/// </summary>
/// <param name="dateOfBirth">Date of birth user could have amended.</param>
/// <param name="originalDateOfBirth">Original date of birth to compare against.</param>
/// <returns></returns>
public JsonResult ValidateDateOfBirth(string dateOfBirth, string originalDateOfBirth)
{
    DateTime dob, originalDob;
    bool isValid = false;

    if (DateTime.TryParse(dateOfBirth, out dob) && DateTime.TryParse(originalDateOfBirth, out originalDob))
    {
        int diff = ((dob.Month - originalDob.Month) + 12 * (dob.Year - originalDob.Year));

        switch (diff)
        {
            case 0:
                // We're on the same month, so ok.
                isValid = true;
                break;
            case -1:
                // The month is the previous month, so check if the date makes it a calendar month out.
                isValid = (dob.Day > originalDob.Day);
                break;
            case 1:
                // The month is the next month, so check if the date makes it a calendar month out.
                isValid = (dob.Day < originalDob.Day);
                break;
            default:
                // Either zero or greater than 1 month difference, so not ok.
                isValid = false;
                break;
        }
        if (!isValid)
            return Json("Date of Birth cannot be greater than one month either side of the date we hold.", JsonRequestBehavior.AllowGet);
    }
    else
    {
        return Json("Date of Birth is invalid.", JsonRequestBehavior.AllowGet);
    }
    return Json(true, JsonRequestBehavior.AllowGet);
}

La réponse acceptée fonctionne parfaitement lorsque vous voulez des mois complets.

J'avais besoin de mois partiels. C'est la solution que j'ai trouvée pendant des mois partiels:

    /// <summary>
    /// Calculate the difference in months.
    /// This will round up to count partial months.
    /// </summary>
    /// <param name="lValue"></param>
    /// <param name="rValue"></param>
    /// <returns></returns>
    public static int MonthDifference(DateTime lValue, DateTime rValue)
    {
        var yearDifferenceInMonths = (lValue.Year - rValue.Year) * 12;
        var monthDifference = lValue.Month - rValue.Month;

        return yearDifferenceInMonths + monthDifference + 
            (lValue.Day > rValue.Day
                ? 1 : 0); // If end day is greater than start day, add 1 to round up the partial month
    }

J'avais également besoin d'une différence d'année avec le même besoin pendant des années partielles. Voici la solution que j'ai proposée:

    /// <summary>
    /// Calculate the differences in years.
    /// This will round up to catch partial months.
    /// </summary>
    /// <param name="lValue"></param>
    /// <param name="rValue"></param>
    /// <returns></returns>
    public static int YearDifference(DateTime lValue, DateTime rValue)
    {
        return lValue.Year - rValue.Year +
               (lValue.Month > rValue.Month // Partial month, same year
                   ? 1
                   : ((lValue.Month = rValue.Month) 
                     && (lValue.Day > rValue.Day)) // Partial month, same year and month
                   ? 1 : 0);
    }
case IntervalType.Month:
    returnValue = start.AddMonths(-end.Month).Month.ToString();
    break;
case IntervalType.Year:
    returnValue = (start.Year - end.Year).ToString();
    break;

Le problème avec les mois est que ce n'est pas vraiment une mesure simple - ils ne sont pas une taille constante. Vous devez définir vos règles pour ce que vous voulez inclure et travailler à partir de là. Par exemple du 1er janvier au 1er février - vous pourriez dire que 2 mois y sont impliqués, ou vous pourriez dire que c'est un mois. Alors qu'en est-il du "1er janvier 20:00" au "1er février 00:00" - ce n'est pas tout à fait un mois complet. Est-ce 0? 1? Qu'en est-il de l'inverse (1er janvier 00:00 au 1er février 20:00) ... 1? 2?

Définissez d'abord les règles, alors vous devrez le coder vous-même, j'ai peur ...

Si vous voulez avoir un résultat 1 entre 28th Feb et 1st March:

DateTime date1, date2;
int monthSpan = (date2.Year - date1.Year) * 12 + date2.Month - date1.Month

Cette La bibliothèque calcule la différence de mois, compte tenu de toutes les parties de DateTime:

// ----------------------------------------------------------------------
public void DateDiffSample()
{
  DateTime date1 = new DateTime( 2009, 11, 8, 7, 13, 59 );
  Console.WriteLine( "Date1: {0}", date1 );
  // > Date1: 08.11.2009 07:13:59
  DateTime date2 = new DateTime( 2011, 3, 20, 19, 55, 28 );
  Console.WriteLine( "Date2: {0}", date2 );
  // > Date2: 20.03.2011 19:55:28

  DateDiff dateDiff = new DateDiff( date1, date2 );

  // differences
  Console.WriteLine( "DateDiff.Years: {0}", dateDiff.Years );
  // > DateDiff.Years: 1
  Console.WriteLine( "DateDiff.Quarters: {0}", dateDiff.Quarters );
  // > DateDiff.Quarters: 5
  Console.WriteLine( "DateDiff.Months: {0}", dateDiff.Months );
  // > DateDiff.Months: 16
  Console.WriteLine( "DateDiff.Weeks: {0}", dateDiff.Weeks );
  // > DateDiff.Weeks: 70
  Console.WriteLine( "DateDiff.Days: {0}", dateDiff.Days );
  // > DateDiff.Days: 497
  Console.WriteLine( "DateDiff.Weekdays: {0}", dateDiff.Weekdays );
  // > DateDiff.Weekdays: 71
  Console.WriteLine( "DateDiff.Hours: {0}", dateDiff.Hours );
  // > DateDiff.Hours: 11940
  Console.WriteLine( "DateDiff.Minutes: {0}", dateDiff.Minutes );
  // > DateDiff.Minutes: 716441
  Console.WriteLine( "DateDiff.Seconds: {0}", dateDiff.Seconds );
  // > DateDiff.Seconds: 42986489

  // elapsed
  Console.WriteLine( "DateDiff.ElapsedYears: {0}", dateDiff.ElapsedYears );
  // > DateDiff.ElapsedYears: 1
  Console.WriteLine( "DateDiff.ElapsedMonths: {0}", dateDiff.ElapsedMonths );
  // > DateDiff.ElapsedMonths: 4
  Console.WriteLine( "DateDiff.ElapsedDays: {0}", dateDiff.ElapsedDays );
  // > DateDiff.ElapsedDays: 12
  Console.WriteLine( "DateDiff.ElapsedHours: {0}", dateDiff.ElapsedHours );
  // > DateDiff.ElapsedHours: 12
  Console.WriteLine( "DateDiff.ElapsedMinutes: {0}", dateDiff.ElapsedMinutes );
  // > DateDiff.ElapsedMinutes: 41
  Console.WriteLine( "DateDiff.ElapsedSeconds: {0}", dateDiff.ElapsedSeconds );
  // > DateDiff.ElapsedSeconds: 29
} // DateDiffSample

Vous trouverez ci-dessous le moyen le plus précis que vous puissiez le faire, car la définition de «1 mois» change en fonction de quel mois il est, et aucune autre réponse en tient compte! Si vous voulez plus d'informations sur le problème qui n'est pas intégré au cadre, vous pouvez lire cet article: Un objet réel de temps avec. (Cependant, la lecture de ce message n'est pas nécessaire pour comprendre et utiliser la fonction ci-dessous, elle fonctionne à 100%, sans les inexactitudes inhérentes de l'approximation que les autres aiment utiliser - et n'hésitez pas à remplacer la fonction .reverseit par le intégré. Fonction inverse que vous pouvez avoir sur votre cadre (c'est juste ici pour l'exhaustivité).

Veuillez noter que vous pouvez obtenir n'importe quel nombre de dates / heures de précision, de secondes et de minutes, ou secondes, minutes et jours, n'importe où jusqu'à des années (qui contiendrait 6 parties / segments). Si vous spécifiez les deux premiers et qu'il a plus d'un an, il reviendra "il y a 1 an et 3 mois" et ne reviendra pas le reste car vous avez demandé deux segments. S'il n'a que quelques heures, il ne reviendra que "2 heures et 1 minute". Bien sûr, les mêmes règles s'appliquent si vous spécifiez 1, 2, 3, 4, 5 ou 6 segmets (maxes à 6 car les secondes, les minutes, les heures, les jours, les mois, les années ne font que 6 types). Il corrigera également les problèmes de grammaire comme "Minutes" vs "Minute" selon qu'il est 1 minute ou plus, identique à tous les types, et la "chaîne" générée sera toujours grammaticalement correcte.

Voici quelques exemples pour une utilisation: BallowSegments identifie le nombre de segments à montrer ... c'est-à-dire: si 3, alors la chaîne de retour serait (par exemple) ... "3 years, 2 months and 13 days" (n'inclura pas les heures, les minutes et les secondes à mesure que les 3 premières catégories de temps sont retournées), si cependant, la date était une date plus récente, comme quelque chose il y a quelques jours, spécifiant les mêmes segments (3) "4 days, 1 hour and 13 minutes ago" Au lieu de cela, cela prend donc tout en compte!

Si Ballowsegments est 2, il reviendrait "3 years and 2 months" et si 6 (valeur maximale) reviendrait "3 years, 2 months, 13 days, 13 hours, 29 minutes and 9 seconds", mais rappelez-vous que ce sera NEVER RETURN quelque chose comme ça "0 years, 0 months, 0 days, 3 hours, 2 minutes and 13 seconds ago" Comme il comprend, il n'y a pas de données de date dans les 3 premiers segments et les ignore, même si vous spécifiez 6 segments, alors ne vous inquiétez pas :). Bien sûr, s'il y a un segment avec 0 dedans, il en tiendra compte lors de la formation de la chaîne et s'affichera comme "3 days and 4 seconds ago" Et ignorer la partie "0 heures"! Profitez et veuillez commenter si vous le souhaitez.

 Public Function RealTimeUntilNow(ByVal dt As DateTime, Optional ByVal bAllowSegments As Byte = 2) As String
  ' bAllowSegments identifies how many segments to show... ie: if 3, then return string would be (as an example)...
  ' "3 years, 2 months and 13 days" the top 3 time categories are returned, if bAllowSegments is 2 it would return
  ' "3 years and 2 months" and if 6 (maximum value) would return "3 years, 2 months, 13 days, 13 hours, 29 minutes and 9 seconds"
  Dim rYears, rMonths, rDays, rHours, rMinutes, rSeconds As Int16
  Dim dtNow = DateTime.Now
  Dim daysInBaseMonth = Date.DaysInMonth(dt.Year, dt.Month)

  rYears = dtNow.Year - dt.Year
  rMonths = dtNow.Month - dt.Month
  If rMonths < 0 Then rMonths += 12 : rYears -= 1 ' add 1 year to months, and remove 1 year from years.
  rDays = dtNow.Day - dt.Day
  If rDays < 0 Then rDays += daysInBaseMonth : rMonths -= 1
  rHours = dtNow.Hour - dt.Hour
  If rHours < 0 Then rHours += 24 : rDays -= 1
  rMinutes = dtNow.Minute - dt.Minute
  If rMinutes < 0 Then rMinutes += 60 : rHours -= 1
  rSeconds = dtNow.Second - dt.Second
  If rSeconds < 0 Then rSeconds += 60 : rMinutes -= 1

  ' this is the display functionality
  Dim sb As StringBuilder = New StringBuilder()
  Dim iSegmentsAdded As Int16 = 0

  If rYears > 0 Then sb.Append(rYears) : sb.Append(" year" & If(rYears <> 1, "s", "") & ", ") : iSegmentsAdded += 1
  If bAllowSegments = iSegmentsAdded Then GoTo parseAndReturn

  If rMonths > 0 Then sb.AppendFormat(rMonths) : sb.Append(" month" & If(rMonths <> 1, "s", "") & ", ") : iSegmentsAdded += 1
  If bAllowSegments = iSegmentsAdded Then GoTo parseAndReturn

  If rDays > 0 Then sb.Append(rDays) : sb.Append(" day" & If(rDays <> 1, "s", "") & ", ") : iSegmentsAdded += 1
  If bAllowSegments = iSegmentsAdded Then GoTo parseAndReturn

  If rHours > 0 Then sb.Append(rHours) : sb.Append(" hour" & If(rHours <> 1, "s", "") & ", ") : iSegmentsAdded += 1
  If bAllowSegments = iSegmentsAdded Then GoTo parseAndReturn

  If rMinutes > 0 Then sb.Append(rMinutes) : sb.Append(" minute" & If(rMinutes <> 1, "s", "") & ", ") : iSegmentsAdded += 1
  If bAllowSegments = iSegmentsAdded Then GoTo parseAndReturn

  If rSeconds > 0 Then sb.Append(rSeconds) : sb.Append(" second" & If(rSeconds <> 1, "s", "") & "") : iSegmentsAdded += 1

parseAndReturn:

  ' if the string is entirely empty, that means it was just posted so its less than a second ago, and an empty string getting passed will cause an error
  ' so we construct our own meaningful string which will still fit into the "Posted * ago " syntax...

  If sb.ToString = "" Then sb.Append("less than 1 second")

  Return ReplaceLast(sb.ToString.TrimEnd(" ", ",").ToString, ",", " and")

 End Function

Bien sûr, vous aurez besoin d'une fonction "Rempacelast", qui prend une chaîne source, et un argument spécifiant ce qui doit être remplacé, et un autre Arg spécifiant ce dont vous voulez le remplacer, et il remplace uniquement la dernière occurrence de cette chaîne ... J'ai inclus mon seul si vous n'en avez pas ou si vous ne voulez pas l'implémenter, donc le voici, cela fonctionnera "comme" sans aucune modification nécessaire. Je sais que la fonction de revers n'est plus nécessaire (n'existe dans .NET) mais le remplacement et le func inversé sont reportés à partir des jours avant. EM depuis plus de dix ans, peut garantir qu'ils sont sans bug) ... :). à votre santé.

<Extension()> _ 
Public Function ReplaceLast(ByVal sReplacable As String, ByVal sReplaceWhat As String, ByVal sReplaceWith As String) As String 
    ' let empty string arguments run, incase we dont know if we are sending and empty string or not. 
    sReplacable = sReplacable.ReverseIt 
    sReplacable = Replace(sReplacable, sReplaceWhat.ReverseIt, sReplaceWith.ReverseIt, , 1) ' only does first item on reversed version! 
    Return sReplacable.ReverseIt.ToString 
End Function 

<Extension()> _ 
Public Function ReverseIt(ByVal strS As String, Optional ByVal n As Integer = -1) As String 
    Dim strTempX As String = "", intI As Integer 

    If n > strS.Length Or n = -1 Then n = strS.Length 

    For intI = n To 1 Step -1 
        strTempX = strTempX + Mid(strS, intI, 1) 
    Next intI 

    ReverseIt = strTempX + Right(strS, Len(strS) - n) 

End Function 

Si vous voulez le numéro exact, vous ne pouvez pas simplement dans le temps de temps, car vous devez savoir quels mois vous trouvez, et si vous avez affaire à une année de saut, comme vous l'avez dit.

Soit opter pour un numéro approximatif, soit faire un peu avec les DateTimes d'origine

http://www.astro.uu.nl/~strous/aa/en/reken/juliaansedag.html

Si vous pouvez obtenir le temps converti à partir d'une date grégorienne en Numéro de jour julien, vous pouvez simplement créer un opérateur pour faire des comparaisons du numéro de jour zulien, qui peut être tapissé double pour obtenir des mois, des jours, des secondes, etc. Consultez le lien ci-dessus pour un algorithme pour convertir du Grégorien en Julian.

Il n'y a pas de manière intégrée pour le faire avec précision dans Idiomatic-C #. Il y a des solutions de contournement, comme Cet exemple de codeproject que les gens ont codé cependant.

Si vous avez affaire à des mois et des années, vous avez besoin de quelque chose qui sait combien de jours par mois et quelles années sont des années de saut.

Entrer le Calendrier Grégorien (Et d'autres spécifiques à la culture Calendrier implémentations).

Bien que Calendar ne fournit pas de méthodes pour calculer directement la différence entre deux points dans le temps, il a des méthodes telles que

DateTime AddWeeks(DateTime time, int weeks)
DateTime AddMonths(DateTime time, int months)
DateTime AddYears(DateTime time, int years)
DateTime start = new DateTime(2003, 12, 25);
DateTime end = new DateTime(2009, 10, 6);
int compMonth = (end.Month + end.Year * 12) - (start.Month + start.Year * 12);
double daysInEndMonth = (end - end.AddMonths(1)).Days;
double months = compMonth + (start.Day - end.Day) / daysInEndMonth;

La méthode renvoie une liste qui contient 3 éléments en premier est l'année, le deuxième est le mois et l'élément final est le jour:

public static List<int> GetDurationInEnglish(DateTime from, DateTime to)
    {
        try
        {
            if (from > to)
                return null;

            var fY = from.Year;
            var fM = from.Month;
            var fD = DateTime.DaysInMonth(fY, fM);

            var tY = to.Year;
            var tM = to.Month;
            var tD = DateTime.DaysInMonth(tY, tM);

            int dY = 0;
            int dM = 0;
            int dD = 0;

            if (fD > tD)
            {
                tM--;

                if (tM <= 0)
                {
                    tY--;
                    tM = 12;
                    tD += DateTime.DaysInMonth(tY, tM);
                }
                else
                {
                    tD += DateTime.DaysInMonth(tY, tM);
                }
            }
            dD = tD - fD;

            if (fM > tM)
            {
                tY--;

                tM += 12;
            }
            dM = tM - fM;

            dY = tY - fY;

            return new List<int>() { dY, dM, dD };
        }
        catch (Exception exception)
        {
            //todo: log exception with parameters in db

            return null;
        }
    }

Voici ma contribution pour obtenir la différence en mois que j'ai trouvé exact:

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

Usage:

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

Vous pouvez créer une autre méthode appelée diffyears et appliquer exactement la même logique que ci-dessus et Addyears au lieu d'ajouter des mois dans la boucle while.

Bien tard vers le jeu, mais j'imagine que cela peut être utile à quelqu'un. La majorité des personnes ont tendance à mesurer de mois en mois à la date à l'exclusion du fait que les mois viennent dans différentes variations. En utilisant ce cadre de pensée, j'ai créé une doublure One qui compare les dates pour nous. En utilisant le processus suivant.

  1. Tout nombre d'années sur 1 lors de la comparaison de l'année sera multiplié par 12, il n'y a pas de cas où cela peut être égal à moins de 1 année complète.
  2. Si l'année de fin est plus élevée, nous devons évaluer si le jour en cours est supérieur ou égal à la veille précédente 2A. Si la journée de fin est plus grande ou égale, nous prenons le mois en cours, puis ajoutez 12 mois à soustraire le mois du mois de début 2B. Si le jour de fin est inférieur au jour de début, nous effectuons la même chose que ci-dessus, sauf que nous ajoutons 1 au mois de départ avant de soustraire
  3. Si l'année de fin n'est pas plus grande, nous effectuons la même chose que 2a / 2b, mais sans ajouter les 12 mois parce que nous n'avons pas besoin d'évaluer vers l'année.

        DateTime date = new DateTime(2003, 11, 25);
        DateTime today = new DateTime(2004, 12, 26);
        var time = (today.Year - date.Year > 1 ? (today.Year - date.Year - 1) * 12 : 0) +  (today.Year > date.Year ? (today.Day >= date.Day ? today.Month + 12 - date.Month : today.Month + 12 - (date.Month + 1)) : (today.Day >= date.Day ? today.Month - date.Month : today.Month - (date.Month + 1)));
    

Calculez les mois entre 2 dates:

$date1 = '2017-01-20';
$date2 = '2019-01-20';

$ts1 = strtotime($date1);
$ts2 = strtotime($date2);

$year1 = date('Y', $ts1);
$year2 = date('Y', $ts2);

$month1 = date('m', $ts1);
$month2 = date('m', $ts2);

echo $joining_months = (($year2 - $year1) * 12) + ($month2 - $month1);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top