2010-06-17 56 views
12

Vì mục đích của câu hỏi này, giả sử người dùng sẽ đến từ Hoa Kỳ và sẽ sử dụng lịch Gregorian chuẩn. Vì vậy, một tuần dương lịch bắt đầu vào Chủ Nhật và kết thúc vào Thứ Bảy.Lấy số tuần theo lịch giữa 2 ngày trong C#

Điều tôi đang cố gắng làm là xác định số tuần lịch tồn tại giữa hai ngày. Một ví dụ hoàn hảo về vấn đề của tôi tồn tại trong tháng 10 năm 2010. Từ 10/16 đến 10/31 có 4 tuần theo lịch.


  1. 10 tháng mười - 16 tháng 10
  2. 17 tháng mười - 23 tháng 10
  3. 24 Tháng Mười - 30 tháng mười
  4. Tháng mười 31 - tháng 11 6

Tôi muốn tránh xa mọi logic được mã hóa cứng như:

if (Day == DayOfWeek.Saturday && LastDayOfMonth == 31) { ... } 

Có ai nghĩ cách hợp lý để làm điều này không?

UPDATE:
Cảm ơn tất cả các câu trả lời tuyệt vời, sau khi một số xem xét ở đây là giải pháp tôi sử dụng:

//get the start and end dates of the current pay period 
DateTime currentPeriodStart = SelectedPeriod.Model.PeriodStart; 
DateTime currentPeriodEnd = SelectedPeriod.Model.PeriodEnd; 

//get the first sunday & last saturday span that encapsulates the current pay period 
DateTime firstSunday = DayExtensions.SundayBeforePeriodStart(currentPeriodStart); 
DateTime lastSaturday = DayExtensions.SaturdayAfterPeriodEnd(currentPeriodEnd); 

//get the number of calendar weeks in the span 
int numberOfCalendarWeeks = DayExtensions.CalendarWeeks(firstSunday, lastSaturday); 

Và đây là những phương pháp từ lớp helper:

/// <summary> 
    /// Get the first Sunday before the pay period start date 
    /// </summary> 
    /// <param name="periodStartDate">Date of the pay period start date</param> 
    /// <returns></returns> 
    public static DateTime SundayBeforePeriodStart(DateTime periodStartDate) 
    { 
     DateTime firstDayOfWeekBeforeStartDate; 

     int daysBetweenStartDateAndPreviousFirstDayOfWeek = (int)periodStartDate.DayOfWeek - (int)DayOfWeek.Sunday; 

     if (daysBetweenStartDateAndPreviousFirstDayOfWeek >= 0) 
     { 
      firstDayOfWeekBeforeStartDate = periodStartDate.AddDays(-daysBetweenStartDateAndPreviousFirstDayOfWeek); 
     } 
     else 
     { 
      firstDayOfWeekBeforeStartDate = periodStartDate.AddDays(-(daysBetweenStartDateAndPreviousFirstDayOfWeek + 7)); 
     } 

     return firstDayOfWeekBeforeStartDate; 
    } 

    /// <summary> 
    /// Get the first Saturday after the period end date 
    /// </summary> 
    /// <param name="periodEndDate">Date of the pay period end date</param> 
    /// <returns></returns> 
    public static DateTime SaturdayAfterPeriodEnd(DateTime periodEndDate) 
    { 
     DateTime lastDayOfWeekAfterEndDate; 

     int daysBetweenEndDateAndFollowingLastDayOfWeek = (int)DayOfWeek.Saturday - (int)periodEndDate.DayOfWeek; 

     if (daysBetweenEndDateAndFollowingLastDayOfWeek >= 0) 
     { 
      lastDayOfWeekAfterEndDate = periodEndDate.AddDays(daysBetweenEndDateAndFollowingLastDayOfWeek); 
     } 
     else 
     { 
      lastDayOfWeekAfterEndDate = periodEndDate.AddDays(daysBetweenEndDateAndFollowingLastDayOfWeek + 7); 
     } 

     return lastDayOfWeekAfterEndDate; 
    } 

    /// <summary> 
    /// Get the calendar weeks between 2 dates 
    /// </summary> 
    /// <param name="d1">First day of date span</param> 
    /// <param name="d2">Last day of date span</param> 
    /// <returns></returns> 
    public static int CalendarWeeks(DateTime d1, DateTime d2) 
    { 
     return 1 + (int)((d2 - d1).TotalDays/7); 
    } 

Và nếu bạn tò mò, đây là những gì tôi sẽ làm với những ngày:

//create an array of all the sundays in this span 
DateTime[] _sundays = new DateTime[numberOfCalendarWeeks]; 

//put the first sunday in the period 
_sundays[0] = firstSunday; 

//step through each week and get each sunday until you reach the last saturday 
for (int i = 1; i <= numberOfCalendarWeeks - 1; i++) 
{ 
    DateTime d = new DateTime(); 
    d = firstSunday.AddDays(i * 7); 
     _sundays[i] = d; 
} 

for (int i = 0; i <= _sundays.Length-1; i++) 
{ 
     //bind my view model with each sunday. 
} 
+0

Nếu tôi hiểu chính xác, bạn muốn số tuần đầy đủ (tôi nghĩ là từ * Thứ Hai * đến Chủ Nhật) giữa hai ngày cụ thể, từ Thứ Năm, 18 Tháng Sáu đến Thứ Tư, 24 Tháng Sáu, bạn sẽ không có một tuần (như trong 7 ngày), nhưng không có, vì bạn chỉ vượt qua thứ hai một lần, và không đạt đến chủ nhật sau đó, là chính xác? – Treb

+0

Ứng dụng cụ thể này gọi cho Sun-Sat. Hãy nghĩ về 2 kỳ lương trong một tháng (giai đoạn 10/1 và thời kỳ 10/16). Một tuần làm việc trong kịch bản này là Sun-Sat. Vì vậy, giai đoạn trả lương 10/16 chạy qua 4 tuần theo lịch. Có lý? –

+0

Bạn đang tìm kiếm một cách tiếp cận công thức đơn giản, hoặc bạn có ok với một cách tiếp cận thuật toán? Ngoài ra, công thức/thuật toán có tính đến năm nhuận/ngày, v.v. quan trọng như thế nào? – jrista

Trả lời

6

Đây là giải pháp chung mà tôi tin rằng sẽ hoạt động cho bất kỳ lựa chọn nào trong tuần bắt đầu và ngày kết thúc. Bạn có thể đơn giản hóa nó cho trường hợp của bạn, nhưng mã này cung cấp cho bạn tùy chọn thay đổi bắt đầu và kết thúc của tuần (ví dụ: từ thứ Hai đến Chủ Nhật) nếu cần thiết. Nó không phải là hiếm trong các ứng dụng biên chế cho định nghĩa của một tuần lịch để thay đổi.

 DateTime periodStart = new DateTime(2010, 10, 17); 
     DateTime periodEnd = new DateTime(2010, 11, 14); 

     const DayOfWeek FIRST_DAY_OF_WEEK = DayOfWeek.Monday; 
     const DayOfWeek LAST_DAY_OF_WEEK = DayOfWeek.Sunday; 
     const int DAYS_IN_WEEK = 7; 

     DateTime firstDayOfWeekBeforeStartDate; 
     int daysBetweenStartDateAndPreviousFirstDayOfWeek = (int)periodStart.DayOfWeek - (int)FIRST_DAY_OF_WEEK; 
     if (daysBetweenStartDateAndPreviousFirstDayOfWeek >= 0) 
     { 
      firstDayOfWeekBeforeStartDate = periodStart.AddDays(-daysBetweenStartDateAndPreviousFirstDayOfWeek); 
     } 
     else 
     { 
      firstDayOfWeekBeforeStartDate = periodStart.AddDays(-(daysBetweenStartDateAndPreviousFirstDayOfWeek + DAYS_IN_WEEK)); 
     } 

     DateTime lastDayOfWeekAfterEndDate; 
     int daysBetweenEndDateAndFollowingLastDayOfWeek = (int)LAST_DAY_OF_WEEK - (int)periodEnd.DayOfWeek; 
     if (daysBetweenEndDateAndFollowingLastDayOfWeek >= 0) 
     { 
      lastDayOfWeekAfterEndDate = periodEnd.AddDays(daysBetweenEndDateAndFollowingLastDayOfWeek); 
     } 
     else 
     { 
      lastDayOfWeekAfterEndDate = periodEnd.AddDays(daysBetweenEndDateAndFollowingLastDayOfWeek + DAYS_IN_WEEK); 
     } 

     int calendarWeeks = 1 + (int)((lastDayOfWeekAfterEndDate - firstDayOfWeekBeforeStartDate).TotalDays/DAYS_IN_WEEK); 
0
private static int weekDifference(DateTime startDate, DateTime endDate) 
{ 
int monthsApart = 12 * (startDate.Year - endDate.Year) + startDate.Month - endDate.Month; 
return Math.Abs(monthsApart*4); 
} 

Cant Xem một cách tốt hơn quyền off the bat.

0
private static int weekDifference(DateTime startDate, DateTime endDate) 
{ 
    const int firstDayOfWeek = 0; // Sunday 
    int wasteDaysStart = (7+startDate.DatOfWeek-firstDayOfWeek)%7; 
    return (int)(((endDate-startDate).TotalDays() + wasteDaysStart + 6)/7); 
} 

Cảnh báo: mã chưa được kiểm tra. Vui lòng kiểm tra và xóa ghi chú.

+0

(10/31/2010) - (10/16/2010) trả về 15. 15/7 = 2.14. Làm thế nào tôi sẽ cắt xén khác nhau để có được 4 từ 2,14? –

+2

Tôi nghĩ rằng điều này chỉ tìm thấy số lượng khoảng thời gian 7 ngày giữa hai ngày ... không phải số tuần dương lịch trong phạm vi ngày. Xin lưu ý, ngày có thể rơi vào ngày cuối cùng của tuần hoặc ngày đầu tiên của tuần, có nghĩa là ngày đó sẽ bao gồm tất cả các tuần đầy đủ, cũng như tuần đầu tiên rơi vào ngày cuối tuần và tuần mà ngày cuối cùng rơi vào ngày đầu tuần. Cho rằng ... Tôi không nghĩ rằng tính toán này sẽ giải quyết vấn đề trong OP. – jrista

+0

cảm ơn, mã cố định, bây giờ tôi đã hiểu câu hỏi của bạn :) hãy kiểm tra cẩn thận. –

4

Lưu ý rằng các tính toán tuần đó được thực hiện khác nhau trong các nền văn hóa khác nhau và không có lỗi nếu bạn thấy số tuần 53!

using System.Globalization; 

CultureInfo cultInfo = CultureInfo.CurrentCulture; 
int weekNumNow = cultInfo.Calendar.GetWeekOfYear(DateTime.Now, 
        cultInfo.DateTimeFormat.CalendarWeekRule, 
         cultInfo.DateTimeFormat.FirstDayOfWeek); 
+0

Điểm tốt về sự phụ thuộc văn hóa! – Treb

5

Cách tôi giải quyết vấn đề này là bắt đầu một tuần cho bất kỳ ngày cụ thể nào. Sử dụng điều đó, bạn sẽ trừ kết quả của ngày bắt đầu từ kết quả của ngày kết thúc. Sự khác biệt ngày của bạn sẽ luôn là bội số của 7, vì vậy hãy chia và thêm 1 (0 ngày => 1 tuần, 7 ngày => 2 tuần, v.v.). Điều này sẽ cho bạn biết có bao nhiêu tuần dương lịch được bao trả hoặc được đại diện bởi bất kỳ hai ngày nào.

static int GetWeeksCovered(DateTime startDate, DateTime endDate) 
{ 
    if (endDate < startDate) 
     throw new ArgumentException("endDate cannot be less than startDate"); 

    return (GetBeginningOfWeek(endDate).Subtract(GetBeginningOfWeek(startDate)).Days/7) + 1; 
} 

static DateTime GetBeginningOfWeek(DateTime date) 
{ 
    return date.AddDays(-1 * (int)date.DayOfWeek).Date; 
} 
  • 16-Oct-2010 và 16-Oct-2010 => 1 tuần được điều chỉnh (hoặc đại diện).
  • 16-Oct-2010 và 31-Oct-2010 => 4 tuần được bao gồm, theo thông số kỹ thuật.
0

Phần sau dường như hoạt động với bất kỳ phạm vi ngày nào. Nó phải là âm thanh về mặt văn hóa, và cần chiếm năm nhuận/ngày hoặc oddities lịch khác:

private static int getWeeksSpannedBy(DateTime first, DateTime last) 
    { 
     var calendar = CultureInfo.CurrentCulture.Calendar; 
     var weekRule = CultureInfo.CurrentCulture.DateTimeFormat.CalendarWeekRule; 
     var firstDayOfWeek = DayOfWeek.Sunday; 

     int lastWeek = calendar.GetWeekOfYear(last, weekRule, firstDayOfWeek); 
     int firstWeek = calendar.GetWeekOfYear(first, weekRule, firstDayOfWeek); 

     int weekDiff = lastWeek - firstWeek + 1; 

     return weekDiff; 
    } 

    static void Main(string[] args) 
    { 
     int weeks1 = getWeeksSpannedBy(new DateTime(2010, 1, 3), new DateTime(2010, 1, 9)); 
     int weeks2 = getWeeksSpannedBy(new DateTime(2010, 10, 16), new DateTime(2010, 10, 31)); 
     int weeks3 = getWeeksSpannedBy(new DateTime(2008, 2, 1), new DateTime(2008, 2, 29)); 
     int weeks4 = getWeeksSpannedBy(new DateTime(2012, 2, 1), new DateTime(2012, 2, 29)); 

     Console.WriteLine("Weeks Difference #1: " + weeks1); 
     Console.WriteLine("Weeks Difference #2: " + weeks2); 
     Console.WriteLine("Weeks Difference #3: " + weeks3); 
     Console.WriteLine("Weeks Difference #4: " + weeks4); 
     Console.ReadLine(); 
    } 

In ra sau, đó là chính xác cho tất cả các phạm vi ngày, quá khứ, hiện tại hay tương lai (năm nhuận năm 2008 và 2012 cả hai đều có 5 tuần giữa 01 tháng 2 và 29 tháng 2):

tuần Difference # 1: 1
tuần Difference # 2: 4
tuần Difference # 3: 5
tuần Difference # 4: 5

0

Thứ bảy là ngày cuối cùng của tuần?

public int CalendarWeeks(DateTime from, DateTime to) { 

    // number of multiples of 7 
    // (rounded up, since 15 days would span at least 3 weeks) 
    // and if we end on a day before we start, we know it's another week 

    return (int)Math.Ceiling(to.Subtract(from).Days/7.0) + 
      (to.DayOfWeek <= from.DayOfWeek) ? 1 : 0; 
} 
Các vấn đề liên quan