格式化TimeSpan与岁月

Dan*_*Dan 21 .net c# formatting timespan .net-4.5

我有一个有2个日期属性的类:FirstDayLastDay. LastDay是可以为空的.我想以格式生成一个字符串"x year(s) y day(s)".如果总年数小于1,我想省略年份部分.如果总天数小于1,我想省略日期部分.如果年份或天数为0,则应分别说"天/年",而不是"天/年".

示例:
2.2年:"2年73天"
1.002738年:"1年1
天"0.
2年:" 73天" 2年:"2年"

我有什么作品,但它很长:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

是否有更简洁的方法(但仍然可读)?

Jon*_*eet 45

A TimeSpan没有"年"的明智概念,因为它取决于起点和终点.(月份相似 - 29天有多少个月?嗯,这取决于...)

为了给一个无耻的插件,我的Noda Time项目使这个非常简单:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

输出:

Between 19 June 2010 and 11 April 2013 are 2 years and 296 days
Run Code Online (Sandbox Code Playgroud)

  • 你肯定可以信赖Jon在[时代]的专业知识(http://stackoverflow.com/a/6841479/211627)和[日期](http://msmvps.com/blogs/jon_skeet/archive/2010/12/01 /the-joys-of-date-time-arithmetic.aspx) (14认同)
  • 呃,额外的第三方图书馆 - 但Jon Skeet的图书馆非常令人信服. (8认同)

小智 7

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);
}
Run Code Online (Sandbox Code Playgroud)