Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Query upcoming birthdays

I'd like to query my customers for the ones, whose birthdays are yet to come.

I've tried this query, and it - of course - has failed breathtakingly:

Addresses.Where(adr => adr.DateOfBirth != null && adr.DateOfBirth.Value >
DateTime.Now).Take(15).ToList();

Of course this can't work properly (not if you're born in the future) and I'd like to know how I can query my Nullable<DateTime> without a year?

like image 861
SeToY Avatar asked Dec 26 '22 08:12

SeToY


2 Answers

You can do it in one line like this:

context.Addresses.Where(adr => adr.DateOfBirth != null).OrderBy(adr => EntityFunctions.DiffDays(DateTime.Today, EntityFunctions.AddYears(adr.DateOfBirth, EntityFunctions.DiffYears(adr.DateOfBirth, DateTime.Today) + ((adr.DateOfBirth.Month < DateTime.Today.Month || (adr.DateOfBirth.Day <= DateTime.Today.Day && adr.DateOfBirth.Month == DateTime.Today.Month)) ? 1 : 0)))).Take(15).ToList();

Or in a more readable format:

var query = from adr in context.Addresses
            where adr.DateOfBirth != null
            let diffYears = EntityFunctions.DiffYears(adr.DateOfBirth, DateTime.Today)
            let birthdayOccurred = adr.DateOfBirth.Month < DateTime.Today.Month || (adr.DateOfBirth.Day <= DateTime.Today.Day && adr.DateOfBirth.Month == DateTime.Today.Month)
            let nextBirthdate = EntityFunctions.AddYears(adr.DateOfBirth, diffYears + (birthdayOccurred ? 1 : 0))
            let daysToBirthdate = EntityFunctions.DiffDays(DateTime.Today, nextBirthdate)
            orderby daysToBirthdate
            select adr;

var result = query.Take(15).ToList();
like image 158
Aducci Avatar answered Jan 09 '23 13:01

Aducci


I'm not sure you can do this as a one-liner. Certainly not with any degree of clarity.

The needed steps are:

  1. Create an ordered list containing only the birthdates where the month/day comes after today.
  2. Create an ordered list containing only the birthdates where the month/day is before today.
  3. Append the second list to the first one, you now have a single list, sorted in birthday order.
  4. Take the first 15.

I think the C# code would look something like this (You might need to add a List or two.)

var list1 = Addresses.Where(adr => adr.DateOfBirth != null && (adr.DateOfBirth.Value.Month > DateTime.Today.Month || (adr.DateOfBirth.Value.Month == DateTime.Today.Month && adr.DateOfBirth.Value.Day >= DateTime.Today.Day))).ToList();
var list2 = Addresses.Where(adr => adr.DateOfBirth != null && (adr.DateOfBirth.Value.Month < DateTime.Today.Month || (adr.DateOfBirth.Value.Month == DateTime.Today.Month && adr.DateOfBirth.Value.Day < DateTime.Today.Day))).ToList();
var fullList = list1.Add(list2);
like image 30
ThatBlairGuy Avatar answered Jan 09 '23 11:01

ThatBlairGuy