ความแตกต่างในเดือนระหว่างวันที่สองวัน


334

จะคำนวณความแตกต่างเป็นเดือนระหว่างวันที่สองวันใน C # ได้อย่างไร

มีวิธีเทียบเท่ากับ VB DateDiff()ใน C # หรือไม่ ฉันต้องการค้นหาความแตกต่างในเดือนระหว่างวันที่สองวันที่มีปี เอกสารบอกว่าฉันสามารถใช้TimeSpanเช่น:

TimeSpan ts = date1 - date2;

แต่นี่ให้ข้อมูลฉันในหน่วยวัน ฉันไม่ต้องการหารจำนวนนี้ด้วย 30เพราะไม่ใช่ทุก ๆ เดือนคือ 30 วันและเนื่องจากค่าตัวถูกดำเนินการทั้งสองค่อนข้างแยกจากกันฉันกลัวว่าการหารด้วย 30 อาจให้ค่าผิด

ข้อเสนอแนะใด ๆ


27
กำหนด "ความแตกต่างในเดือน" ความแตกต่างในเดือนระหว่าง "พฤษภาคม 1,2010" และ "16 มิถุนายน 2010" คืออะไร? 1.5, 1 หรืออย่างอื่น
เฉินเฉิ

7
หรือเพื่อเน้นประเด็นนี้ต่อไปความแตกต่างของเดือนระหว่าง 31 ธันวาคม 2010 ถึง 1 มกราคม 2011 คืออะไร ขึ้นอยู่กับเวลากลางวันนี่อาจแตกต่างเพียง 1 วินาทีเท่านั้น คุณจะนับสิ่งนี้เป็นผลต่างของหนึ่งเดือนหรือไม่?
stakx - ไม่ได้มีส่วนร่วมอีก

นี่คือรหัสที่ง่ายและสั้นในกรณีที่คุณยังไม่สามารถรับคำตอบได้ดูPOST stackoverflow.com/questions/8820603//
wirol

11
แดนนี่: 1 เดือนกับ 15 วัน stakx: 0 เดือนและ 1 วัน จุดคือการได้รับองค์ประกอบเดือน ดูเหมือนว่าฉันจะค่อนข้างชัดเจนและเป็นคำถามที่ดี
Kirk Woll

DateDiffการปลูกฝัง: การอ้างอิงแหล่งข้อมูล Microsoft#VisualBasic /
dovid

คำตอบ:


462

สมมติว่าวันของเดือนนั้นไม่เกี่ยวข้อง (เช่นความแตกต่างระหว่าง 2011.1.1 และ 2010.12.31 คือ 1) กับวันที่ 1> วันที่ 2 ให้ค่าบวกและวันที่ 2> วันที่ 1 ค่าลบ

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

หรือสมมติว่าคุณต้องการจำนวน 'เดือนเฉลี่ย' ระหว่างวันที่สองวันโดยประมาณดังต่อไปนี้ควรใช้กับความแตกต่างของวันที่ทั้งหมด แต่มีขนาดใหญ่มาก

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

หมายเหตุหากคุณต้องใช้โซลูชันหลังการทดสอบหน่วยของคุณควรระบุช่วงวันที่ที่กว้างที่สุดซึ่งแอปพลิเคชันของคุณถูกออกแบบมาเพื่อทำงานและตรวจสอบความถูกต้องของผลการคำนวณตามนั้น


อัปเดต (ขอบคุณGary )

หากใช้วิธีการ 'เดือนเฉลี่ยจำนวนเล็กน้อยที่ถูกต้องมากขึ้นเพื่อใช้สำหรับ' ค่าเฉลี่ยของจำนวนวันต่อปีคือ365.2425


3
@Kurru - 365/12 เป็นเพียงการวัดโดยประมาณของความยาวเฉลี่ยของเดือนในวัน มันเป็นมาตรการที่ไม่ถูกต้อง สำหรับช่วงวันที่ขนาดเล็กความไม่ถูกต้องนี้สามารถยอมรับได้ แต่สำหรับช่วงวันที่ขนาดใหญ่มากความไม่ถูกต้องนี้อาจมีความสำคัญ
Adam Ralph

21
ฉันคิดว่าจำเป็นต้องพิจารณาองค์ประกอบของวัน บางสิ่งเช่นนี้ (date1.Year - date2.Year) * 12 + date1.Month - date2.Month + (date1.Day >= date2.Day ? 0 : -1)
DrunkCoder

2
@DunkunkCoder มันขึ้นอยู่กับความต้องการของระบบที่กำหนด ในบางกรณีทางออกของคุณอาจเป็นทางเลือกที่ดีที่สุด เช่นการพิจารณาว่าจะเกิดอะไรขึ้นเมื่อวันที่สองวันมีเดือน 31 วันเดือน 30 วัน 28 วันกุมภาพันธ์หรือ 29 วันกุมภาพันธ์ หากผลลัพธ์ของสูตรของคุณส่งมอบสิ่งที่ระบบต้องการนั้นเป็นตัวเลือกที่เหมาะสมอย่างชัดเจน ถ้าไม่เช่นนั้นจะต้องมีอย่างอื่น
Adam Ralph

6
อย่างที่สองที่อดัมพูดฉันใช้เวลาเขียนโค้ดสำหรับ Acturaries การคำนวณบางคนหารด้วยจำนวนวันรอบขึ้นโดยวันที่ 30 จะได้รับตัวเลขรายเดือน บางครั้งนับเดือนสันนิษฐานว่าทุกวันจะเริ่มต้นในวันแรกของเดือนนับทั้งเดือนตาม ไม่มีวิธีที่ดีที่สุดในการคำนวณวันที่ หากคุณไม่ได้เป็นลูกค้าที่คุณกำลังเขียนรหัสไว้ให้ผลักดันการสำรองข้อมูลนี้และชี้แจงให้ลูกค้าของคุณทราบ
Binary Worrier

1
365.2425 เป็นจำนวนวันที่แม่นยำยิ่งขึ้นเล็กน้อยในปฏิทิน Gregorian ถ้านั่นคือสิ่งที่คุณกำลังใช้ อย่างไรก็ตามตาม DateTime.MaxValue (1 มกราคม 10,000) นั่นแตกต่างกันเพียง 59 วัน นอกจากนี้คำจำกัดความของปีอาจจะแตกต่างกันมากขึ้นอยู่กับมุมมองของคุณen.wikipedia.org/wiki/Year
Gary

207

นี่คือโซลูชันที่ครอบคลุมเพื่อส่งคืน a DateTimeSpanซึ่งคล้ายกับ a TimeSpanยกเว้นว่าจะรวมคอมโพเนนต์วันที่ทั้งหมดนอกเหนือจากคอมโพเนนต์เวลา

การใช้งาน:

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

ขาออก:

ปี: 1
เดือน: 5
วัน: 27
ชั่วโมง: 1
นาที: 36
วินาที: 50
มิลลิวินาที: 0

เพื่อความสะดวกฉันได้ลอจิกตรรกะลงในโครงสร้างDateTimeSpanแต่คุณอาจย้ายวิธีการCompareDatesทุกที่ที่คุณเห็นว่าเหมาะสม โปรดทราบว่าไม่สำคัญว่าวันใดจะมาก่อนวันอื่น

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

2
@ KirkWoll ขอบคุณ แต่ทำไม DateTimeSpan ถึงส่งคืน34วันสำหรับความแตกต่างของเวลาในวันนี้จริง ๆ แล้วมันเป็น35 timeanddate.com/date/…
Deeptechtons

@ Deeptechtons จับดี มีปัญหาสองสามข้อที่คุณแจ้งให้ฉันทราบทั้งเรื่องวันที่เริ่มต้นคือ31วันที่ "ผ่าน" เดือนที่มีจำนวนวันน้อยลง ฉันได้ย้อนกลับตรรกะ (เพื่อให้มันจากต้นถึงช้ากว่าในทางกลับกัน) และตอนนี้สะสมเดือนโดยไม่ต้องแก้ไขวันที่ปัจจุบัน (และผ่านในเดือนระหว่างกับวันที่น้อยกว่า) ยังไม่แน่ใจว่าผลลัพธ์ที่สมบูรณ์แบบทั้งหมด ควรจะเป็นเมื่อเปรียบเทียบการ10/31/2012 11/30/2012ตอนนี้ผลลัพธ์คือ1เดือน
Kirk Woll

@ KirkWoll ขอบคุณสำหรับการอัปเดตบางทีฉันอาจได้ gotchas เพิ่มอีกสองสามขอให้ฉันยืนยันหลังจากการทดสอบบางอย่างงานที่ดี :)
Deeptechtons

1
ฉันเขียนคำตอบstackoverflow.com/a/17537472/1737957ไปยังคำถามที่คล้ายกันซึ่งทดสอบคำตอบที่เสนอ (และพบว่าส่วนใหญ่ไม่ทำงาน) คำตอบนี้เป็นหนึ่งในไม่กี่คนที่ทำงาน (ตามชุดทดสอบของฉัน) เชื่อมโยงไปยัง GitHub ในคำตอบของฉัน
jwg

@KirkWoll - คำตอบนี้ไม่ทำงานสำหรับกรณีขอบที่จากวันที่มีค่าวันสูงกว่าเดือนของวันที่หรือวันที่แหล่งที่มาเป็นวันก้าวกระโดด ลอง2020-02-29ไป2021-06-29- มันคืน "1y 4m 1D" แต่ค่าที่ควรจะเป็น "1y 4m 0d" ใช่มั้ย?
Enigmativity

37

คุณสามารถทำได้

if ( date1.AddMonths(x) > date2 )

มันเรียบง่ายและสมบูรณ์แบบสำหรับฉัน ฉันรู้สึกประหลาดใจอย่างยิ่งที่เห็นว่ามันทำงานตามที่ตั้งใจไว้เมื่อคำนวณวันที่จากสิ้นเดือน 1 ไปจนถึงวันที่สิ้นเดือนถัดไปที่มีวันน้อยกว่า เช่น .. 1-31-2018 + 1 เดือน = 28 ก.พ. 218
lucky.expert

นี่คือหนึ่งในโซลูชั่นที่ดีกว่า
barnacle.m

ทางออกที่ง่ายและมีประสิทธิภาพจริงๆ! เสนอคำตอบที่ดีที่สุด
Cedric Arnould

2
เกิดอะไรขึ้นถ้า date1 = 2018-10-28 และ date2 = 2018-12-21 คำตอบจะเป็น 2 ในขณะที่คำตอบที่ถูกต้องควรเป็น 3 เพราะช่วงวันที่เป็นเวลา 3 เดือน ถ้าเรานับเพียงเดือนที่ไม่สนใจวัน ดังนั้นคำตอบนี้ไม่ถูกต้อง
Tommix

จะมีเหตุผลมากกว่านี้: if ( date1.AddMonths(x).Month == date2.Month )จากนั้นคุณใช้ x + 1 เป็นจำนวนเดือน
Tommix

34

หากคุณต้องการจำนวนที่แน่นอนของเดือนทั้งหมดให้บวกเสมอ (2000-01-15, 2000-02-14 กลับเป็น 0) การพิจารณาทั้งเดือนคือเมื่อคุณมาถึงวันเดียวกันในเดือนถัดไป (เช่นการคำนวณอายุ)

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

แก้ไขเหตุผล: รหัสเก่าไม่ถูกต้องในบางกรณีเช่น:

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

เพียงเพื่อหลีกเลี่ยงความสับสนสำหรับผู้อื่นฉันคิดว่าวิธีนี้ไม่ถูกต้อง การใช้กรณีทดสอบ: new { From = new DateTime(2015, 12, 31), To = new DateTime(2015, 6, 30), Result = 6 } การทดสอบจะล้มเหลวเนื่องจากผลลัพธ์คือ 5
Cristian Badila

เพิ่มส่วนสำคัญอย่างรวดเร็วด้วยการแก้ไขที่ฉันเสนอที่นี่
Cristian Badila

ฉันไม่แน่ใจว่าฉันได้รับแล้วฟังก์ชันของฉันจะคืนค่า 6 ตามที่ควร: dotnetfiddle.net/MRZNnC
Guillaume86

ฉันคัดลอกกรณีทดสอบที่นี่ด้วยมือและมันมีข้อผิดพลาด ข้อมูลจำเพาะที่ล้มเหลวควรเป็น: new { From = new DateTime(2015, 12, 31), To = new DateTime(2016, 06, 30), Result = 6 }. "ข้อผิดพลาด" อยู่ในto.Day < from.Dayรหัสที่ไม่คำนึงถึงว่าเดือนจะสิ้นสุดใน "วันของเดือน" ที่แตกต่างกัน ในกรณีนี้ตั้งแต่วันที่ 31 ธันวาคม 2558 จนถึง 30 มิถุนายน 2559 จะมีการผ่าน 6 เดือนที่สมบูรณ์ (ตั้งแต่มิถุนายนมี 30 วัน) แต่โค้ดของคุณจะส่งคืน 5
Cristian Badila

3
เป็นพฤติกรรมที่คาดหวังในความคิดของฉันดีหรือเป็นพฤติกรรมที่ฉันคาดหวังอย่างน้อย ฉันคิดว่าเดือนที่สมบูรณ์คือเมื่อคุณมาถึงในวันเดียวกัน (หรือเดือนถัดไปเช่นในกรณีนี้)
Guillaume86

22

ฉันตรวจสอบการใช้วิธีนี้ใน VB.NET ผ่าน MSDN และดูเหมือนว่ามันมีวิธีใช้งานมากมาย ไม่มีวิธีการในตัวใน C # (แม้จะไม่ใช่ความคิดที่ดี) คุณสามารถโทรหา VB ใน C # ได้

  1. เพิ่มMicrosoft.VisualBasic.dllไปยังโครงการของคุณเป็นข้อมูลอ้างอิง
  2. ใช้ Microsoft.VisualBasic.DateAndTime.DateDiff ในรหัสของคุณ

7
ทำไมคุณคิดว่าไม่ใช่ความคิดที่ดี อย่างสังหรณ์ใจฉันจะเดาว่าห้องสมุดเป็น 'อีกไลบรารี. NET' เพื่อรันไทม์ หมายเหตุฉันเล่นเป็นทนายของปีศาจที่นี่ฉันก็จะทำเช่นนี้เพราะมัน 'รู้สึกผิด' (การโกง) แต่ฉันสงสัยว่ามีเหตุผลทางเทคนิคที่น่าเชื่อถือหรือไม่ที่จะทำเช่นนี้
Adam Ralph

3
@ AdamRalph: ไม่มีเหตุผลเลยที่จะไม่ทำ ไลบรารีเหล่านั้นถูกนำไปใช้ในโค้ดที่มีการจัดการ 100% ดังนั้นมันจึงเหมือนกับทุกอย่าง ข้อแตกต่างที่เป็นไปได้เพียงอย่างเดียวคือMicrosoft.VisualBasic.dllต้องโหลดโมดูล แต่เวลาที่ใช้ในการทำนั้นเล็กน้อยมาก ไม่มีเหตุผลที่จะโกงตัวเองจากคุณสมบัติที่ผ่านการทดสอบและมีประโยชน์เพียงเพราะคุณเลือกที่จะเขียนโปรแกรมของคุณใน C # (สิ่งนี้เกิดขึ้นกับสิ่งต่าง ๆ เช่นMy.Application.SplashScreenกัน)
Cody Grey

3
คุณจะเปลี่ยนใจไหมถ้าคุณรู้ว่าเขียนด้วยภาษา C # มันเป็น ด้วยตรรกะเดียวกันการใช้ System.Data และ PresentationFramework ก็คือการโกงส่วนที่สำคัญของมันเขียนด้วย C ++ / CLI
ฮันส์ Passant

3
@ AdamRalph: มีตัวอย่างเฉพาะของ "สัมภาระแปลก ๆ " ที่ทำให้นึกถึง? หรือคุณกำลังบอกว่าอย่างหมดจดสมมุติ? และใช่มันอาจยุ่งกับจิตใจของเพื่อน C # ของคุณบางคนที่เขียนโค้ดจำนวนมากเพื่อทำสิ่งที่คุณสามารถทำได้ในบรรทัดเดียวด้วยข้อความที่ถูกต้องusingแต่ฉันสงสัยว่าจะเกิดความเสียหายร้ายแรง
Cody Gray

1
@Cody Gray: เห็นด้วยตัวอย่างเป็นเรื่องเล็กน้อยตามที่คุณอธิบาย มันเป็น 'สัญญาณรบกวน' ของรหัสพิเศษที่แนะนำโดยการเรียกวิธีการที่ผิดปกติ (จาก C # POV) ที่ฉันอยากจะหลีกเลี่ยง ในทีมที่มีการจัดระเบียบอย่างดีสิ่งต่าง ๆ จะถูกหยิบขึ้นมาในการตรวจสอบโค้ดและสามารถหลีกเลี่ยงได้ง่าย BTW - ฉันไม่ได้พยายามโจมตี VB6 / VB.NET ฉันอธิบายวิธีการดังกล่าวว่า 'แปลก' เพียงเพราะจาก. NET POV ไม่มีเหตุผลที่DateAndTime.Year()จะมีอยู่เพราะมันDateTimeมีYearคุณสมบัติ มีอยู่เพื่อให้ VB.NET ปรากฏมากขึ้นเช่น VB6 เท่านั้น ในฐานะโปรแกรมเมอร์ VB6 คนก่อนฉันสามารถชื่นชมสิ่งนี้ ;-)
Adam Ralph

10

ในการรับความแตกต่างในเดือน (รวมทั้งจุดเริ่มต้นและจุดสิ้นสุด) โดยไม่คำนึงถึงวันที่:

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

5
ลองนึกภาพstartและendเหมือนกัน ถ้าอย่างนั้นคุณจะได้ผลลัพธ์จาก 1. วิธีการที่ถูกต้อง? ทำไมคุณเพิ่ม 1 ลงในผลลัพธ์ ใครโหวตคำตอบนี้: - /?
paul

สำหรับวันที่เหมือนกันมันจะให้ผลลัพธ์เป็น 1 โดยทั่วไปจะนับเดือนทั้งหมดรวมเดือนเริ่มต้นและสิ้นสุด
Chirag

3
ไม่เหมือนความแตกต่างระหว่างสองรายการกับฉัน ความแตกต่างระหว่าง 2 และ 2 คืออะไร? เป็น 1 จริงเหรอ? ฉันขอแนะนำความแตกต่างคือ 0
paul


7

ฉันแค่ต้องการบางสิ่งที่ง่าย ๆ เพื่อรองรับเช่นวันที่มีงานซึ่งป้อนเดือน / ปีเท่านั้นดังนั้นต้องการปีและเดือนที่แตกต่างกันดังนั้นนี่คือสิ่งที่ฉันใช้ที่นี่เพื่อการใช้งานเต็มเท่านั้น

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

คุณสามารถใช้คลาสDateDiffของTime Period Library สำหรับ. 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

นี่คือผลงานของฉันเพื่อสร้างความแตกต่างในเดือนที่ฉันพบว่าถูกต้อง

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

การใช้งาน:

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

คุณสามารถสร้างวิธีอื่นที่เรียกว่า DiffYears และใช้ตรรกะเดียวกันกับข้างบนและ AddYears แทน AddMonths ในลูป while


2

สิ่งนี้ใช้ได้กับสิ่งที่ฉันต้องการ วันของเดือนไม่สำคัญในกรณีของฉันเพราะมันมักจะเป็นวันสุดท้ายของเดือน

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

วิธีที่แม่นยำที่สุดคือวิธีนี้จะให้ผลต่างเป็นเศษส่วนในแต่ละเดือน:

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

นี่เป็นวิธีง่ายๆที่ทำงานได้อย่างน้อยสำหรับฉัน อาจไม่ใช่วิธีที่เร็วที่สุดเพราะใช้คุณลักษณะ AddMonth ที่ยอดเยี่ยมของ DateTime ในการวนซ้ำ:

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

นี่คือจากห้องสมุดของฉันเองจะคืนส่วนต่างของเดือนระหว่างวันที่สองวัน

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
มันใช้ได้ไหม? ฉันได้รับ 11 บนกระดาษสำหรับJan-31-2014และDec-31-2013
Dave Cousineau

1

คุณสามารถมีฟังก์ชั่นบางอย่างเช่นนี้

ตัวอย่างเช่นจาก 2012/12/27 ถึง 2012/12/29 กลายเป็น 3 วัน เช่นเดียวกันจาก 2012/12/15 ถึง 2013/01/15 จะกลายเป็น 2 เดือนเพราะมากถึง 2013/01/14 เป็น 1 เดือน จากวันที่ 15 เป็นเดือนที่ 2

คุณสามารถลบ "=" ในเงื่อนไขที่สองหากคุณไม่ต้องการรวมทั้งสองวันในการคำนวณ เช่นจาก 2012/12/15 ถึง 2013/01/15 คือ 1 เดือน

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

คุณสามารถใช้ส่วนขยายต่อไปนี้: รหัส

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
}

การใช้งาน!

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

ต่อไปนี้เป็นโซลูชันที่กระชับยิ่งขึ้นโดยใช้ VB.Net DateDiff สำหรับปี, เดือน, วันเท่านั้น คุณสามารถโหลดไลบรารี DateDiff ใน C # ได้เช่นกัน

date1 ต้องเป็น <= 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))

ค#

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

นี่คือการตอบสนองต่อคำตอบของ Kirk Woll ฉันมีคะแนนชื่อเสียงไม่เพียงพอที่จะตอบกลับความคิดเห็น ...

ฉันชอบวิธีแก้ปัญหาของเคิร์กและกำลังจะลอกออกมาและใช้มันในโค้ดของฉัน แต่เมื่อฉันดูมันฉันก็รู้ว่ามันซับซ้อนเกินไป การสลับและการวนซ้ำที่ไม่จำเป็นและตัวสร้างพับลิกที่ไม่มีประโยชน์ที่จะใช้

นี่คือการเขียนของฉัน:

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

การใช้ 1 เหมือนกันมาก:

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

การใช้งาน 2, ที่คล้ายกัน:

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

ในกรณีของฉันจำเป็นต้องคำนวณเดือนที่สมบูรณ์จากวันที่เริ่มต้นถึงวันก่อนวันนี้ในเดือนถัดไปหรือจากต้นเดือนถึงสิ้นเดือน


เช่นจาก 1/1/2018 ถึง 31/1/2018 เป็นเดือนที่สมบูรณ์
Ex2: ตั้งแต่ 5/1/2018 ถึง 4/2/2018 เป็นเดือนที่สมบูรณ์

ดังนั้นตามนี่คือทางออกของฉัน:

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

การใช้งาน:

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

หมายเหตุ: ในกรณีของฉันจำเป็นต้องคำนวณวันที่เหลือหลังจากครบเดือนดังนั้นถ้าไม่ใช่กรณีของคุณคุณสามารถละเว้นผลลัพธ์วันหรือแม้กระทั่งคุณสามารถเปลี่ยนวิธีการส่งคืนจาก tuple เป็นจำนวนเต็ม


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

โซลูชันนี้ใช้สำหรับการคำนวณค่าเช่า / สมัครสมาชิกโดยที่ความแตกต่างไม่ได้หมายความว่าจะเป็นการลบมันหมายถึงการขยายภายในสองวันนั้น


1

มี 3 กรณีคือปีเดียวกันปีก่อนและปีอื่น ๆ

หากวันในเดือนนั้นไม่สำคัญ ...

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

ฉันเขียนฟังก์ชันเพื่อทำสิ่งนี้ให้สำเร็จเพราะวิธีอื่น ๆ ไม่ได้ผลสำหรับฉัน

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

โปรดตอบเป็นภาษาอังกฤษ (เทียบกับภาษาที่ประดิษฐ์ขึ้นใด ๆ ... )
kleopatra

ทำไมไม่เพียงทำ startDate.AddMonths (monthCount). ToShortDateString () นี่ไม่ได้ตอบคำถามเดิมที่ถูกถามอยู่แล้ว!
TabbyCool

โอ้ขอโทษ @TabbyCool รหัสนี้ใช้งานได้ดีในโปรแกรมของฉัน! โปรแกรมเมอร์กฎพูดว่า: รหัสแรกทำงานแล้วเพิ่มประสิทธิภาพ! tanx สำหรับความคิดเห็นของคุณ :)
reza akhlaghi

1

ความเข้าใจของฉันเกี่ยวกับความแตกต่างของเดือนรวมระหว่างวันที่ 2 มีส่วนที่เป็นส่วนหนึ่งและเศษส่วน (วันที่สำคัญ)

ส่วนที่สำคัญคือผลต่างเดือนเต็ม

ส่วนสำหรับฉันคือความแตกต่างของ% ของวัน (กับวันเต็มของเดือน) ระหว่างเดือนเริ่มต้นและสิ้นสุด

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

ด้วยส่วนขยายนี้ผลลัพธ์คือ:

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

ไม่มีคำตอบที่ชัดเจนเกี่ยวกับเรื่องนี้เพราะคุณมักจะคาดเดาสิ่งต่างๆ

โซลูชันนี้จะคำนวณระหว่างวันที่สองเดือนในช่วงเวลาสมมติว่าคุณต้องการบันทึกวันของเดือนเพื่อเปรียบเทียบ (หมายถึงวันที่ของเดือนนั้นถูกพิจารณาในการคำนวณ)

ตัวอย่างเช่นถ้าคุณมีวันที่ 30 มกราคม 2012, 29 กุมภาพันธ์ 2012 จะไม่เป็นเดือน แต่จะวันที่ 1 มีนาคม 2013

ผ่านการทดสอบแล้วอย่างละเอียดอาจจะล้างในภายหลังเมื่อเราใช้ แต่ที่นี่:

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

จากการทำงานที่ยอดเยี่ยมของ DateTimeSpan ที่ได้ทำไปแล้วฉันได้ทำให้โค้ดกลับมาเป็นปกติ ดูเหมือนว่าจะทำงานได้ดี:

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

เมื่อเทียบกับCompareDates(x, y)ที่x={01/02/2019 00:00:00}และy={01/05/2020 00:00:00}จากนั้นMonthsให้ฉัน2
Bassie

1

ฟังก์ชันสแตติกแบบง่ายนี้จะคำนวณเศษส่วนของเดือนระหว่างสองชุดข้อมูลเช่น

  • 1.1 ถึง 31.1 = 1.0
  • 1.4 ถึง 15.4 = 0.5
  • 16.4 ถึง 30.4 = 0.5
  • 1.3 ถึง 1.4 = 1 + 1/30

ฟังก์ชันสันนิษฐานว่าวันแรกมีขนาดเล็กกว่าวันที่สอง เพื่อจัดการกับช่วงเวลาที่เป็นค่าลบเราสามารถปรับเปลี่ยนฟังก์ชันได้อย่างง่ายดายโดยการแนะนำเครื่องหมายและการสลับตัวแปรที่จุดเริ่มต้น

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

เพื่อให้สามารถคำนวณความแตกต่างระหว่าง 2 วันในเดือนนั้นเป็นสิ่งที่สมบูรณ์แบบที่ต้องทำและจำเป็นต้องใช้ในแอพพลิเคชั่นทางธุรกิจมากมาย ผู้เขียนหลายคนที่แสดงความคิดเห็นเช่น - อะไรคือความแตกต่างในเดือนระหว่าง "พฤษภาคม 1,2010" และ "16 มิถุนายน 2010 สิ่งที่แตกต่างในเดือนระหว่าง 31 ธันวาคม 2010 และ 1 มกราคม 2011 - ไม่เข้าใจ พื้นฐานของแอปพลิเคชันทางธุรกิจ

นี่คือคำตอบของความคิดเห็น 2 ข้อด้านบน - จำนวนเดือนระหว่าง 1 พ.ค. - 16 พ.ค. และ 16 มิ.ย. 2553 คือ 1 เดือนจำนวนเดือนระหว่าง 31 ธ.ค. 2553 ถึง 1 พ.ค. 2554 อยู่ที่ 0 จะเป็นเรื่องโง่มากหากคำนวณเป็น 1.5 เดือนและ 1 วินาทีตามที่ผู้เขียนโค้ดข้างต้นแนะนำไว้

ผู้ที่เคยทำงานเกี่ยวกับบัตรเครดิตการจำนองการประมวลผลภาษีการประมวลผลค่าเช่าการคำนวณดอกเบี้ยรายเดือนและโซลูชั่นธุรกิจอื่น ๆ

ปัญหาคือว่าฟังก์ชั่นดังกล่าวไม่รวมอยู่ใน C # หรือ VB.NET สำหรับเรื่องนั้น Datediff จะพิจารณาเฉพาะปีบัญชีหรือองค์ประกอบของเดือนเท่านั้นดังนั้นจึงไม่มีประโยชน์

นี่คือตัวอย่างในชีวิตจริงที่คุณสามารถคำนวณเดือนได้อย่างถูกต้องและถูกต้อง:

คุณอาศัยอยู่ในค่าเช่าระยะสั้นจาก 18-feb ถึง 23-aug คุณอยู่ที่นั่นกี่เดือน คำตอบนั้นง่าย - 6 เดือน

คุณมีบัญชีธนาคารที่มีการคำนวณและจ่ายดอกเบี้ยทุกสิ้นเดือน คุณฝากเงินในวันที่ 10 มิถุนายนและนำออกมา 29 ตุลาคม (ปีเดียวกัน) คุณได้รับดอกเบี้ยกี่เดือน? คำตอบที่ง่ายมาก - 4 เดือน (อีกวันพิเศษไม่สำคัญ)

ในแอปพลิเคชันทางธุรกิจส่วนใหญ่เวลาที่คุณต้องการคำนวณเดือนเป็นเพราะคุณจำเป็นต้องรู้ว่า 'เต็ม' เดือนขึ้นอยู่กับว่ามนุษย์คำนวณเวลาอย่างไร ไม่ได้ขึ้นอยู่กับความคิดที่เป็นนามธรรม / ไม่เกี่ยวข้องบางอย่าง


5
นี่คือหนึ่งในเหตุผลที่การบัญชีไม่ใช่คณิตศาสตร์ ในการบัญชีผลขึ้นอยู่กับวิธีที่คุณคำนวณ .. ฉันรู้ว่าคะแนนของคุณและฉันรู้ว่า "มุมมองทางธุรกิจทั่วไป" ในเรื่องนี้ แต่คำอธิบายนี้ไม่ถูกต้องชัดเจน ระหว่าง 2012/11/30 2012/12/01 และมีทั้ง 0 หรือ 1/30 หรือ 1/31 หรือ 1 หรือ 2 เดือนขึ้นอยู่กับสิ่งที่คุณขอ เป็นวันที่ exlusive หรือรวม? คุณถามจำนวนเดือนที่ผ่านมาแตะหรือผ่านหรือไม่ คุณต้องการปัดเศษขึ้นปัดเศษหรือแน่นอน
quetzalcoatl

3
ตอนนี้อธิบายให้นักธุรกิจหรือนักบัญชีและพวกเขาจะทำให้คุณดูงุนงง เป็นเสมอ "ชัดเจนสำหรับพวกเขาที่แน่นอนว่าพวกเขาหมายถึง X และ Y และ Z คุณจะคิดต่างกันอย่างไร?" ตอนนี้รับนักธุรกิจหลายคนและพยายามให้พวกเขาเห็นด้วยกับหัวข้อ นักบัญชีมีแนวโน้มที่จะเห็นด้วยมากขึ้นเพราะในบางครั้งพวกเขาจะใช้คณิตศาสตร์เพื่อตรวจสอบว่ามีตัวเลือกใดบ้างที่พวกเขาอาจสรุปรวมในช่วงเวลาเดียวกันสองครั้งโดยบังเอิญเป็นต้นแม้กระทั่งตัวอย่างการคำนวณของคุณก็เป็นข้อโต้แย้งและขึ้นอยู่กับภูมิภาค กฎเกณฑ์ทางธุรกิจเพิ่มเติมเช่นละเว้นวันพิเศษ
quetzalcoatl

2
-1 คุณกำลังสมมติว่าซอฟต์แวร์ทั้งหมดเป็น "แอปพลิเคชันทางธุรกิจ" ไม่ได้กล่าวถึงวัตถุประสงค์ของรหัสที่เป็นปัญหา นอกจากนี้คุณยังถือว่า "แอปพลิเคชันธุรกิจ" ทั้งหมดมีกฎเดียวกันซึ่งไม่เป็นความจริง
Jesse Webb

0

ขยาย Kirks struct ด้วย ToString (รูปแบบ) และระยะเวลา (ยาว 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));
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.