使用年份格式化TimeSpan

我有一个有两个date属性的类: FirstDayLastDayLastDay为空。 我想生成一个string格式为"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; } } 

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

TimeSpan没有明确的“年”的概念,因为它取决于开始和结束点。 (几个月是相似的 – 在29天内有多less个月?呃,这取决于…)

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

输出:

 Between 19 June 2010 and 11 April 2013 are 2 years and 296 days 
 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); } 

我不会用TimeSpan做到这一点。 由于一个月中的天数和一年中的天数不再是恒定的,所以一旦超过了date,datemath就变得棘手。 TimeSpan很可能不包含“ Years和“ Months属性。 而是确定两个DateTime值之间的年/月/日等数,并相应地显示结果。

我认为这应该工作:

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