2010-03-31 45 views
25

Tôi có ngày sinh nhật/kỷ niệm Ngày giờ làm cách nào để xác định xem ngày đó có xảy ra trong một phạm vi ngày cụ thể không? Ví dụ,Cách xác định ngày sinh hoặc ngày kỷ niệm xảy ra trong phạm vi ngày

Birthday = 2000/01/02
Phạm vi Ngày = 2008/12/25 - 1/3/2009

Tôi cần một phương pháp để xác định có hay không sinh nhật của người này đã xảy ra trong ngày đó phạm vi - tốt nhất là trong C#.

Lần đầu tiên tôi thay đổi ngày sinh nhật DateTime để khớp với phạm vi ngày, sau đó chỉ kiểm tra ngày sinh nhật "mới" là giữa ngày bắt đầu và ngày kết thúc của phạm vi ngày ... nhưng khi phạm vi ngày trải qua các năm khác nhau, như trong ví dụ trên của tôi - tôi đã phải thêm một câu lệnh khó chịu nếu. Có cách nào tốt hơn không?

+3

+1 như câu hỏi này là phức tạp hơn rất nhiều so với nó có vẻ! – NibblyPig

+3

Đừng quên rằng mọi thứ trở nên phức tạp hơn với những năm nhuận :) –

+0

Thực ra năm nhuận sẽ không tạo ra bất kỳ sự khác biệt nào :) – NibblyPig

Trả lời

8

Ok, đây là mất của tôi

public static bool IsBirthDayInRange(DateTime birthday, DateTime start, DateTime end) 
{ 
    DateTime temp = birthday.AddYears(start.Year - birthday.Year); 

    if (temp < start) 
     temp = temp.AddYears(1); 

    return birthday <= end && temp >= start && temp <= end; 
} 
2

Tôi giả sử rằng ngày của bạn được lưu trữ trong biến DateTime? Nếu vậy, việc so sánh là khá thẳng về phía trước:

if (Birthday > DateRangeLower && Birthday < DateRangeUpper) { 
    // it's your birthday! 
} 

Bạn có thể gói gọn trong một phương pháp mở rộng nếu bạn thích:

public static bool Between(this DateTime compareDate, DateTime startDate, DateTime endDate) { 
    return compareDate > startDate && compareDate < endDate; 
} 

sau đó bạn có thể gọi nó như vậy:

if (Birthday.Between(DateRangeLower, DateRangeUpper) { 
    // it's your birthday 
} 

Cập nhật: Nếu bạn muốn bỏ qua phần năm sinh nhật để xác định xem ngày kỷ niệm của ngày có nằm trong phạm vi không, hãy áp dụng các điều sau:

if (DateRangeLower.DayOfYear <= DateRangeUpper.DayOfYear && 
    Birthday.DayOfYear > DateRangeLower.DayOfYear && Birthday.DayOfYear < DateRangeUpper.DayOfYear) { 
    // it's your birthday 
    // the days are within the date range (and the range is in a single year) 
} 
else if (DateRangeLower.DayOfYear > DateRangeUpper.DayOfYear && 
    Birthday.DayOfYear < DateRangeLower.DayOfYear && Birthday.DayOfYear > DateRangeUpper.DayOfYear) { 
    // it's your birthday 
    // note, we're actually checking to see if the date is outside of the 
    // original date's days to handle the case where the dates span a year end boundary 
    // this only works if the dates are not more than 1 year apart 
} 
+2

Tôi nghĩ bạn có nghĩa là Birthday = và <=. –

+0

Tôi không chắc chắn đây là những gì OP đang tìm kiếm. Tình huống của anh ta liên quan đến việc chuyển giá trị sinh nhật * thành * phạm vi (dựa trên năm) để xem liệu nó có nằm trong hay ngoài phạm vi. – LBushkin

+0

Rất tiếc .. điểm tốt @Mongus. @ davekaro có thể làm cho ngày so sánh bao gồm nếu anh ta cần bằng cách thay đổi thành> = và <= (và có thể sử dụng .Date để bỏ qua bất kỳ phần thời gian nào nếu cần) – Dexter

1

Bạn có thể sử dụng thuộc tính DayOfYear của đối tượng DateTime.

if ((birthday.DayOfYear >= start.DayOfYear) && (birthday.DayOfYear <= end.DayOfYear)) { 
    ... 
} 
+1

Điều này sẽ giảm nếu phạm vi là 01/11/2008 - 01/03/2009. –

+0

đúng - có thể tình trạng của anh ta sẽ cho phép anh ta sử dụng điều này - nếu không, có vẻ như anh ta trở lại với một tuyên bố khó chịu nếu. Tôi nghĩ tanascius có ý tưởng đúng. – Ray

+0

Điều này sẽ thất bại nếu người đó không được sinh ra trước khi phạm vi được kiểm tra. Kiểm tra câu trả lời của tôi cho một giải pháp có thể. –

0
if (Birthday.Month >= DateRangeLower.Month && Birthday.Month <= DateRangeUpper.Month 
     && Birthday.Day>= DateRangeLower.Day && Birthday.Day<= DateRangeUpper.Day) { 
//Partytime... 
} 
+0

Chờ đã, tôi nghĩ đây là câu trả lời đúng, nhưng không phải - Nếu phạm vi ngày của bạn là ngày 1 tháng 1 đến ngày 3 tháng 3 và ngày sinh của bạn là ngày 6, mã này sẽ không hoạt động. – NibblyPig

+0

Nó không chính xác nhưng nó gần. Bạn cần phải kiểm tra tháng và chỉ khi Birthday.Month == DateRangeLower.Month hoặc Birthday.Month == DateRangeUpper.Month sau đó kiểm tra ngày là tốt. –

+0

Cả hai đều đúng, cảm ơn. Lỗi lầm nhỏ của tôi. =) – chriszero

1

Đây là giải pháp của tôi. Nó sử dụng DayOfYear để tìm một kết quả phù hợp. Nhưng bạn phải cẩn thận, nếu số DayOfYear của ngày bắt đầu vượt quá DayOfYear của ngày kết thúc. Tôi cho rằng, đó là ngày bắt đầu sớm hơn so với ngày kết thúc:

private static bool HasBirthDay(DateTime birthday, DateTime start, DateTime end) 
{ 
    Debug.Assert(start < end); 
    if(start.DayOfYear < end.DayOfYear) 
    { 
     if(birthday.DayOfYear > start.DayOfYear && birthday.DayOfYear < end.DayOfYear) 
     { 
      return true; 
     } 
    } 
    else 
    { 
     if(birthday.DayOfYear < end.DayOfYear || birthday.DayOfYear > start.DayOfYear) 
     { 
      return true; 
     } 
    } 
    return false; 
} 

// DayOfYear(start date) > DayOfYear(end date) 
var start = new DateTime(2008, 12, 25); 
var end = new DateTime(2009, 1, 3); 
Debug.Assert(HasBirthDay(new DateTime(2000, 1, 2), start, end)); 
Debug.Assert(HasBirthDay(new DateTime(2000, 12, 26), start, end)); 
Debug.Assert(!HasBirthDay(new DateTime(2000, 1, 5), start, end)); 
Debug.Assert(!HasBirthDay(new DateTime(2000, 12, 24), start, end)); 

// DayOfYear(start date) < DayOfYear(end date) 
start = new DateTime(2008, 10, 25); 
end = new DateTime(2008, 11, 3); 
Debug.Assert(HasBirthDay(new DateTime(2000, 10, 26), start, end)); 
Debug.Assert(!HasBirthDay(new DateTime(2000, 12, 5), start, end)); 
Debug.Assert(!HasBirthDay(new DateTime(2000, 1, 24), start, end)); 
+0

Có lý do nào cho việc giảm giá không? Tôi muốn biết khi nào có lỗi trong mã này. Xin vui lòng để lại một bình luận – tanascius

2

cập nhật câu trả lời bao gồm bình thường ràng buộc trên được đề cập bởi SLC. Điều này sẽ làm việc cho các trường hợp mà người đó cũng không sinh ngày 29/02.

DateTime birthday = new DateTime(2000, 2, 1); 

DateTime min = new DateTime(2008, 12, 25); 
DateTime max = new DateTime(2009, 3, 1); 

DateTime nLower = new DateTime(min.Year, birthday.Month, birthday.Day); 
DateTime nUpper = new DateTime(max.Year, birthday.Month, birthday.Day); 

if (birthday.Year <= max.Year && 
    ((nLower >= min && nLower <= max) || (nUpper >= min && nUpper <= max))) 
{ 
    // Happy birthday 
    Console.WriteLine("Happy birthday"); 
} 

Và bây giờ là một phiên bản để xử lý những người sinh ra vào ngày (29/02):

public static bool IsBirthdayInRange(
    DateTime birthday, DateTime min, DateTime max) 
{ 
    var dates = new DateTime[] { birthday, min }; 
    for (int i = 0; i < dates.Length; i++) 
    { 
     if (dates[i].Month == 2 && dates[i].Day == 29) 
     { 
      dates[i] = dates[i].AddDays(-1); 
     } 
    } 

    birthday = dates[0]; 
    min = dates[1]; 

    DateTime nLower = new DateTime(min.Year, birthday.Month, birthday.Day); 
    DateTime nUpper = new DateTime(max.Year, birthday.Month, birthday.Day); 

    if (birthday.Year <= max.Year && 
     ((nLower >= min && nLower <= max) || (nUpper >= min && nUpper <= max))) 
    { 
     return true; 
    } 

    return false; 
} 
+0

Tôi đã trở lại để gửi giải pháp này, đây là cách để làm điều đó, về cơ bản thiết lập năm đầu vào của bạn để có cùng năm với giới hạn dưới của tìm kiếm. Bạn có thể phải làm điều đó cho giới hạn trên mặc dù, trong trường hợp trên, nếu bday là 1983 10 5 và phạm vi là 1985 10 6 đến 1986 10 10 như IF sẽ thất bại trên phần bình thường> = min. – NibblyPig

+0

Và điều gì xảy ra trong năm nhuận? Ví dụ, khi 'birthday' là' 29/02/1984' và 'min' là' 01/10/2005'? – LukeH

+0

Tôi không nghĩ rằng điều này sẽ làm việc cho Ngày tôi đã cung cấp trong câu hỏi ban đầu của mình. Sử dụng ngày của tôi, ngày bình thường sẽ là 1/2/2008 mà không phải là> = đến "min" (25/12/2008). – davekaro

1

Điểm mấu chốt của vấn đề của bạn là tìm ra Năm gán cho sinh nhật để đảm bảo rằng bạn có thể thực hiện so sánh phạm vi hợp lệ.

Bạn có hai subcases liên quan đến phạm vi mà bạn cần để đối phó với:

  1. Các LowerBound có năm giống như UpperBound
  2. Các LowerBound có một năm khác với UpperBound

CHỈNH SỬA: Không đủ cà phê. Bỏ qua câu trả lời trước của tôi.

Bạn cần điều chỉnh ngày dựa trên tháng/ngày sinh nhật bạn đang kiểm tra.

Bạn không thể luôn sử dụng năm bị ràng buộc phía trên vì ngày sinh có thể rơi vào tháng lớn hơn tháng bị ràng buộc phía trên. Một giải pháp thay thế đơn giản là thực hiện kiểm tra hai lần: một lần sử dụng năm bị ràng buộc trên và sau đó lại sử dụng năm trước đó. Thao tác này xử lý các trường hợp ranh giới năm:

var birthday = DateTime.Parse("1/2/2000"); 
var lowerBound = DateTime.Parse("12/25/2008"); 
var upperBound = DateTime.Parse("1/3/2009"); 

var adjustA = new Birthday(upperBound.Year, birthday.Month, birthday.Day); 
var adjustB = adjustA.AddYears(-1); 

var isInBounds = (adjustA >= lowerBound && adjustA <= upperBound) || 
       (adjustB >= lowerBound && adjustB <= upperBound); 
+0

Nếu người đó được sinh ra trong năm 2010, điều này vẫn sẽ nói rằng anh ấy có sinh nhật trong phạm vi đó. Tôi đã cung cấp một giải pháp có thể bằng cách kiểm tra đầu tiên chỉ trong năm và sau đó bình thường hóa ngày sinh nhật để so sánh. –

+0

Trình tạo DateTime của bạn sai. Giải pháp của bạn không khớp với 12/26/2000 – tanascius

+0

Và điều gì xảy ra, ví dụ, khi 'someBirthday' là' 29/02/2008' và 'upperBoundDate' là' 25/03/2009'? – LukeH

0

Bạn có thể vẽ hình ảnh này tốt nhất.

Vấn đề về cơ bản là xác định nếu tồn tại N sao cho sinh nhật thứ N của người đó nằm trong phạm vi hay không.

Bạn có thể lấy đường cơ sở và thực hiện phép tính số ngày với modulo, điều này sẽ xử lý số lần chuyển đổi năm (nhưng năm nhuận có thể gây ra lỗi theo từng lần).

Một giải pháp khác có thể làm cho biểu diễn đơn giản hơn là vì ngày sinh tạo thành lưới 1-D trên dòng lịch, vì ngày sinh không nằm trong phạm vi, phạm vi phải nằm hoàn toàn giữa ngày sinh của người đó năm: tức là KHÔNG (BirthdayY1 < RangeStart & & Phạm viEnd < BirthdayY2).

Thông thường khi chúng tôi thực hiện loại phân tích này vào tháng, do đó, việc tìm kiếm tất cả sinh nhật vào tháng 5 trở nên đơn giản hơn nhiều, ví dụ như để nhận thẻ sinh nhật.

0

Đặt birthday to năm = 2000, từ ngày này sang năm khác = 2000, và cho đến nay với năm 2000. Nếu đến nay là trước từ ngày, thiết lập cho đến nay với năm 2001.

Sau đó shenanigans, từ trên cao:

if (Birthday > DateRangeLower && Birthday < DateRangeUpper) { 
    // it's your birthday! 
} 
0

Sẽ làm việc này !!!

for(int i = startDate.year; i <= endDate.year; i++) 
{ 
    DateTime newBD = new DateTime(i, BD.month, BD.day); 
    if((DateTime.Compare(newBD, startDate) >= 0) && (DateTime.Compare(newBD, endDate) <= 0))   
    { 
     //gotcha 
     break; 
    } 
} 
1

Tôi chỉ muốn chuyển đổi tất cả các ngày để thời gian Epoch, sau đó làm một so sánh thẳng.

tôi thấy chuyển đổi này here, chút thay đổi

int epoch = (int)({Beginning/Ending Date} - new DateTime(1970, 1, 1)).TotalSeconds; 

Vì vậy, toàn bộ thiết lập của bạn mã sẽ chỉ được

int StartDateInEpoch = (int)(StartDate - new DateTime(1970, 1, 1)).TotalSeconds; 
int EndDateInEpoch = (int)(EndDate - new DateTime(1970, 1, 1)).TotalSeconds; 
int TargetDateInEpoch = (int)(TargetDate - new DateTime(1970, 1, 1)).TotalSeconds; 

if (StartDateInEpoch < TargetDateInEpoch && TargetDateInEpoch <= EndDateInEpoch) 
    return true; 
1

Một câu trả lời khác nhau, di chuyển tất cả các ngày đến một năm cụ thể.

public static bool IsBirthDayInRange(DateTime birthday, DateTime start, DateTime end) 
{ 
    // This could be any date... 
    var epoch = new DateTime(1970, 1, 1); 

    // Start date is always epoch, end date is epoch + range span 
    DateTime endDateInEpoch = epoch.AddSeconds((end - start).TotalSeconds); 
    // Move the bithday back to epoch.Year 
    DateTime birthDayInEpoch = birthday.AddYears(epoch.Year - birthday.Year); 

    return birthday <= end && epoch < birthDayInEpoch && birthDayInEpoch <= endDateInEpoch; 
} 
0

Cái này nên xử lý một cách chính xác năm nhuận:

public static bool IsBirthdayInRange(DateTime birthday, DateTime from, DateTime to) 
{ 
    if (to < from) 
    { 
     throw new ArgumentException("The specified range is not valid"); 
    } 

    int year = from.Year; 
    int month = birthday.Month; 
    int day = birthday.Day; 
    if (from.DayOfYear > to.DayOfYear && birthday.DayOfYear < from.DayOfYear) 
    { 
     year++; 
    } 
    if (month == 2 && day == 29 && !DateTime.IsLeapYear(year)) 
    { 
     // Assuming people born on February 29 celebrate their birthday 
     // one day earlier on non-leap years 
     day--; 
    } 
    DateTime bDate = new DateTime(year, month, day); 
    return bDate >= from.Date && bDate <= to.Date; 
} 
Các vấn đề liên quan