Calculate Years, Months, weeks and Days

后端 未结 7 1054
南笙
南笙 2020-12-10 07:19

In my application, a user enters two dates. A scheduled start date, and a scheduled end date. We have to take those dates, and populate 4 fields, based on the difference.

相关标签:
7条回答
  • 2020-12-10 07:54

    Heres a complete method, weeks are not included, but could be added relatively simply. It's a somewhat complex question (asked in a multitude of ways on stackoverflow and answered poorly in a multitude of ways), but none the less can be answered. The TimeSpan object gives us part of what we need, but only works up through days. I've written a significant number of tests against this method, if you find a hole, please post a comment.

    What this will do is compare 2 dates, getting the years, months, days, hours, and minutes. (e.g. some event happened 1 year, 6 months, 3 days, 4 hours and 7 minutes ago)

    Because this question has been asked and attempted to be answered so many times, I'm not sure this will ever even get noticed, but if so it should provide value.

        public static void TimeSpanToDateParts(DateTime d1, DateTime d2, out int years, out int months, out int days, out int hours, out int minutes)
        {
            if (d1 < d2)
            {
                var d3 = d2;
                d2 = d1;
                d1 = d3;
            }
    
            var span = d1 - d2;
    
            months = 12 * (d1.Year - d2.Year) + (d1.Month - d2.Month);
    
            //month may need to be decremented because the above calculates the ceiling of the months, not the floor.
            //to do so we increase d2 by the same number of months and compare.
            //(500ms fudge factor because datetimes are not precise enough to compare exactly)
            if (d1.CompareTo(d2.AddMonths(months).AddMilliseconds(-500)) <= 0)
            {
                --months;
            }
    
            years = months / 12;
            months -= years * 12;
    
            if (months == 0 && years == 0)
            {
                days = span.Days;
            }
            else
            {
                var md1 = new DateTime(d1.Year, d1.Month, d1.Day);
                // Fixed to use d2.Day instead of d1.Day
                var md2 = new DateTime(d2.Year, d2.Month, d2.Day);
                var mDays = (int) (md1 - md2).TotalDays;
    
                if (mDays > span.Days)
                {
                    mDays = (int)(md1.AddMonths(-1) - md2).TotalDays;
                }
    
                days = span.Days - mDays;
    
    
            }
            hours = span.Hours;
            minutes = span.Minutes;
        }
    
    0 讨论(0)
  • 2020-12-10 07:58

    I think TimeSpan is what you are looking for, but it does not do years or months because those vary in length.

    The below example is from the above link;

    // Define two dates.
    DateTime date1 = new DateTime(2010, 1, 1, 8, 0, 15);
    DateTime date2 = new DateTime(2010, 8, 18, 13, 30, 30);
    // Calculate the interval between the two dates.
    TimeSpan interval = date2 - date1;
    Console.WriteLine("{0} - {1} = {2}", date2, date1, interval.ToString());
    // Display individual properties of the resulting TimeSpan object.
    Console.WriteLine("   {0,-35} {1,20}", "Value of Days Component:", interval.Days);
    Console.WriteLine("   {0,-35} {1,20}", "Total Number of Days:", interval.TotalDays);
    Console.WriteLine("   {0,-35} {1,20}", "Value of Hours Component:", interval.Hours);
    Console.WriteLine("   {0,-35} {1,20}", "Total Number of Hours:", interval.TotalHours);
    Console.WriteLine("   {0,-35} {1,20}", "Value of Minutes Component:", interval.Minutes);
    Console.WriteLine("   {0,-35} {1,20}", "Total Number of Minutes:", interval.TotalMinutes);
    Console.WriteLine("   {0,-35} {1,20:N0}", "Value of Seconds Component:", interval.Seconds);
    Console.WriteLine("   {0,-35} {1,20:N0}", "Total Number of Seconds:", interval.TotalSeconds);
    Console.WriteLine("   {0,-35} {1,20:N0}", "Value of Milliseconds Component:", interval.Milliseconds);
    Console.WriteLine("   {0,-35} {1,20:N0}", "Total Number of Milliseconds:", interval.TotalMilliseconds);
    Console.WriteLine("   {0,-35} {1,20:N0}", "Ticks:", interval.Ticks);
    // the example displays the following output:
    //       8/18/2010 1:30:30 PM - 1/1/2010 8:00:15 AM = 229.05:30:15
    //          Value of Days Component:                             229
    //          Total Number of Days:                   229.229340277778
    //          Value of Hours Component:                              5
    //          Total Number of Hours:                  5501.50416666667
    //          Value of Minutes Component:                           30
    //          Total Number of Minutes:                       330090.25
    //          Value of Seconds Component:                           15
    //          Total Number of Seconds:                      19,805,415
    //          Value of Milliseconds Component:                       0
    //          Total Number of Milliseconds:             19,805,415,000
    //          Ticks:                               198,054,150,000,000
    
    0 讨论(0)
  • 2020-12-10 08:03

    I also needed this but, in my case, without the weeks part (so only years, months and days). Given that, here's what I made:

    DateTime startDate = DateTime.ParseExact (start, "dd/MM/yyyy",CultureInfo.InvariantCulture);
    DateTime endDate = DateTime.ParseExact (end, "dd/MM/yyyy",CultureInfo.InvariantCulture);
    int days=0;
    int months = 0;
    int years = 0;
    //calculate days
    if (endDate.Day >= startDate.Day) {
        days = endDate.Day - startDate.Day;
    } else {
        var tempDate = endDate.AddMonths (-1);
        int daysInMonth = DateTime.DaysInMonth (tempDate.Year, tempDate.Month);
        days = daysInMonth - (startDate.Day - endDate.Day);
        months--;
    }
    //calculate months
    if (endDate.Month >= startDate.Month) {
        months+=endDate.Month - startDate.Month;
    } else {
        months+= 12 - (startDate.Month - endDate.Month);
        years--;
    }
    //calculate years
    years+=endDate.Year - startDate.Year;
    Debug.WriteLine (string.Format("{0} years, {1} months, {2} days",years,months,days));
    

    If you want to show this more dynamically, you can also use this code:

    //build the string
    var result = "";
    if (years!=0){
        result = years == 1 ? years + " year" : years + " years";
    }
    if (months != 0) {
        if (result != "") {
            result += ", ";
        }
        result += months == 1 ? months + " month" : months + " months";
    }
    if (days != 0) {
        if (result != "") {
            result += ", ";
        }
        result += days == 1 ? days + " day" : days + " days";
    }
    Debug.WriteLine (result);
    
    0 讨论(0)
  • 2020-12-10 08:04

    You can use the DateDiff class of this free library:

    // ----------------------------------------------------------------------
    public void DateDiffSample()
    {
      DateTime date1 = new DateTime( 2009, 11, 8, 7, 13, 59 );
      Console.WriteLine( "Date1: {0}", date1 );
      // > Date1: 08.11.2009 07:13:59
      DateTime date2 = new DateTime( 2011, 3, 20, 19, 55, 28 );
      Console.WriteLine( "Date2: {0}", date2 );
      // > Date2: 20.03.2011 19:55:28
    
      DateDiff dateDiff = new DateDiff( date1, date2 );
    
      // differences
      Console.WriteLine( "DateDiff.Years: {0}", dateDiff.Years );
      // > DateDiff.Years: 1
      Console.WriteLine( "DateDiff.Quarters: {0}", dateDiff.Quarters );
      // > DateDiff.Quarters: 5
      Console.WriteLine( "DateDiff.Months: {0}", dateDiff.Months );
      // > DateDiff.Months: 16
      Console.WriteLine( "DateDiff.Weeks: {0}", dateDiff.Weeks );
      // > DateDiff.Weeks: 70
      Console.WriteLine( "DateDiff.Days: {0}", dateDiff.Days );
      // > DateDiff.Days: 497
      Console.WriteLine( "DateDiff.Weekdays: {0}", dateDiff.Weekdays );
      // > DateDiff.Weekdays: 71
      Console.WriteLine( "DateDiff.Hours: {0}", dateDiff.Hours );
      // > DateDiff.Hours: 11940
      Console.WriteLine( "DateDiff.Minutes: {0}", dateDiff.Minutes );
      // > DateDiff.Minutes: 716441
      Console.WriteLine( "DateDiff.Seconds: {0}", dateDiff.Seconds );
      // > DateDiff.Seconds: 42986489
    
      // elapsed
      Console.WriteLine( "DateDiff.ElapsedYears: {0}", dateDiff.ElapsedYears );
      // > DateDiff.ElapsedYears: 1
      Console.WriteLine( "DateDiff.ElapsedMonths: {0}", dateDiff.ElapsedMonths );
      // > DateDiff.ElapsedMonths: 4
      Console.WriteLine( "DateDiff.ElapsedDays: {0}", dateDiff.ElapsedDays );
      // > DateDiff.ElapsedDays: 12
      Console.WriteLine( "DateDiff.ElapsedHours: {0}", dateDiff.ElapsedHours );
      // > DateDiff.ElapsedHours: 12
      Console.WriteLine( "DateDiff.ElapsedMinutes: {0}", dateDiff.ElapsedMinutes );
      // > DateDiff.ElapsedMinutes: 41
      Console.WriteLine( "DateDiff.ElapsedSeconds: {0}", dateDiff.ElapsedSeconds );
      // > DateDiff.ElapsedSeconds: 29
    } // DateDiffSample
    
    0 讨论(0)
  • 2020-12-10 08:08

    Investigate the C# TimeSpan structure. It doesn't do months or years, but it does do days. That makes things easier.

    0 讨论(0)
  • 2020-12-10 08:09

    I had created this one for returning difference in years,month and days between 2 dates.

    public static Dictionary<string, int> TimeSpanToDateParts(DateTime fromDate,DateTime toDate)
            {
                int years;
                int months;
                int days;
                Dictionary<string, int> dateParts = new Dictionary<string, int>();
                if (toDate < fromDate)
                {
                   return TimeSpanToDateParts(toDate,fromDate);
                }
    
                var span = toDate - fromDate;
    
                months = 12 * (toDate.Year - fromDate.Year) + (toDate.Month - fromDate.Month);
    
                if (toDate.CompareTo(fromDate.AddMonths(months).AddMilliseconds(-500)) <= 0)
                {
                    --months;
                }
    
                years = months / 12;
                months -= years * 12;
    
                if (months == 0 && years == 0)
                {
                    days = span.Days;
                }
                else
                {
                    days = toDate.Day;
                    if (fromDate.Day > toDate.Day)
                        days = days + (DateTime.DaysInMonth(toDate.Year, toDate.Month - 1) - fromDate.Day);
                    else
                        days = days - fromDate.Day;
                }
                dateParts.Add("Years", years);
                dateParts.Add("Months", months);
                dateParts.Add("Days", days);
    
                return dateParts;
            }
    
    0 讨论(0)
提交回复
热议问题