web-dev-qa-db-fra.com

Formater un intervalle de temps avec des années

J'ai une classe avec 2 propriétés de date: FirstDay et LastDay. LastDay est nullable. Je voudrais générer une chaîne au format de "x year(s) y day(s)". Si le nombre total d'années est inférieur à 1, j'aimerais supprimer la section Année. Si le nombre total de jours est inférieur à 1, je voudrais supprimer la section jour. Si les années ou les jours sont 0, ils doivent dire "jour/année", plutôt que "jours/années" respectivement.

Exemples:
2,2 ans: "2 ans et 73 jours"
1,002738 ans: "1 an 1 jour"
0.2 ans: "73 jours"
2 ans: "2 ans"

Ce que j'ai travaille, mais c'est long:

private const decimal DaysInAYear = 365.242M;

public string LengthInYearsAndDays
{
    get
    {
        var lastDay = this.LastDay ?? DateTime.Today;
        var lengthValue = lastDay - this.FirstDay;

        var builder = new StringBuilder();

        var totalDays = (decimal)lengthValue.TotalDays;
        var totalYears = totalDays / DaysInAYear;
        var years = (int)Math.Floor(totalYears);

        totalDays -= (years * DaysInAYear);
        var days = (int)Math.Floor(totalDays);

        Func<int, string> sIfPlural = value =>
            value > 1 ? "s" : string.Empty;

        if (years > 0)
        {
            builder.AppendFormat(
                CultureInfo.InvariantCulture,
                "{0} year{1}",
                years,
                sIfPlural(years));

            if (days > 0)
            {
                builder.Append(" ");
            }
        }

        if (days > 0)
        {
            builder.AppendFormat(
                CultureInfo.InvariantCulture,
                "{0} day{1}",
                days,
                sIfPlural(days));
        }

        var length = builder.ToString();
        return length;
    }
}

Y a-t-il un moyen plus concis de le faire (mais toujours lisible)?

20
Dan

Une TimeSpan n'a pas de notion raisonnable d '"années" car elle dépend du point de départ et de la fin. (Les mois sont semblables - combien de mois y a-t-il dans 29 jours? Ça dépend ...)

Pour donner une fiche éhontée, mon Noda Time projet rend cela très simple:

using System;
using NodaTime;

public class Test
{
    static void Main(string[] args)
    {
        LocalDate start = new LocalDate(2010, 6, 19);
        LocalDate end = new LocalDate(2013, 4, 11);
        Period period = Period.Between(start, end,
                                       PeriodUnits.Years | PeriodUnits.Days);

        Console.WriteLine("Between {0} and {1} are {2} years and {3} days",
                          start, end, period.Years, period.Days);
    }
}

Sortie:

Between 19 June 2010 and 11 April 2013 are 2 years and 296 days
44
Jon Skeet
public string GetAgeText(DateTime birthDate)
{
        const double ApproxDaysPerMonth = 30.4375;
        const double ApproxDaysPerYear = 365.25;

        /*
        The above are the average days per month/year over a normal 4 year period
        We use these approximations as they are more accurate for the next century or so
        After that you may want to switch over to these 400 year approximations

           ApproxDaysPerMonth = 30.436875
           ApproxDaysPerYear  = 365.2425 

          How to get theese numbers:
            The are 365 days in a year, unless it is a leepyear.
            Leepyear is every forth year if Year % 4 = 0
            unless year % 100 == 1
            unless if year % 400 == 0 then it is a leep year.

            This gives us 97 leep years in 400 years. 
            So 400 * 365 + 97 = 146097 days.
            146097 / 400      = 365.2425
            146097 / 400 / 12 = 30,436875

        Due to the nature of the leap year calculation, on this side of the year 2100
        you can assume every 4th year is a leap year and use the other approximatiotions

        */
    //Calculate the span in days
    int iDays = (DateTime.Now - birthDate).Days;

    //Calculate years as an integer division
    int iYear = (int)(iDays / ApproxDaysPerYear);

    //Decrease remaing days
    iDays -= (int)(iYear * ApproxDaysPerYear);

    //Calculate months as an integer division
    int iMonths = (int)(iDays / ApproxDaysPerMonth);

    //Decrease remaing days
    iDays -= (int)(iMonths * ApproxDaysPerMonth);

    //Return the result as an string   
    return string.Format("{0} years, {1} months, {2} days", iYear, iMonths, iDays);
}
6
Jens Borrisholt

Je ne ferais pas cela avec un TimeSpan. Le calcul des dates devient compliqué dès que vous dépassez les jours, car le nombre de jours dans un mois et de jours dans une année n'est plus constant. Il est probable que TimeSpan ne contient pas de propriétés pour Years et Months. Je voudrais plutôt déterminer le nombre d'années/mois/jours, etc. entre les deux valeurs DateTime et afficher les résultats en conséquence.

1
D Stanley

Je pense que cela devrait fonctionner:

public static int DiffYears(DateTime dateValue1, DateTime dateValue2)
{
    var intToCompare1 = Convert.ToInt32(dateValue1.ToString("yyyyMMdd"));
    var intToCompare2 = Convert.ToInt32(dateValue2.ToString("yyyyMMdd"));
    return (intToCompare2 - intToCompare1) / 10000;
}
0
user3469676
Public Function TimeYMDBetween(StartDate As DateTime, EndDate As DateTime) As String
    Dim Years As Integer = EndDate.Year - StartDate.Year
    Dim Months As Integer = EndDate.Month - StartDate.Month
    Dim Days As Integer = EndDate.Day - StartDate.Day
    Dim DaysLastMonth As Integer

    'figure out how many days were in last month
    If EndDate.Month = 1 Then
        DaysLastMonth = DateTime.DaysInMonth(EndDate.Year - 1, 12)
    Else
        DaysLastMonth = DateTime.DaysInMonth(EndDate.Year, EndDate.Month - 1)
    End If

    'adjust for negative days
    If Days < 0 Then
        Months = Months - 1
        Days = Days + DaysLastMonth 'borrowing from last month
    End If

    'adjust for negative Months
    If Months < 0 Then 'startdate hasn't happend this year yet
        Years = Years - 1
        Months = Months + 12
    End If

    Return Years.ToString() + " Years, " + Months.ToString() + " Months and " + Days.ToString() + " Days"

End Function
0
Mark