按生日加载用户

时间:2013-08-01 07:47:05

标签: c# .net

我想知道有没有更好/更简单的方式来加载用户的生日。

我有一个User实例,它有属性,包括这个:

public DateTime? BirthDate { get; set; }

我想要做的是加载从一个日期到另一个日期的bday的用户:

public IEnumerable<User> LoadUsersByBirthday(DateTime from, DateTime into)

我不关心生日年,例如,如果我有3个生日用户:

  1. DateTime(1991,3,20);
  2. DateTime(1990,4,25);
  3. DateTime(1989,3,10);
  4. LoadUsersByBirthday(new DateTime(2990, 3, 1), new DateTime(3013, 4, 15))应该返回2个用户 - 第1和第3个。

    我的方法如下:

    public IEnumerable<User> LoadUsersByBirthday(DateTime from, DateTime into)
        {
            var days = DateTime.DaysInMonth(from.Year, from.Month);
    
            var u1 = _unit.User.Load(u => ((DateTime) (u.BirthDate)).Month == from.Month
                                          && ((DateTime) (u.BirthDate)).Day >= from.Day
                                          && ((DateTime) (u.BirthDate)).Day <= days);
    
            var u2 = _unit.User.Load(u => ((DateTime) (u.BirthDate)).Month > from.Month
                                          && ((DateTime) (u.BirthDate)).Month < into.Month);
    
            var u3 = _unit.User.Load(u => ((DateTime) (u.BirthDate)).Month == into.Month 
                                          && ((DateTime) (u.BirthDate)).Day <= into.Day);
    
            return u1.Concat(u2).Concat(u3);
        }
    

    它有效,但有更好/更简单的方法吗?

4 个答案:

答案 0 :(得分:3)

由于闰年引起的问题以及生日实际上是闰日的人,这比预期更难解决。

最后,我记得我已经有一种方法可以准确计算出某人的年龄,计算闰年和闰年的生日。

鉴于这种方法,确定某人是否有生日给出一系列日期是微不足道的:

首先,计算他们的年龄 BEFORE 范围的开始。 接下来,计算范围结束时的年龄。

如果计算的年龄不同,那么他们必须在指定的范围内过生日。

全部放在一起:

public IEnumerable<User> UsersByBirthday(IEnumerable<User> users, DateTime from, DateTime to)
{
    if (to < from)
        throw new ArgumentException("'from' must be at or before 'to'.");

    return users.Where(user => IsBirthdayInRange(user.BirthDate, from, to));
}

public bool IsBirthdayInRange(DateTime birthday, DateTime from, DateTime to)
{
    if (to < from)
        throw new ArgumentException("'from' must be at or before 'to'.");

    if (birthday > from)
        throw new ArgumentException("'from' must be after 'birthday'");

    return AgeInYears(birthday, from.AddDays(-1)) < AgeInYears(birthday, to);
}

/// <summary>Returns a person's age in years, accounting for leap years.</summary>

public static int AgeInYears(DateTime birthday, DateTime today)
{
    // See here for why this works:
    // http://social.msdn.microsoft.com/Forums/en-US/ba4a98af-aab3-4c59-bdee-611334e502f2/calculate-age-with-a-single-line-of-code-c

    return ((today.Year - birthday.Year) * 372 + (today.Month - birthday.Month) * 31 + (today.Day - birthday.Day)) / 372;
}

这是闰日生日的一个小测试:

DateTime test = new DateTime(2004, 2, 29); // Leap day.

var start = new DateTime(2005, 3, 1);
var end = new DateTime(2005, 6, 7);

Console.WriteLine(IsBirthdayInRange(test, start, end));

使用您的_unit.User.Load()

public IEnumerable<User> LoadUsersByBirthday(DateTime from, DateTime into)
{
    return _unit.User.Load(u => IsBirthdayInRange(u.Birthdate, from, into));
}

[编辑]

在非闰年处理闰日生日有两种可能性:将其视为2月28日,或将其视为3月1日。

上面的代码将其视为3月1日(根据英国法规)。如果您想参与处理,可以将leapDayMapsToFeb28参数添加到IsBirthdayInRange(),如下所示:

public bool IsBirthdayInRange(DateTime birthday, DateTime from, DateTime to, bool leapDayMapsToFeb28)
{
    if (to < from)
        throw new ArgumentException("'from' must be at or before 'to'.");

    if (birthday > from)
        throw new ArgumentException("'from' must be after 'birthday'");

    if (leapDayMapsToFeb28 && (birthday.Month == 2) && (birthday.Day == 29) && !DateTime.IsLeapYear(from.Year))
        birthday = new DateTime(birthday.Year, birthday.Month, 28);

    return AgeInYears(birthday, from.AddDays(-1)) < AgeInYears(birthday, to);
}

答案 1 :(得分:2)

我认为这应该有效:

public IEnumerable<User> UsersByBirthday(IEnumerable<User> users, DateTime from, DateTime to)
{
    var fromNormalized = NormalizeDate(from);
    var intoNormalized = NormalizeDate(into);

    return users.Where(u => fromNormalized <= NormalizeDate(u.BirthDate) && NormalizeDate(u.BirthDate) <= intoNormalized);
}

public int NormalizeDate(DateTime date)
{
    return date.Month * 100 + date.Day;
}

NormalizeDate()方法返回一个整数值,表示容易与之比较的月和日。 9月3日返回903,4月24日返回424。

如果from > to没有错误处理。

答案 2 :(得分:1)

您可以将DateTime转换为Ticks并进行比较。

类似代码的东西(没有VS附近可能是语法错误)

   DateTime from=new DateTime(...); 
   DateTime into=new DateTime(...); 

   IList<User> allUsers=...

固定:

IList<User> foundedUsers=allUsers.Where(user=> (new DateTime(1900, user.Birthday.Month,  user.Birthday.Day)>new DateTime(1900,from.Month,from,Day)) && ...).ToList();

答案 3 :(得分:1)

假设第一天是birthday1(y1,m1,d1),第二天是birthday2(y2,m2,d2),那么你可以使用它:

diff = 31 * (m2 - m1) + (d2 - d1)

因为-31 < d2 - d1 < 31,所以如果m2 - m1 > 0,那么无论d2或d1是什么,结果都是差异&gt; 0; m2 - m1 < 0diff < 0时的情况相同;当m2 == m1时,diff的值范围仅在d2和d1上消失。实际上,31可以替换为任何更大的数字31,如32。