Sự khác biệt trong tháng giữa hai ngày


334

Làm cách nào để tính chênh lệch theo tháng giữa hai ngày trong C #?

Có tương đương với DateDiff()phương pháp của VB trong C #. Tôi cần tìm sự khác biệt về tháng giữa hai ngày cách nhau nhiều năm. Các tài liệu nói rằng tôi có thể sử dụng TimeSpannhư:

TimeSpan ts = date1 - date2;

nhưng điều này mang lại cho tôi dữ liệu trong vài ngày. Tôi không muốn chia số này cho 30 vì không phải mỗi tháng là 30 ngày và vì hai giá trị toán hạng khá tách biệt với nhau, tôi sợ chia cho 30 có thể cho tôi một giá trị sai.

Bất kỳ đề xuất?


27
Xác định "sự khác biệt trong tháng", sự khác biệt trong các tháng giữa "tháng 5 năm 2010" và "ngày 16 tháng 6 năm 2010" là gì? 1,5, 1 hay cái gì khác?
Cheng Chen

7
Hoặc, để nhấn mạnh điểm này hơn nữa, sự khác biệt trong các tháng giữa ngày 31 tháng 12 năm 2010 và ngày 1 tháng 1 năm 2011 là gì? Tùy thuộc vào ban ngày, đây có thể là một sự khác biệt chỉ 1 giây; bạn sẽ tính đây là một sự khác biệt của một tháng?
stakx - không còn đóng góp

Đây là mã đơn giản và ngắn trong trường hợp, bạn vẫn không thể nhận được câu trả lời, hãy xem POST stackoverflow.com/questions/8820603/iêu
wirol

11
Danny: 1 tháng và 15 ngày. stakx: 0 tháng và 1 ngày. Vấn đề là để có được thành phần tháng . Điều này có vẻ khá rõ ràng đối với tôi và là một câu hỏi hay.
Kirk Woll

Câu trả lời:


462

Giả sử ngày trong tháng là không liên quan (nghĩa là độ chênh lệch giữa 2011.1.1 và 2010.12.31 là 1), với ngày1> date2 cho giá trị dương và date2> date1 một giá trị âm

((date1.Year - date2.Year) * 12) + date1.Month - date2.Month

Hoặc, giả sử bạn muốn có một số 'tháng trung bình' xấp xỉ giữa hai ngày, những điều sau đây sẽ có hiệu quả đối với tất cả nhưng chênh lệch ngày rất lớn.

date1.Subtract(date2).Days / (365.25 / 12)

Lưu ý, nếu bạn đã sử dụng giải pháp sau thì các bài kiểm tra đơn vị của bạn sẽ nêu phạm vi ngày rộng nhất mà ứng dụng của bạn được thiết kế để làm việc và xác thực kết quả tính toán tương ứng.


Cập nhật (cảm ơn Gary )

Nếu sử dụng phương pháp 'tháng trung bình', một con số chính xác hơn một chút để sử dụng cho 'số ngày trung bình mỗi năm' là 365,2425 .


3
@Kurru - 365/12 chỉ là thước đo gần đúng về độ dài trung bình của một tháng tính theo ngày. Đó là một biện pháp không chính xác. Đối với phạm vi ngày nhỏ, sự không chính xác này có thể được chấp nhận nhưng đối với phạm vi ngày rất lớn thì sự không chính xác này có thể trở nên đáng kể.
Adam Ralph

21
Tôi nghĩ rằng cần phải xem xét thành phần ngày. Một cái gì đó như thế này (date1.Year - date2.Year) * 12 + date1.Month - date2.Month + (date1.Day >= date2.Day ? 0 : -1)
DrunkCoder

2
@DrunkCoder nó phụ thuộc vào yêu cầu của một hệ thống nhất định. Trong một số trường hợp, giải pháp của bạn thực sự có thể là sự lựa chọn tốt nhất. Ví dụ, điều quan trọng là xem xét những gì xảy ra khi hai ngày kéo dài một tháng 31 ngày, một tháng 30 ngày, 28 ngày tháng hai hoặc 29 ngày tháng hai. Nếu kết quả của công thức của bạn cung cấp những gì hệ thống yêu cầu thì rõ ràng đó là lựa chọn đúng đắn. Nếu không, sau đó một cái gì đó được yêu cầu.
Adam Ralph

6
Để thứ hai những gì Adam nói, tôi đã dành nhiều năm để viết mã cho Acturaries. Một số tính toán được chia theo số ngày, làm tròn 30 để có được con số hàng tháng . Đôi khi tính tháng được giả định mỗi ngày bắt đầu vào ngày đầu tiên của tháng, tính cả tháng tương ứng . Không có phương pháp tốt nhất khi tính ngày. Trừ khi bạn là khách hàng mà bạn đang viết mã, hãy đẩy chuỗi này lên và làm cho nó được làm rõ, có thể là do kế toán khách hàng của bạn.
Nhị phân nhị phân

1
365.2425 là số ngày chính xác hơn một chút trong Lịch Gregorian, nếu đó là những gì bạn đang sử dụng. Tuy nhiên, bởi DateTime.MaxValue (ngày 1 tháng 1 năm 10000) chỉ chênh lệch khoảng 59 ngày. Ngoài ra, định nghĩa của một năm có thể khác nhau tùy thuộc vào quan điểm của bạn en.wikipedia.org/wiki/Year .
Gary

205

Đây là một giải pháp toàn diện để trả về a DateTimeSpan, tương tự như a TimeSpan, ngoại trừ việc nó bao gồm tất cả các thành phần ngày ngoài các thành phần thời gian.

Sử dụng:

void Main()
{
    DateTime compareTo = DateTime.Parse("8/13/2010 8:33:21 AM");
    DateTime now = DateTime.Parse("2/9/2012 10:10:11 AM");
    var dateSpan = DateTimeSpan.CompareDates(compareTo, now);
    Console.WriteLine("Years: " + dateSpan.Years);
    Console.WriteLine("Months: " + dateSpan.Months);
    Console.WriteLine("Days: " + dateSpan.Days);
    Console.WriteLine("Hours: " + dateSpan.Hours);
    Console.WriteLine("Minutes: " + dateSpan.Minutes);
    Console.WriteLine("Seconds: " + dateSpan.Seconds);
    Console.WriteLine("Milliseconds: " + dateSpan.Milliseconds);
}

Đầu ra:

Năm: 1
Tháng: 5
Ngày: 27
Giờ: 1
Phút: 36
giây: 50
mili giây: 0

Để thuận tiện, tôi đã đưa logic vào DateTimeSpancấu trúc, nhưng bạn có thể di chuyển phương thức CompareDatesbất cứ nơi nào bạn thấy phù hợp. Cũng lưu ý, không có vấn đề ngày nào đến trước ngày khác.

public struct DateTimeSpan
{
    public int Years { get; }
    public int Months { get; }
    public int Days { get; }
    public int Hours { get; }
    public int Minutes { get; }
    public int Seconds { get; }
    public int Milliseconds { get; }

    public DateTimeSpan(int years, int months, int days, int hours, int minutes, int seconds, int milliseconds)
    {
        Years = years;
        Months = months;
        Days = days;
        Hours = hours;
        Minutes = minutes;
        Seconds = seconds;
        Milliseconds = milliseconds;
    }

    enum Phase { Years, Months, Days, Done }

    public static DateTimeSpan CompareDates(DateTime date1, DateTime date2)
    {
        if (date2 < date1)
        {
            var sub = date1;
            date1 = date2;
            date2 = sub;
        }

        DateTime current = date1;
        int years = 0;
        int months = 0;
        int days = 0;

        Phase phase = Phase.Years;
        DateTimeSpan span = new DateTimeSpan();
        int officialDay = current.Day;

        while (phase != Phase.Done)
        {
            switch (phase)
            {
                case Phase.Years:
                    if (current.AddYears(years + 1) > date2)
                    {
                        phase = Phase.Months;
                        current = current.AddYears(years);
                    }
                    else
                    {
                        years++;
                    }
                    break;
                case Phase.Months:
                    if (current.AddMonths(months + 1) > date2)
                    {
                        phase = Phase.Days;
                        current = current.AddMonths(months);
                        if (current.Day < officialDay && officialDay <= DateTime.DaysInMonth(current.Year, current.Month))
                            current = current.AddDays(officialDay - current.Day);
                    }
                    else
                    {
                        months++;
                    }
                    break;
                case Phase.Days:
                    if (current.AddDays(days + 1) > date2)
                    {
                        current = current.AddDays(days);
                        var timespan = date2 - current;
                        span = new DateTimeSpan(years, months, days, timespan.Hours, timespan.Minutes, timespan.Seconds, timespan.Milliseconds);
                        phase = Phase.Done;
                    }
                    else
                    {
                        days++;
                    }
                    break;
            }
        }

        return span;
    }
}

1
@KirkWoll cảm ơn. Nhưng tại sao DateTimeSpan trả lại 34ngày cho chênh lệch thời gian ngày này thực sự là 35 timeanddate.com/date/
mẹo

@Deeptechtons, bắt đẹp. Có một vài vấn đề bạn đã chú ý đến tôi, cả hai đều phải làm với ngày bắt đầu 31và ngày "trôi qua" vài tháng với ít ngày hơn. Tôi đã đảo ngược logic (để nó đi từ sớm đến muộn hơn ngược lại) và bây giờ tích lũy các tháng mà không sửa đổi ngày hiện tại (và do đó chuyển qua giữa các tháng với ít ngày hơn) Vẫn không hoàn toàn chắc chắn kết quả lý tưởng là gì nên khi so sánh 10/31/2012với 11/30/2012. Ngay bây giờ kết quả là 1tháng.
Kirk Woll

@KirkWoll cảm ơn về bản cập nhật, có lẽ tôi đã nhận được thêm vài bản gotchas để tôi xác nhận nó sau một số bài kiểm tra Công việc tốt :)
Deeptechtons

1
Tôi đã viết một câu trả lời stackoverflow.com/a/17537472/1737957 cho một câu hỏi tương tự đã kiểm tra các câu trả lời được đề xuất (và thấy rằng hầu hết chúng không hoạt động). Câu trả lời này là một trong số ít hoạt động (theo bộ thử nghiệm của tôi). Liên kết đến github trên câu trả lời của tôi.
jwg

@KirkWoll - Câu trả lời này dường như không hoạt động đối với các trường hợp cạnh trong đó ngày từ có giá trị ngày cao hơn tháng đến ngày hoặc ngày nguồn là ngày nhuận. Hãy thử 2020-02-29để 2021-06-29- nó trả "1n 4m 1d", nhưng giá trị cần được "1n 4m 0d", phải không?
Enigmativity

37

Bạn có thể làm

if ( date1.AddMonths(x) > date2 )

Điều này là rất đơn giản và làm việc hoàn hảo cho tôi. Tôi đã rất ngạc nhiên khi thấy nó hoạt động như dự định khi tính một ngày từ cuối 1 tháng đến một ngày vào cuối tháng tiếp theo có ít ngày hơn. Ví dụ .. 1-31-2018 + 1 tháng = 28 tháng 2 218
lucky.expert

Đây là một trong những giải pháp tốt hơn.
barnacle.m

Giải pháp thực sự đơn giản và hiệu quả! Câu trả lời tốt nhất được đề xuất.
Cedric Arnould

2
Nếu ngày 1 = 2018-10-28 và ngày2 = 2018-12-21 thì sao? Câu trả lời sẽ là 2. trong khi câu trả lời đúng phải là 3. Vì phạm vi ngày là trong 3 tháng. nếu chúng ta chỉ đếm tháng bỏ qua ngày. Vì vậy, câu trả lời này là KHÔNG chính xác.
Tommix

Hợp lý hơn sẽ là: if ( date1.AddMonths(x).Month == date2.Month )sau đó bạn chỉ cần sử dụng x + 1 theo số tháng
Tommix

34

Nếu bạn muốn có số tháng đầy đủ chính xác, luôn luôn dương (2000-01-15, 2000-02-14 trả về 0), xem xét cả tháng là khi bạn đạt được cùng ngày vào tháng tiếp theo (giống như cách tính tuổi)

public static int GetMonthsBetween(DateTime from, DateTime to)
{
    if (from > to) return GetMonthsBetween(to, from);

    var monthDiff = Math.Abs((to.Year * 12 + (to.Month - 1)) - (from.Year * 12 + (from.Month - 1)));

    if (from.AddMonths(monthDiff) > to || to.Day < from.Day)
    {
        return monthDiff - 1;
    }
    else
    {
        return monthDiff;
    }
}

Chỉnh sửa lý do: mã cũ không đúng trong một số trường hợp như:

new { From = new DateTime(1900, 8, 31), To = new DateTime(1901, 8, 30), Result = 11 },

Test cases I used to test the function:

var tests = new[]
{
    new { From = new DateTime(1900, 1, 1), To = new DateTime(1900, 1, 1), Result = 0 },
    new { From = new DateTime(1900, 1, 1), To = new DateTime(1900, 1, 2), Result = 0 },
    new { From = new DateTime(1900, 1, 2), To = new DateTime(1900, 1, 1), Result = 0 },
    new { From = new DateTime(1900, 1, 1), To = new DateTime(1900, 2, 1), Result = 1 },
    new { From = new DateTime(1900, 2, 1), To = new DateTime(1900, 1, 1), Result = 1 },
    new { From = new DateTime(1900, 1, 31), To = new DateTime(1900, 2, 1), Result = 0 },
    new { From = new DateTime(1900, 8, 31), To = new DateTime(1900, 9, 30), Result = 0 },
    new { From = new DateTime(1900, 8, 31), To = new DateTime(1900, 10, 1), Result = 1 },
    new { From = new DateTime(1900, 1, 1), To = new DateTime(1901, 1, 1), Result = 12 },
    new { From = new DateTime(1900, 1, 1), To = new DateTime(1911, 1, 1), Result = 132 },
    new { From = new DateTime(1900, 8, 31), To = new DateTime(1901, 8, 30), Result = 11 },
};

Để tránh nhầm lẫn cho người khác, tôi nghĩ giải pháp này không đúng. Sử dụng trường hợp thử nghiệm: new { From = new DateTime(2015, 12, 31), To = new DateTime(2015, 6, 30), Result = 6 } thử nghiệm sẽ thất bại vì kết quả là 5.
Cristian Badila

Đã thêm một ý chính nhanh chóng với bản sửa lỗi tôi đề xuất ở đây
Cristian Badila

Tôi không chắc chắn tôi có được nó, chức năng của tôi trả về 6 như vậy: dotnetfiddle.net/MRZNnC
Guillaume86

Tôi đã sao chép trường hợp thử nghiệm ở đây bằng tay và nó có một lỗi. Thông số kỹ thuật thất bại phải là : new { From = new DateTime(2015, 12, 31), To = new DateTime(2016, 06, 30), Result = 6 }. "Lỗi" nằm trong to.Day < from.Daymã không tính đến việc các tháng có thể kết thúc vào một "ngày trong tháng" khác. Trong trường hợp này từ ngày 31 tháng 12 năm 2015, cho đến ngày 30 tháng 6 năm 2016, 6 tháng hoàn thành sẽ trôi qua (kể từ tháng 6 có 30 ngày) nhưng mã của bạn sẽ trở lại 5.
Cristian Badila

3
Đó là hành vi được mong đợi theo ý kiến ​​của tôi, hoặc đó là hành vi mà tôi mong đợi ít nhất. Tôi dự đoán một tháng hoàn thành là khi bạn đạt được cùng một ngày (hoặc tháng tiếp theo như trong trường hợp này).
Guillaume86

22

Tôi đã kiểm tra việc sử dụng phương pháp này trong VB.NET thông qua MSDN và dường như nó có rất nhiều công dụng. Không có một phương thức tích hợp nào như vậy trong C #. (Ngay cả đó không phải là một ý tưởng hay) bạn có thể gọi VB bằng C #.

  1. Thêm Microsoft.VisualBasic.dllvào dự án của bạn như một tài liệu tham khảo
  2. sử dụng Microsoft.VisualBasic.DateAndTime.DateDiff trong mã của bạn

7
Tại sao bạn nghĩ rằng nó không phải là một ý tưởng tốt? Theo trực giác, tôi đoán rằng thư viện 'chỉ là một thư viện .NET' khác trong thời gian chạy. Lưu ý, tôi đang chơi trò bênh vực của quỷ ở đây, tôi cũng sẽ không thể làm điều này vì nó chỉ "cảm thấy sai" (loại gian lận) nhưng tôi tự hỏi liệu có lý do kỹ thuật thuyết phục nào để không làm điều này không.
Adam Ralph

3
@AdamRalph: Không có lý do nào để không làm điều đó. Các thư viện đó được triển khai theo mã được quản lý 100%, vì vậy tất cả đều giống như mọi thứ khác. Sự khác biệt duy nhất có thể hiểu được là Microsoft.VisualBasic.dllmô-đun phải được tải, nhưng thời gian cần thiết để làm điều đó là không đáng kể. Không có lý do gì để tự lừa dối bản thân khỏi các tính năng hữu ích và được kiểm tra kỹ lưỡng chỉ vì bạn đã chọn viết chương trình của mình bằng C #. (Điều này cũng đúng với những thứ tương tự My.Application.SplashScreen.)
Cody Grey

3
Bạn sẽ thay đổi ý định nếu bạn biết rằng nó được viết bằng C #? Nó đã được. Theo cùng một logic, sử dụng System.Data và PresentationFramework cũng gian lận, những phần đáng kể của nó được viết bằng C ++ / CLI.
Hans Passant

3
@AdamRalph: Bất kỳ ví dụ cụ thể nào về "hành lý lạ" mà mùa xuân đến trong tâm trí? Hay bạn đang nói điều đó hoàn toàn là giả thuyết? Và vâng, nó có thể gây rối với suy nghĩ của một số bạn bè C # của bạn, những người đã viết một số lượng sử thi để làm điều gì đó mà bạn có thể làm trong một dòng với usingtuyên bố đúng , nhưng tôi nghi ngờ sẽ có bất kỳ thiệt hại nghiêm trọng nào.
Cody Grey

1
@Cody Grey: đồng ý, ví dụ này là tầm thường như bạn minh họa. Đó là mã bổ sung 'nhiễu' được giới thiệu bằng cách gọi một phương thức khác thường (từ phương pháp C # POV) mà tôi muốn tránh. Trong một nhóm được tổ chức tốt, những thứ như vậy dù sao cũng sẽ được chọn trong phần đánh giá mã và có thể dễ dàng tránh được. BTW - Tôi không cố tấn công VB6 / VB.NET. Tôi đã mô tả các phương thức như 'lạ' chỉ bởi vì, từ .NET POV, không có lý do gì DateAndTime.Year()để tồn tại, do DateTimecó một thuộc Yeartính. Nó chỉ tồn tại để làm cho VB.NET xuất hiện giống như VB6. Là một cựu lập trình viên VB6, tôi có thể đánh giá cao điều này ;-)
Adam Ralph

10

Để có sự khác biệt về tháng (bao gồm cả bắt đầu và kết thúc), không phân biệt ngày tháng:

DateTime start = new DateTime(2013, 1, 1);
DateTime end = new DateTime(2014, 2, 1);
var diffMonths = (end.Month + end.Year * 12) - (start.Month + start.Year * 12);

4
Hãy tưởng tượng startendgiống hệt nhau. Sau đó, bạn nhận được kết quả là 1. Làm thế nào là đúng? Tại sao bạn thêm 1 vào kết quả? Ai đang bỏ phiếu cho câu trả lời này: - /?
paul

Đối với các ngày giống hệt nhau, nó sẽ cho đầu ra là 1. Về cơ bản, nó sẽ tính tất cả các tháng bắt đầu và tháng kết thúc.
Chirag

3
Không có vẻ như sự khác biệt giữa hai mặt hàng với tôi. Sự khác biệt giữa 2 và 2 là gì? Có thực sự là 1? Tôi sẽ đề nghị sự khác biệt là 0.
paul


7

Tôi chỉ cần một cái gì đó đơn giản để phục vụ cho ngày làm việc, nơi chỉ nhập tháng / năm, vì vậy muốn có năm và tháng làm việc khác biệt. Đây là những gì tôi sử dụng, ở đây chỉ cho sự hữu ích

public static YearsMonths YearMonthDiff(DateTime startDate, DateTime endDate) {
    int monthDiff = ((endDate.Year * 12) + endDate.Month) - ((startDate.Year * 12) + startDate.Month) + 1;
    int years = (int)Math.Floor((decimal) (monthDiff / 12));
    int months = monthDiff % 12;
    return new YearsMonths {
        TotalMonths = monthDiff,
            Years = years,
            Months = months
    };
}

.NET Fiddle


4

Bạn có thể sử dụng lớp DateDiff của Thư viện Khoảng thời gian cho .NET :

// ----------------------------------------------------------------------
public void DateDiffSample()
{
  DateTime date1 = new DateTime( 2009, 11, 8, 7, 13, 59 );
  DateTime date2 = new DateTime( 2011, 3, 20, 19, 55, 28 );
  DateDiff dateDiff = new DateDiff( date1, date2 );

  // differences
  Console.WriteLine( "DateDiff.Months: {0}", dateDiff.Months );
  // > DateDiff.Months: 16

  // elapsed
  Console.WriteLine( "DateDiff.ElapsedMonths: {0}", dateDiff.ElapsedMonths );
  // > DateDiff.ElapsedMonths: 4

  // description
  Console.WriteLine( "DateDiff.GetDescription(6): {0}", dateDiff.GetDescription( 6 ) );
  // > DateDiff.GetDescription(6): 1 Year 4 Months 12 Days 12 Hours 41 Mins 29 Secs
} // DateDiffSample

2

Đây là đóng góp của tôi để có được sự khác biệt trong các Tháng mà tôi thấy là chính xác:

namespace System
{
     public static class DateTimeExtensions
     {
         public static Int32 DiffMonths( this DateTime start, DateTime end )
         {
             Int32 months = 0;
             DateTime tmp = start;

             while ( tmp < end )
             {
                 months++;
                 tmp = tmp.AddMonths( 1 );
             }

             return months;
        }
    }
}

Sử dụng:

Int32 months = DateTime.Now.DiffMonths( DateTime.Now.AddYears( 5 ) );

Bạn có thể tạo một phương thức khác gọi là DiffYears và áp dụng chính xác logic tương tự như trên và AddYears thay vì AddMonths trong vòng lặp while.


2

Điều này làm việc cho những gì tôi cần nó cho. Ngày của tháng không thành vấn đề trong trường hợp của tôi vì nó luôn luôn là ngày cuối cùng của tháng.

public static int MonthDiff(DateTime d1, DateTime d2){
    int retVal = 0;

    if (d1.Month<d2.Month)
    {
        retVal = (d1.Month + 12) - d2.Month;
        retVal += ((d1.Year - 1) - d2.Year)*12;
    }
    else
    {
        retVal = d1.Month - d2.Month;
        retVal += (d1.Year - d2.Year)*12;
    }
    //// Calculate the number of years represented and multiply by 12
    //// Substract the month number from the total
    //// Substract the difference of the second month and 12 from the total
    //retVal = (d1.Year - d2.Year) * 12;
    //retVal = retVal - d1.Month;
    //retVal = retVal - (12 - d2.Month);

    return retVal;
}

2

Cách chính xác nhất là cách này trả lại chênh lệch theo tháng theo phân số:

private double ReturnDiffereceBetweenTwoDatesInMonths(DateTime startDateTime, DateTime endDateTime)
{
    double result = 0;
    double days = 0;
    DateTime currentDateTime = startDateTime;
    while (endDateTime > currentDateTime.AddMonths(1))
    {
        result ++;

        currentDateTime = currentDateTime.AddMonths(1);
    }

    if (endDateTime > currentDateTime)
    {
        days = endDateTime.Subtract(currentDateTime).TotalDays;

    }
    return result + days/endDateTime.GetMonthDays;
}

2

Đây là một giải pháp đơn giản mà ít nhất là cho tôi. Mặc dù đây có thể không phải là nhanh nhất vì nó sử dụng tính năng AddMonth tuyệt vời của DateTime trong một vòng lặp:

public static int GetMonthsDiff(DateTime start, DateTime end)
{
    if (start > end)
        return GetMonthsDiff(end, start);

    int months = 0;
    do
    {
        start = start.AddMonths(1);
        if (start > end)
            return months;

        months++;
    }
    while (true);
}

1
Public Class ClassDateOperation
    Private prop_DifferenceInDay As Integer
    Private prop_DifferenceInMonth As Integer
    Private prop_DifferenceInYear As Integer


    Public Function DayMonthYearFromTwoDate(ByVal DateStart As Date, ByVal DateEnd As Date) As ClassDateOperation
        Dim differenceInDay As Integer
        Dim differenceInMonth As Integer
        Dim differenceInYear As Integer
        Dim myDate As Date

        DateEnd = DateEnd.AddDays(1)

        differenceInYear = DateEnd.Year - DateStart.Year

        If DateStart.Month <= DateEnd.Month Then
            differenceInMonth = DateEnd.Month - DateStart.Month
        Else
            differenceInYear -= 1
            differenceInMonth = (12 - DateStart.Month) + DateEnd.Month
        End If


        If DateStart.Day <= DateEnd.Day Then
            differenceInDay = DateEnd.Day - DateStart.Day
        Else

            myDate = CDate("01/" & DateStart.AddMonths(1).Month & "/" & DateStart.Year).AddDays(-1)
            If differenceInMonth <> 0 Then
                differenceInMonth -= 1
            Else
                differenceInMonth = 11
                differenceInYear -= 1
            End If

            differenceInDay = myDate.Day - DateStart.Day + DateEnd.Day

        End If

        prop_DifferenceInDay = differenceInDay
        prop_DifferenceInMonth = differenceInMonth
        prop_DifferenceInYear = differenceInYear

        Return Me
    End Function

    Public ReadOnly Property DifferenceInDay() As Integer
        Get
            Return prop_DifferenceInDay
        End Get
    End Property

    Public ReadOnly Property DifferenceInMonth As Integer
        Get
            Return prop_DifferenceInMonth
        End Get
    End Property

    Public ReadOnly Property DifferenceInYear As Integer
        Get
            Return prop_DifferenceInYear
        End Get
    End Property

End Class

1

Đây là từ thư viện của riêng tôi, sẽ trả lại sự khác biệt của tháng giữa hai ngày.

public static int MonthDiff(DateTime d1, DateTime d2)
{
    int retVal = 0;

    // Calculate the number of years represented and multiply by 12
    // Substract the month number from the total
    // Substract the difference of the second month and 12 from the total
    retVal = (d1.Year - d2.Year) * 12;
    retVal = retVal - d1.Month;
    retVal = retVal - (12 - d2.Month);

    return retVal;
}

1
Nó có hoạt động không? Tôi liên tục nhận được 11 trên giấy cho Jan-31-2014Dec-31-2013
Dave Cousineau

1

Bạn có thể có một chức năng như thế này.

Ví dụ: từ 2012/12/27 đến 2012/12/29 trở thành 3 ngày. Tương tự, từ 2012/12/15 đến 2013/01/15 trở thành 2 tháng, vì đến 2013/01/14 là 1 tháng. từ ngày 15, tháng thứ 2 bắt đầu.

Bạn có thể xóa "=" trong điều kiện if thứ hai, nếu bạn không muốn bao gồm cả hai ngày trong phép tính. tức là từ 2012/12/15 đến 2013/01/15 là 1 tháng.

public int GetMonths(DateTime startDate, DateTime endDate)
{
    if (startDate > endDate)
    {
        throw new Exception("Start Date is greater than the End Date");
    }

    int months = ((endDate.Year * 12) + endDate.Month) - ((startDate.Year * 12) + startDate.Month);

    if (endDate.Day >= startDate.Day)
    {
        months++;
    }

    return months;
}

1

bạn có thể sử dụng phần mở rộng sau: Code

public static class Ext
{
    #region Public Methods

    public static int GetAge(this DateTime @this)
    {
        var today = DateTime.Today;
        return ((((today.Year - @this.Year) * 100) + (today.Month - @this.Month)) * 100 + today.Day - @this.Day) / 10000;
    }

    public static int DiffMonths(this DateTime @from, DateTime @to)
    {
        return (((((@to.Year - @from.Year) * 12) + (@to.Month - @from.Month)) * 100 + @to.Day - @from.Day) / 100);
    }

    public static int DiffYears(this DateTime @from, DateTime @to)
    {
        return ((((@to.Year - @from.Year) * 100) + (@to.Month - @from.Month)) * 100 + @to.Day - @from.Day) / 10000;
    }

    #endregion Public Methods
}

Thực hiện !

int Age;
int years;
int Months;
//Replace your own date
var d1 = new DateTime(2000, 10, 22);
var d2 = new DateTime(2003, 10, 20);
//Age
Age = d1.GetAge();
Age = d2.GetAge();
//positive
years = d1.DiffYears(d2);
Months = d1.DiffMonths(d2);
//negative
years = d2.DiffYears(d1);
Months = d2.DiffMonths(d1);
//Or
Months = Ext.DiffMonths(d1, d2);
years = Ext.DiffYears(d1, d2); 

1

Đây là một giải pháp ngắn gọn hơn nhiều chỉ sử dụng VB.Net DateDiff cho Năm, Tháng, Ngày. Bạn cũng có thể tải thư viện DateDiff bằng C #.

date1 phải là <= date2

VB.NET

Dim date1 = Now.AddDays(-2000)
Dim date2 = Now
Dim diffYears = DateDiff(DateInterval.Year, date1, date2) - If(date1.DayOfYear > date2.DayOfYear, 1, 0)
Dim diffMonths = DateDiff(DateInterval.Month, date1, date2) - diffYears * 12 - If(date1.Day > date2.Day, 1, 0)
Dim diffDays = If(date2.Day >= date1.Day, date2.Day - date1.Day, date2.Day + (Date.DaysInMonth(date1.Year, date1.Month) - date1.Day))

C #

DateTime date1 = Now.AddDays(-2000);
DateTime date2 = Now;
int diffYears = DateDiff(DateInterval.Year, date1, date2) - date1.DayOfYear > date2.DayOfYear ? 1 : 0;
int diffMonths = DateDiff(DateInterval.Month, date1, date2) - diffYears * 12 - date1.Day > date2.Day ? 1 : 0;
int diffDays = date2.Day >= date1.Day ? date2.Day - date1.Day : date2.Day + (System.DateTime.DaysInMonth(date1.Year, date1.Month) - date1.Day);

1

Đây là câu trả lời cho câu trả lời của Kirk Woll. Tôi chưa có đủ điểm danh tiếng để trả lời bình luận ...

Tôi thích giải pháp của Kirk và sẽ xấu hổ xé nó ra và sử dụng nó trong mã của tôi, nhưng khi tôi nhìn qua nó tôi nhận ra nó quá phức tạp. Chuyển đổi và lặp không cần thiết, và một nhà xây dựng công cộng là vô nghĩa để sử dụng.

Đây là bản viết lại của tôi:

public class DateTimeSpan {
    private DateTime _date1;
    private DateTime _date2;
    private int _years;
    private int _months;
    private int _days;
    private int _hours;
    private int _minutes;
    private int _seconds;
    private int _milliseconds;

    public int Years { get { return _years; } }
    public int Months { get { return _months; } }
    public int Days { get { return _days; } }
    public int Hours { get { return _hours; } }
    public int Minutes { get { return _minutes; } }
    public int Seconds { get { return _seconds; } }
    public int Milliseconds { get { return _milliseconds; } }

    public DateTimeSpan(DateTime date1, DateTime date2) {
        _date1 = (date1 > date2) ? date1 : date2;
        _date2 = (date2 < date1) ? date2 : date1;

        _years = _date1.Year - _date2.Year;
        _months = (_years * 12) + _date1.Month - _date2.Month;
        TimeSpan t = (_date2 - _date1);
        _days = t.Days;
        _hours = t.Hours;
        _minutes = t.Minutes;
        _seconds = t.Seconds;
        _milliseconds = t.Milliseconds;

    }

    public static DateTimeSpan CompareDates(DateTime date1, DateTime date2) {
        return new DateTimeSpan(date1, date2);
    }
}

Cách sử dụng1, khá giống nhau:

void Main()
{
    DateTime compareTo = DateTime.Parse("8/13/2010 8:33:21 AM");
    DateTime now = DateTime.Parse("2/9/2012 10:10:11 AM");
    var dateSpan = new DateTimeSpan(compareTo, now);
    Console.WriteLine("Years: " + dateSpan.Years);
    Console.WriteLine("Months: " + dateSpan.Months);
    Console.WriteLine("Days: " + dateSpan.Days);
    Console.WriteLine("Hours: " + dateSpan.Hours);
    Console.WriteLine("Minutes: " + dateSpan.Minutes);
    Console.WriteLine("Seconds: " + dateSpan.Seconds);
    Console.WriteLine("Milliseconds: " + dateSpan.Milliseconds);
}

Cách sử dụng2, tương tự:

void Main()
{
    DateTime compareTo = DateTime.Parse("8/13/2010 8:33:21 AM");
    DateTime now = DateTime.Parse("2/9/2012 10:10:11 AM");
    Console.WriteLine("Years: " + DateTimeSpan.CompareDates(compareTo, now).Years);
    Console.WriteLine("Months: " + DateTimeSpan.CompareDates(compareTo, now).Months);
    Console.WriteLine("Days: " + DateTimeSpan.CompareDates(compareTo, now).Days);
    Console.WriteLine("Hours: " + DateTimeSpan.CompareDates(compareTo, now).Hours);
    Console.WriteLine("Minutes: " + DateTimeSpan.CompareDates(compareTo, now).Minutes);
    Console.WriteLine("Seconds: " + DateTimeSpan.CompareDates(compareTo, now).Seconds);
    Console.WriteLine("Milliseconds: " + DateTimeSpan.CompareDates(compareTo, now).Milliseconds);
}

1

Trong trường hợp của tôi, cần phải tính toán toàn bộ tháng từ ngày bắt đầu đến ngày trước ngày này trong tháng tiếp theo hoặc từ đầu đến cuối tháng.


Vd: từ 1/1/2018 đến 31/1/2018 là một tháng hoàn thành
Ex2: từ 5/1/2018 đến 4/2/2018 là một tháng hoàn chỉnh

Vì vậy, dựa trên đây là giải pháp của tôi:

public static DateTime GetMonthEnd(DateTime StartDate, int MonthsCount = 1)
{
    return StartDate.AddMonths(MonthsCount).AddDays(-1);
}
public static Tuple<int, int> CalcPeriod(DateTime StartDate, DateTime EndDate)
{
    int MonthsCount = 0;
    Tuple<int, int> Period;
    while (true)
    {
        if (GetMonthEnd(StartDate) > EndDate)
            break;
        else
        {
            MonthsCount += 1;
            StartDate = StartDate.AddMonths(1);
        }
    }
    int RemainingDays = (EndDate - StartDate).Days + 1;
    Period = new Tuple<int, int>(MonthsCount, RemainingDays);
    return Period;
}

Sử dụng:

Tuple<int, int> Period = CalcPeriod(FromDate, ToDate);

Lưu ý: trong trường hợp của tôi, cần phải tính các ngày còn lại sau các tháng hoàn chỉnh, vì vậy nếu không phải là trường hợp của bạn, bạn có thể bỏ qua kết quả ngày hoặc thậm chí bạn có thể thay đổi phương thức trả về từ tuple sang số nguyên.


1
public static int PayableMonthsInDuration(DateTime StartDate, DateTime EndDate)
{
    int sy = StartDate.Year; int sm = StartDate.Month; int count = 0;
    do
    {
        count++;if ((sy == EndDate.Year) && (sm >= EndDate.Month)) { break; }
        sm++;if (sm == 13) { sm = 1; sy++; }
    } while ((EndDate.Year >= sy) || (EndDate.Month >= sm));
    return (count);
}

Giải pháp này dành cho tính toán Thuê / đăng ký, trong đó sự khác biệt không có nghĩa là trừ, nó có nghĩa là khoảng thời gian trong hai ngày đó.


1

Có 3 trường hợp: cùng năm, năm trước và các năm khác.

Nếu ngày trong tháng không quan trọng ...

public int GetTotalNumberOfMonths(DateTime start, DateTime end)
{
    // work with dates in the right order
    if (start > end)
    {
        var swapper = start;
        start = end;
        end = swapper;
    }

    switch (end.Year - start.Year)
    {
        case 0: // Same year
            return end.Month - start.Month;

        case 1: // last year
            return (12 - start.Month) + end.Month;

        default:
            return 12 * (3 - (end.Year - start.Year)) + (12 - start.Month) + end.Month;
    }
}

1

Tôi đã viết một chức năng để thực hiện điều này, bởi vì những cách khác không làm việc cho tôi.

public string getEndDate (DateTime startDate,decimal monthCount)
{
    int y = startDate.Year;
    int m = startDate.Month;

    for (decimal  i = monthCount; i > 1; i--)
    {
        m++;
        if (m == 12)
        { y++;
            m = 1;
        }
    }
    return string.Format("{0}-{1}-{2}", y.ToString(), m.ToString(), startDate.Day.ToString());
}

Vui lòng trả lời bằng tiếng Anh (so với bất kỳ ngôn ngữ được phát minh nào ...)
kleopatra

Tại sao không chỉ làm startDate.AddMonths (thángCount) .ToShortDateString ()? Điều này không trả lời câu hỏi ban đầu được hỏi nào!
TabbyCool

oh, xin lỗi @TabbyCool, mã này hoạt động tốt trong chương trình của tôi! quy tắc lập trình viên nói: mã đầu tiên hoạt động và sau đó tối ưu hóa! tanx cho bình luận của bạn :)
reza akhlaghi

1

Sự hiểu biết của tôi về tổng số tháng chênh lệch giữa 2 ngày có một phần không thể tách rời và một phần (ngày quan trọng).

Phần không thể thiếu là sự khác biệt đầy đủ trong tháng.

Đối với tôi, phần phân số là sự khác biệt của% trong ngày (đến toàn bộ ngày trong tháng) giữa tháng bắt đầu và tháng kết thúc.

public static class DateTimeExtensions
{
    public static double TotalMonthsDifference(this DateTime from, DateTime to)
    {
        //Compute full months difference between dates
        var fullMonthsDiff = (to.Year - from.Year)*12 + to.Month - from.Month;

        //Compute difference between the % of day to full days of each month
        var fractionMonthsDiff = ((double)(to.Day-1) / (DateTime.DaysInMonth(to.Year, to.Month)-1)) -
            ((double)(from.Day-1)/ (DateTime.DaysInMonth(from.Year, from.Month)-1));

        return fullMonthsDiff + fractionMonthsDiff;
    }
}

Với phần mở rộng này, đó là những kết quả:

2/29/2000 TotalMonthsDifference 2/28/2001 => 12
2/28/2000 TotalMonthsDifference 2/28/2001 => 12.035714285714286
01/01/2000 TotalMonthsDifference 01/16/2000 => 0.5
01/31/2000 TotalMonthsDifference 01/01/2000 => -1.0
01/31/2000 TotalMonthsDifference 02/29/2000 => 1.0
01/31/2000 TotalMonthsDifference 02/28/2000 => 0.9642857142857143
01/31/2001 TotalMonthsDifference 02/28/2001 => 1.0

1

Không có nhiều câu trả lời rõ ràng về điều này bởi vì bạn luôn giả định mọi thứ.

Giải pháp này tính toán giữa hai ngày các tháng giữa giả sử bạn muốn lưu ngày trong tháng để so sánh, (có nghĩa là ngày trong tháng được xem xét trong tính toán)

Ví dụ: nếu bạn có ngày 30 tháng 1 năm 2012, ngày 29 tháng 2 năm 2012 sẽ không phải là một tháng mà là ngày 01 tháng 3 năm 2013.

Nó đã được thử nghiệm khá kỹ lưỡng, có thể sẽ dọn sạch nó sau khi chúng ta sử dụng nó, nhưng ở đây:

private static int TotalMonthDifference(DateTime dtThis, DateTime dtOther)
{
    int intReturn = 0;
    bool sameMonth = false;

    if (dtOther.Date < dtThis.Date) //used for an error catch in program, returns -1
        intReturn--;

    int dayOfMonth = dtThis.Day; //captures the month of day for when it adds a month and doesn't have that many days
    int daysinMonth = 0; //used to caputre how many days are in the month

    while (dtOther.Date > dtThis.Date) //while Other date is still under the other
    {
        dtThis = dtThis.AddMonths(1); //as we loop, we just keep adding a month for testing
        daysinMonth = DateTime.DaysInMonth(dtThis.Year, dtThis.Month); //grabs the days in the current tested month

        if (dtThis.Day != dayOfMonth) //Example 30 Jan 2013 will go to 28 Feb when a month is added, so when it goes to march it will be 28th and not 30th
        {
            if (daysinMonth < dayOfMonth) // uses day in month max if can't set back to day of month
                dtThis.AddDays(daysinMonth - dtThis.Day);
            else
                dtThis.AddDays(dayOfMonth - dtThis.Day);
        }
        if (((dtOther.Year == dtThis.Year) && (dtOther.Month == dtThis.Month))) //If the loop puts it in the same month and year
        {
            if (dtOther.Day >= dayOfMonth) //check to see if it is the same day or later to add one to month
                intReturn++;
            sameMonth = true; //sets this to cancel out of the normal counting of month
        }
        if ((!sameMonth)&&(dtOther.Date > dtThis.Date))//so as long as it didn't reach the same month (or if i started in the same month, one month ahead, add a month)
            intReturn++;
    }
    return intReturn; //return month
}

1

Dựa trên công việc DateTimeSpan tuyệt vời được thực hiện ở trên, tôi đã bình thường hóa mã một chút; điều này dường như hoạt động khá tốt:

public class DateTimeSpan
{
  private DateTimeSpan() { }

  private DateTimeSpan(int years, int months, int days, int hours, int minutes, int seconds, int milliseconds)
  {
    Years = years;
    Months = months;
    Days = days;
    Hours = hours;
    Minutes = minutes;
    Seconds = seconds;
    Milliseconds = milliseconds;
  }

  public int Years { get; private set; } = 0;
  public int Months { get; private set; } = 0;
  public int Days { get; private set; } = 0;
  public int Hours { get; private set; } = 0;
  public int Minutes { get; private set; } = 0;
  public int Seconds { get; private set; } = 0;
  public int Milliseconds { get; private set; } = 0;

  public static DateTimeSpan CompareDates(DateTime StartDate, DateTime EndDate)
  {
    if (StartDate.Equals(EndDate)) return new DateTimeSpan();
    DateTimeSpan R = new DateTimeSpan();
    bool Later;
    if (Later = StartDate > EndDate)
    {
      DateTime D = StartDate;
      StartDate = EndDate;
      EndDate = D;
    }

    // Calculate Date Stuff
    for (DateTime D = StartDate.AddYears(1); D < EndDate; D = D.AddYears(1), R.Years++) ;
    if (R.Years > 0) StartDate = StartDate.AddYears(R.Years);
    for (DateTime D = StartDate.AddMonths(1); D < EndDate; D = D.AddMonths(1), R.Months++) ;
    if (R.Months > 0) StartDate = StartDate.AddMonths(R.Months);
    for (DateTime D = StartDate.AddDays(1); D < EndDate; D = D.AddDays(1), R.Days++) ;
    if (R.Days > 0) StartDate = StartDate.AddDays(R.Days);

    // Calculate Time Stuff
    TimeSpan T1 = EndDate - StartDate;
    R.Hours = T1.Hours;
    R.Minutes = T1.Minutes;
    R.Seconds = T1.Seconds;
    R.Milliseconds = T1.Milliseconds;

    // Return answer. Negate values if the Start Date was later than the End Date
    if (Later)
      return new DateTimeSpan(-R.Years, -R.Months, -R.Days, -R.Hours, -R.Minutes, -R.Seconds, -R.Milliseconds);
    return R;
  }
}

Khi so sánh với CompareDates(x, y)nơi x={01/02/2019 00:00:00}y={01/05/2020 00:00:00}sau đó Monthscho tôi2
Bassie

1

Hàm tĩnh đơn giản này tính toán tỷ lệ các tháng giữa hai Dữ liệu, ví dụ:

  • 1.1. đến 31.1. = 1,0
  • 1.4. đến 15.4. = 0,5
  • 16.4. đến 30.4. = 0,5
  • 1.3. đến 1.4. = 1 + 1/30

Hàm giả định rằng ngày đầu tiên nhỏ hơn ngày thứ hai. Để xử lý các khoảng thời gian âm, người ta có thể dễ dàng sửa đổi hàm bằng cách đưa ra một dấu hiệu và một hoán đổi biến đổi ở đầu.

public static double GetDeltaMonths(DateTime t0, DateTime t1)
{
     DateTime t = t0;
     double months = 0;
     while(t<=t1)
     {
         int daysInMonth = DateTime.DaysInMonth(t.Year, t.Month);
         DateTime endOfMonth = new DateTime(t.Year, t.Month, daysInMonth);
         int cutDay = endOfMonth <= t1 ? daysInMonth : t1.Day;
         months += (cutDay - t.Day + 1) / (double) daysInMonth;
         t = new DateTime(t.Year, t.Month, 1).AddMonths(1);
     }
     return Math.Round(months,2);
 }

0

Để có thể tính toán sự khác biệt giữa 2 ngày trong tháng là một điều hoàn toàn hợp lý và cần thiết trong nhiều ứng dụng kinh doanh. Một số lập trình viên ở đây đã cung cấp các nhận xét như - sự khác biệt trong các tháng giữa "tháng 5 năm 2010" và "ngày 16 tháng 6 năm 2010, sự khác biệt trong các tháng giữa ngày 31 tháng 12 năm 2010 và ngày 1 tháng 1 năm 2011? - đã không hiểu những điều cơ bản của ứng dụng kinh doanh.

Dưới đây là câu trả lời cho 2 ý kiến ​​trên - Số tháng trong khoảng từ 1 tháng 5 năm 2010 đến 16 tháng 6 năm 2010 là 1 tháng, số tháng trong khoảng từ 31 tháng 12 năm 2010 đến 1 tháng 1 năm 2011 là 0. Nó sẽ rất ngu ngốc khi tính toán chúng là 1,5 tháng và 1 giây, như các lập trình viên ở trên đã đề xuất.

Những người đã làm việc trên thẻ tín dụng, xử lý thế chấp, xử lý thuế, xử lý tiền thuê nhà, tính lãi hàng tháng và một loạt các giải pháp kinh doanh khác sẽ đồng ý.

Vấn đề là một chức năng như vậy không được bao gồm trong C # hoặc VB.NET cho vấn đề đó. Datediff chỉ đưa vào tài khoản năm hoặc thành phần tháng, vì vậy thực sự là vô dụng.

Dưới đây là một số ví dụ thực tế về nơi bạn cần và chính xác có thể tính toán tháng:

Bạn đã sống trong một hợp đồng thuê ngắn hạn từ 18-feb đến 23-aug. Bạn ở đó bao nhiêu tháng Câu trả lời rất đơn giản - 6 tháng

Bạn có một tài khoản ngân hàng nơi tính lãi và thanh toán vào cuối mỗi tháng. Bạn gửi tiền vào ngày 10 tháng 6 và lấy ra 29-oct (cùng năm). Bạn nhận được bao nhiêu tháng tiền lãi? Câu trả lời rất đơn giản - 4 tháng (một lần nữa số ngày không quan trọng)

Trong các ứng dụng kinh doanh, hầu hết thời gian, khi bạn cần tính toán tháng, đó là vì bạn cần biết 'tháng đầy đủ dựa trên cách con người tính thời gian; không dựa trên một số suy nghĩ trừu tượng / không liên quan.


5
Đây là một trong những lý do tại sao kế toán không phải là toán học. Trong kế toán kết quả phụ thuộc vào cách bạn tính toán .. Tôi biết điểm của bạn và tôi biết "quan điểm kinh doanh chung" về điều này, nhưng giải thích này hoàn toàn sai. Trong khoảng thời gian 2012.11.30 đến 2012.12.01, có 0, hoặc 1/30 hoặc 1/31 hoặc 1 hoặc 2 tháng, tùy thuộc vào những gì bạn yêu cầu . Là ngày bao gồm hoặc bao gồm? Bạn đã yêu cầu số tháng vượt qua, chạm vào, hoặc vượt qua? Bạn có muốn làm tròn, làm tròn, hoặc chính xác?
quetzalcoatl

3
Bây giờ hãy giải thích nó cho một anh chàng kinh doanh hoặc một kế toán viên và họ sẽ cho bạn một cái nhìn khó hiểu. Điều đó luôn luôn "rõ ràng với họ rằng tất nhiên họ có nghĩa là X và Y và Z, làm thế nào bạn có thể nghĩ khác?" Bây giờ có được một số doanh nhân và cố gắng để họ đồng ý về chủ đề này. Kế toán có nhiều khả năng đồng ý, bởi vì tại một số điểm, họ sẽ sử dụng toán học để kiểm tra xem những tùy chọn nào họ có thể tình cờ tổng hợp cùng kỳ hai lần, v.v. Ngay cả các ví dụ về tính toán của bạn là không thể tranh cãi và phụ thuộc vào khu vực, hoặc không hợp lệ như họ cho là quy tắc kinh doanh thêm như bỏ qua ngày thêm.
quetzalcoatl

2
-1 Bạn đang cho rằng tất cả phần mềm là một "ứng dụng kinh doanh". Mục đích của mã trong câu hỏi không được đề cập. Bạn cũng cho rằng tất cả các "ứng dụng kinh doanh" đều có cùng một quy tắc, điều này hoàn toàn không đúng.
Jesse Webb

0

Cấu trúc Kirks được mở rộng với ToString (định dạng) và Thời lượng (dài ms)

 public struct DateTimeSpan
{
    private readonly int years;
    private readonly int months;
    private readonly int days;
    private readonly int hours;
    private readonly int minutes;
    private readonly int seconds;
    private readonly int milliseconds;

    public DateTimeSpan(int years, int months, int days, int hours, int minutes, int seconds, int milliseconds)
    {
        this.years = years;
        this.months = months;
        this.days = days;
        this.hours = hours;
        this.minutes = minutes;
        this.seconds = seconds;
        this.milliseconds = milliseconds;
    }

    public int Years { get { return years; } }
    public int Months { get { return months; } }
    public int Days { get { return days; } }
    public int Hours { get { return hours; } }
    public int Minutes { get { return minutes; } }
    public int Seconds { get { return seconds; } }
    public int Milliseconds { get { return milliseconds; } }

    enum Phase { Years, Months, Days, Done }


    public string ToString(string format)
    {
        format = format.Replace("YYYY", Years.ToString());
        format = format.Replace("MM", Months.ToString());
        format = format.Replace("DD", Days.ToString());
        format = format.Replace("hh", Hours.ToString());
        format = format.Replace("mm", Minutes.ToString());
        format = format.Replace("ss", Seconds.ToString());
        format = format.Replace("ms", Milliseconds.ToString());
        return format;
    }


    public static DateTimeSpan Duration(long ms)
    {
        DateTime dt = new DateTime();
        return CompareDates(dt, dt.AddMilliseconds(ms));
    }


    public static DateTimeSpan CompareDates(DateTime date1, DateTime date2)
    {
        if (date2 < date1)
        {
            var sub = date1;
            date1 = date2;
            date2 = sub;
        }

        DateTime current = date1;
        int years = 0;
        int months = 0;
        int days = 0;

        Phase phase = Phase.Years;
        DateTimeSpan span = new DateTimeSpan();

        while (phase != Phase.Done)
        {
            switch (phase)
            {
                case Phase.Years:
                    if (current.AddYears(years + 1) > date2)
                    {
                        phase = Phase.Months;
                        current = current.AddYears(years);
                    }
                    else
                    {
                        years++;
                    }
                    break;
                case Phase.Months:
                    if (current.AddMonths(months + 1) > date2)
                    {
                        phase = Phase.Days;
                        current = current.AddMonths(months);
                    }
                    else
                    {
                        months++;
                    }
                    break;
                case Phase.Days:
                    if (current.AddDays(days + 1) > date2)
                    {
                        current = current.AddDays(days);
                        var timespan = date2 - current;
                        span = new DateTimeSpan(years, months, days, timespan.Hours, timespan.Minutes, timespan.Seconds, timespan.Milliseconds);
                        phase = Phase.Done;
                    }
                    else
                    {
                        days++;
                    }
                    break;
            }
        }

        return span;
    }
}

0
  var dt1 = (DateTime.Now.Year * 12) + DateTime.Now.Month;
  var dt2 = (DateTime.Now.AddMonths(-13).Year * 12) + DateTime.Now.AddMonths(-13).Month;
  Console.WriteLine(dt1);
  Console.WriteLine(dt2);
  Console.WriteLine((dt1 - dt2));
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.