C# 用年份格式化时间跨度

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15957984/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 18:36:17  来源:igfitidea点击:

Format A TimeSpan With Years

c#.netformatting.net-4.5timespan

提问by Dan

I have a class with 2 date properties: FirstDayand LastDay. LastDayis nullable. I would like to generate a string in the format of "x year(s) y day(s)". If the total years are less than 1, I would like to omit the year section. If the total days are less than 1, I would like to omit the day section. If either years or days are 0, they should say "day/year", rather than "days/years" respectively.

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

Examples:
2.2 years:             "2 years 73 days"
1.002738 years:   "1 year 1 day"
0.2 years:             "73 days"
2 years:                "2 years"

示例:
2.2 年:“2 年 73 天”
1.002738 年:“1 年 1 天”
0.2 年:“73 天”
2 年:“2 年”

What I have works, but it is 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;
    }
}

Is there a more concise way of doing this (but still readable)?

有没有更简洁的方法来做到这一点(但仍然可读)?

采纳答案by Jon Skeet

A TimeSpandoesn't have a sensible concept of "years" because it depends on the start and end point. (Months is similar - how many months are there in 29 days? Well, it depends...)

ATimeSpan没有合理的“年”概念,因为它取决于起点和终点。(月份是相似的 - 29 天内有多少个月?嗯,这取决于...)

To give a shameless plug, my Noda Timeproject makes this really simple though:

为了提供一个无耻的插件,我的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);
    }
}

Output:

输出:

Between 19 June 2010 and 11 April 2013 are 2 years and 296 days

回答by D Stanley

I wouldn't do this with a TimeSpan. Date math gets tricky as soon as you go beyond days because the number of days in a month and days in a year is no longer constant. It's likely why TimeSpandoes not contain properties for Yearsand Months. I would instead determine the number of years/months/days, etc between the two DateTimevalues and display the results accordingly.

我不会用TimeSpan. 一旦超过天数,日期数学就会变得棘手,因为一个月中的天数和一年中的天数不再是恒定的。很可能为什么TimeSpan不包含Yearsand 的属性Months。我会改为确定两个DateTime值之间的年数/月数/天数等,并相应地显示结果。

回答by Jens Borrisholt

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

回答by user3469676

I think this should work:

我认为这应该有效:

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

回答by Mark

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