2013-04-11 34 views
16

Tôi có một lớp học có 2 thuộc tính ngày: FirstDayLastDay. LastDay không thể thực hiện được. Tôi muốn tạo một chuỗi ở định dạng "x year(s) y day(s)". Nếu tổng số năm dưới 1, tôi muốn bỏ qua phần năm. Nếu tổng số ngày nhỏ hơn 1, tôi muốn bỏ qua phần ngày. Nếu năm hoặc ngày là 0, họ phải nói "ngày/năm" thay vì "ngày/năm" tương ứng.Định dạng A TimeSpan Với Năm

Ví dụ:
2.2 năm:                           "2 năm 73 ngày"
1,002738 năm:       "1 năm 1 ngày"
0,2 năm :                           "73 ngày"
2 năm:                                 "2 năm"

Những gì tôi có tác phẩm, nhưng nó là dài:

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

Có cách nào ngắn gọn hơn để thực hiện việc này (nhưng vẫn có thể đọc được) không?

+2

http://codereview.stackexchange.com/ – Kashif

Trả lời

42

A TimeSpan không có khái niệm hợp lý về "năm" vì nó phụ thuộc vào điểm xuất phát và điểm đến. (Tháng là tương tự - có bao nhiêu tháng đang có trong 29 ngày Vâng, nó phụ thuộc ...?)

Để cung cấp một plug không biết xấu hổ, dự án Noda Time của tôi làm cho điều này thực sự đơn giản mặc dù:

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 
+13

Và bạn chắc chắn có thể tin tưởng chuyên môn của Jon vào [lần] (http://stackoverflow.com/a/6841479/211627) và [ngày] (http://msmvps.com/blogs/jon_skeet/archive/2010/ 12/01/the-joys-of-date-time-arithmetic.aspx) – JDB

+4

ugh, thêm thư viện của bên thứ ba - nhưng thư viện của Jon Skeet là khá thuyết phục. – tofutim

+0

này tính toán năm nhuận cũng phải không ??? – Ali

1

Tôi sẽ không làm điều này với số TimeSpan. Toán ngày tháng trở nên khó khăn ngay sau khi bạn vượt quá ngày vì số ngày trong tháng và ngày trong một năm không còn liên tục. Đó có thể là lý do tại sao TimeSpan không chứa các thuộc tính cho YearsMonths. Thay vào đó, tôi sẽ xác định số năm/tháng/ngày, v.v ... giữa hai giá trị DateTime và hiển thị kết quả tương ứng.

+1

Điều đó có vẻ như OP đã giải quyết thỏa đáng đầy đủ (cho mục đích của mình): '365.242M' ngày mỗi năm. – JDB

+1

Không có 365.242 ngày trong một năm.Một số năm có 365 ngày, một số có 366. Có 365.242 trong một năm _average_, sẽ không hoạt động nếu bạn so sánh hai ngày cụ thể. Nếu tất cả những gì đã có sẵn là số ngày (đó là "TimeSpan' có thể làm được), thì nó sẽ là một _estimate_ phong nha nhưng có thể bị tắt một ngày trong một số trường hợp nhất định. –

+1

Tôi đồng ý với bạn, tôi chỉ đang nói về một dự án phi cá nhân, công khai, chính xác có thể (hợp pháp) có một ghế sau để thuận tiện. – JDB

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

tôi nghĩ rằng điều này sẽ làm việc:

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

Bạn đang hiển thị tháng và ngày ở đây để chuyển đổi thành 'int', nhưng sau đó chia cho mười nghìn - được đúc thành một Int. Điều này gần như tương đương với việc 'dateValue1.Year - dateValue2.year' về độ chính xác. Kết quả của điều này sẽ là một con số duy nhất cho biết năm đã hoàn toàn qua bất kể bất kỳ 354 ngày trailing có thể. Ngữ nghĩa, điều này cũng rất đáng ngờ. –

0
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

Sẽ rất tốt để giải thích tại sao mã này hoạt động. Cung cấp thêm chi tiết luôn là ý tưởng hay khi trả lời câu hỏi. –

Các vấn đề liên quan