Date and time Calculator - c#

I was hoping for some help with something I have been working on.
I have an ASP.NET web form that is trying to be a calculator, now I have dates and days of the week sorted as well as other forms of other parts working.
Now I need to add public holidays to this form.
I have an array holding the dates and if I put a date range of any type I get the full count as if it was counting for a full year.
And the intent is to read the date rage and pick the holidays in said date rage and only show said dates e.g.over two years the count should be double.
I'm sure it's something simple, I'm just not seeing it.
public class Program
{
public static void Main()
{
DisplayDayInfo(new DateTime(2018, 01, 01), new DateTime(2019, 01, 01));
// Show info for April 2018
//DisplayDayInfo(new DateTime(2018, 04, 01), new DateTime(2018, 05, 01));
}
private static int GetDayCount(IEnumerable<DateTime>dates, DayOfWeek dayOfWeek)
{
return dates == null ? 0 : dates.Count(date => date.DayOfWeek == dayOfWeek);
}
private static int GetHoliDayCount(IEnumerable<DateTime> holiday, DayOfWeek dayOfWeek)
{
DateTime[] holidayState = new DateTime[]
{
new DateTime(DateTime.Now.Year, 1, 1),
new DateTime(DateTime.Now.Year, 1, 26),
new DateTime(DateTime.Now.Year, 3, 30),
new DateTime(DateTime.Now.Year, 3, 31),
new DateTime(DateTime.Now.Year, 4, 1),
new DateTime(DateTime.Now.Year, 4, 2),
new DateTime(DateTime.Now.Year, 4, 25),
new DateTime(DateTime.Now.Year, 5, 7),
new DateTime(DateTime.Now.Year, 8, 15),
new DateTime(DateTime.Now.Year, 9, 1),
new DateTime(DateTime.Now.Year, 12, 25),
new DateTime(DateTime.Now.Year, 12, 26)
};
return holiday == null ? 0 : holidayState.Count(date => date.DayOfWeek == dayOfWeek);
}
private static void DisplayDayInfo(DateTime fromDate, DateTime toDate)
{
var numDays = toDate.Subtract(fromDate).Days;
Console.WriteLine("Total number of days from {0} to {1}: {2}\n",fromDate.ToShortDateString(), toDate.ToShortDateString(), numDays);
var dates = Enumerable.Range(0, numDays).Select(days => fromDate.AddDays(days)).ToArray();
var holiday = Enumerable.Range(0, numDays).Select(days => fromDate.AddDays(days)).ToArray();
foreach (DayOfWeek dayOfWeek in Enum.GetValues(typeof(DayOfWeek)))
{
Console.WriteLine("{0} {1} ", dayOfWeek, GetDayCount(dates, dayOfWeek));
}
Console.WriteLine("****************************************************");
foreach (DayOfWeek dayOfWeek in Enum.GetValues(typeof(DayOfWeek)))
{
Console.WriteLine("{0} {1} ", dayOfWeek, GetHoliDayCount(holiday, dayOfWeek));
}
}
}
https://dotnetfiddle.net/XjoCpf
Any help would be grate, Thank you.

I changed some implementation of your methods based on your intent:
private static DateTime? GetHoliDayCount(DateTime holiday)
{
DateTime? holidayToReturn = null ;
DateTime[] holidayState = new DateTime[]
{
new DateTime(DateTime.Now.Year, 1, 1),
new DateTime(DateTime.Now.Year, 1, 26),
new DateTime(DateTime.Now.Year, 3, 30),
new DateTime(DateTime.Now.Year, 3, 31),
new DateTime(DateTime.Now.Year, 4, 1),
new DateTime(DateTime.Now.Year, 4, 2),
new DateTime(DateTime.Now.Year, 4, 25),
new DateTime(DateTime.Now.Year, 5, 7),
new DateTime(DateTime.Now.Year, 8, 15),
new DateTime(DateTime.Now.Year, 9, 1),
new DateTime(DateTime.Now.Year, 12, 25),
new DateTime(DateTime.Now.Year, 12, 26)
};
if (holidayState.Contains(holiday))
{
holidayToReturn = holiday;
}
return holidayToReturn;
}
Then you need to modify your DisplayDateInfo to loop over the holiday enumerable.
private static void DisplayDayInfo(DateTime fromDate, DateTime toDate)
{
var numDays = toDate.Subtract(fromDate).Days;
Console.WriteLine("Total number of days from {0} to {1}: {2}\n", fromDate.ToShortDateString(), toDate.ToShortDateString(), numDays);
var dates = Enumerable.Range(0, numDays).Select(days => fromDate.AddDays(days)).ToArray();
var holiday = Enumerable.Range(0, numDays).Select(days => fromDate.AddDays(days)).ToArray();
foreach (DayOfWeek dayOfWeek in Enum.GetValues(typeof(DayOfWeek)))
{
Console.WriteLine("{0} {1} ", dayOfWeek, GetDayCount(dates, dayOfWeek));
}
Console.WriteLine("****************************************************");
foreach (DateTime dayOfWeek in holiday)
{
string holidayToWrite = GetHoliDayCount(dayOfWeek).ToString();
if (holidayToWrite != "")
Console.WriteLine("{0} ", holidayToWrite);
}
}
Result:
Or if you don't want to edit the method signature of your GetHolidayCount method and do no changes in your DisplayDateInfo method, you can do this by comparing your IEnumerable range to the dates in the array, and if an item in the array contains the date in your IEnumerable then add it to the final list.:
private static int GetHoliDayCount(IEnumerable<DateTime> holiday, DayOfWeek dayOfWeek)
{
List<DateTime> days = holiday.ToList(); //convert this to list
List<DateTime> daysToAdd = new List<DateTime>(); //have a list as container for the holidays after the comparison.
DateTime[] holidayState = new DateTime[]
{
new DateTime(DateTime.Now.Year, 1, 1),
new DateTime(DateTime.Now.Year, 1, 26),
new DateTime(DateTime.Now.Year, 3, 30),
new DateTime(DateTime.Now.Year, 3, 31),
new DateTime(DateTime.Now.Year, 4, 1),
new DateTime(DateTime.Now.Year, 4, 2),
new DateTime(DateTime.Now.Year, 4, 25),
new DateTime(DateTime.Now.Year, 5, 7),
new DateTime(DateTime.Now.Year, 8, 15),
new DateTime(DateTime.Now.Year, 9, 1),
new DateTime(DateTime.Now.Year, 12, 25),
new DateTime(DateTime.Now.Year, 12, 26)
};
foreach (DateTime day in days)
{
if (holidayState.Contains(day))
{
daysToAdd.Add(day);
}
}
holiday = daysToAdd;
return holiday == null ? 0 : holidayState.Count(date => date.DayOfWeek == dayOfWeek);
}
You can also use this method if you don't want the instantiation of your holidayState array to be limited to the current year. What this does is that it groups the years in your enumerable and runs the comparison of your holiday enumerable to the array for each year in the grouping:
private static int GetHoliDayCount(IEnumerable<DateTime> holiday, DayOfWeek dayOfWeek)
{
var yearsGroup = holiday.GroupBy(x => x.Year);
List<DateTime> daysToAdd = new List<DateTime>();
DateTime[] holidayState = null;
foreach (var year in yearsGroup)
{
List<DateTime> days = holiday.Where(x => x.Year == Convert.ToInt32(year.Key)).ToList();
holidayState = new DateTime[]
{
new DateTime(Convert.ToInt32(year.Key), 1, 1),
new DateTime(Convert.ToInt32(year.Key), 1, 26),
new DateTime(Convert.ToInt32(year.Key), 3, 30),
new DateTime(Convert.ToInt32(year.Key), 3, 31),
new DateTime(Convert.ToInt32(year.Key), 4, 1),
new DateTime(Convert.ToInt32(year.Key), 4, 2),
new DateTime(Convert.ToInt32(year.Key), 4, 25),
new DateTime(Convert.ToInt32(year.Key), 5, 7),
new DateTime(Convert.ToInt32(year.Key), 8, 15),
new DateTime(Convert.ToInt32(year.Key), 9, 1),
new DateTime(Convert.ToInt32(year.Key), 12, 25),
new DateTime(Convert.ToInt32(year.Key), 12, 26)
};
foreach (DateTime day in days)
{
if (holidayState.Contains(day))
{
daysToAdd.Add(day);
}
}
}
holiday = daysToAdd;
return holiday == null ? 0 : holidayState.Count(date => date.DayOfWeek == dayOfWeek);
}
UPDATE: Using my first implementation stated above, I was able to get all dates for a given range (say 6 months). I don't know if this is what you need.

Related

Calculate total minutes in list of datetime

I have list of Appointment class.
In below code;
appointment1,appointment2 and appointment3 are intersect.
appointment4 and appointment5 are intersect.
appointment6 is non intersect
appointment1,appointment2 and appointment3 start datetime is '2018-07-10 08:00:00' and finish datetime is '2018-07-10 12:00:00' and total time is 4 hours here.
appointment4 and appointment5 start datetime is '2018-07-10 14:00:00' and finishdatetime is '2018-07-10 17:00:00' and total time is 3 hours here.
and appointment6 is non intersect comes 1 hour here.
And total time is 4+3+1=8,
How can i find 8 in given Appointment datetime values.
class Program
{
static void Main(string[] args)
{
List<Appointment> appointments = new List<Appointment>();
Appointment appointment1 = new Appointment();
appointment1.StartDate = new DateTime(2018, 07, 11, 08, 00, 00);
appointment1.FinishDate = new DateTime(2018, 07, 11, 11, 00, 00);
Appointment appointment2 = new Appointment();
appointment2.StartDate = new DateTime(2018, 07, 11, 10, 00, 00);
appointment2.FinishDate = new DateTime(2018, 07, 11, 12, 00, 00);
Appointment appointment3 = new Appointment();
appointment3.StartDate = new DateTime(2018, 07, 11, 09, 00, 00);
appointment3.FinishDate = new DateTime(2018, 07, 11, 12, 00, 00);
Appointment appointment4 = new Appointment();
appointment4.StartDate = new DateTime(2018, 07, 11, 14, 00, 00);
appointment4.FinishDate = new DateTime(2018, 07, 11, 16, 00, 00);
Appointment appointment5 = new Appointment();
appointment5.StartDate = new DateTime(2018, 07, 11, 15, 00, 00);
appointment5.FinishDate = new DateTime(2018, 07, 11, 17, 00, 00);
Appointment appointment6 = new Appointment();
appointment6.StartDate = new DateTime(2018, 07, 11, 18, 00, 00);
appointment6.FinishDate = new DateTime(2018, 07, 11, 19, 00, 00);
appointments.Add(appointment1);
appointments.Add(appointment2);
appointments.Add(appointment3);
appointments.Add(appointment4);
appointments.Add(appointment5);
appointments.Add(appointment6);
Console.ReadLine();
}
}
public class Appointment
{
public DateTime StartDate { get; set; }
public DateTime FinishDate { get; set; }
}
You first need to merge the overlapping times and then sum the timespan:
void Main()
{
List<Appointment> appointments = new List<Appointment>();
Appointment appointment1 = new Appointment();
appointment1.StartDate = new DateTime(2018, 07, 11, 08, 00, 00);
appointment1.FinishDate = new DateTime(2018, 07, 11, 11, 00, 00);
Appointment appointment2 = new Appointment();
appointment2.StartDate = new DateTime(2018, 07, 11, 10, 00, 00);
appointment2.FinishDate = new DateTime(2018, 07, 11, 12, 00, 00);
Appointment appointment3 = new Appointment();
appointment3.StartDate = new DateTime(2018, 07, 11, 09, 00, 00);
appointment3.FinishDate = new DateTime(2018, 07, 11, 12, 00, 00);
Appointment appointment4 = new Appointment();
appointment4.StartDate = new DateTime(2018, 07, 11, 14, 00, 00);
appointment4.FinishDate = new DateTime(2018, 07, 11, 16, 00, 00);
Appointment appointment5 = new Appointment();
appointment5.StartDate = new DateTime(2018, 07, 11, 15, 00, 00);
appointment5.FinishDate = new DateTime(2018, 07, 11, 17, 00, 00);
Appointment appointment6 = new Appointment();
appointment6.StartDate = new DateTime(2018, 07, 11, 18, 00, 00);
appointment6.FinishDate = new DateTime(2018, 07, 11, 19, 00, 00);
appointments.Add(appointment1);
appointments.Add(appointment2);
appointments.Add(appointment3);
appointments.Add(appointment4);
appointments.Add(appointment5);
appointments.Add(appointment6);
var ranges = appointments.Select(a => new Range {Start=a.StartDate, End=a.FinishDate});
var total = MergeTimes(ranges).Sum(a => (a.End-a.Start).TotalHours);
Console.WriteLine(total);
}
public class Appointment
{
public DateTime StartDate { get; set; }
public DateTime FinishDate { get; set; }
}
public class Range
{
public DateTime Start {get;set;}
public DateTime End {get;set;}
}
public IEnumerable<Range> MergeTimes(IEnumerable<Range> times)
{
if (times.Count() == 0)
{
return times;
}
Range[] orderedTimes = (from t in times
orderby t.Start
select t).ToArray();
List<Range> merged = new List<Range>();
Range current = new Range
{
Start = orderedTimes[0].Start,
End = orderedTimes[0].End
};
for (int i = 0; i < orderedTimes.Length; i++)
{
if (current.Start <= orderedTimes[i].End && current.End >= orderedTimes[i].Start)
{
current.Start = ((current.Start < orderedTimes[i].Start) ? current.Start : orderedTimes[i].Start);
current.End = ((current.End > orderedTimes[i].End) ? current.End : orderedTimes[i].End);
}
else
{
merged.Add(new Range
{
Start = current.Start,
End = current.End
});
current = new Range
{
Start = orderedTimes[i].Start,
End = orderedTimes[i].End
};
}
}
merged.Add(new Range
{
Start = current.Start,
End = current.End
});
return merged;
}
Let's sort the appointments and then Aggregate them: we have only 3 choices to implement:
Appointments disjoint
Appointment includes the next appointment
Appointments overlap
Sample code:
var total = appointments
.OrderBy(appointment => appointment.StartDate)
.Aggregate(new Tuple<double, DateTime?>(0.0, null), (acc, item) => {
if (!acc.Item2.HasValue || acc.Item2.Value <= item.StartDate) // Disjoint
return new Tuple<double, DateTime?>(
acc.Item1 + (item.FinishDate - item.StartDate).TotalHours,
item.FinishDate);
else if (acc.Item2.Value >= item.FinishDate) // Include
return acc;
else // Partially overlap
return new Tuple<double, DateTime?>(
acc.Item1 + (item.FinishDate - acc.Item2.Value).TotalHours,
item.FinishDate);
})
.Item1;
// 8
Console.WriteLine(total);
Are you aware of the properties on the TimeSpan class?
(dateA - dateB).TotalMinutes
https://msdn.microsoft.com/en-us/library/system.timespan.totalminutes.aspx
One way to solve this would be to gather the hours that are covered by appointments, then group them.
You could add a method to the Appointment class to get the hours covered by the appointment:
public IEnumerable<int> GetHours()
{
List<int> hours = new List<int>();
var startDate = StartDate;
var finishDate = FinishDate;
while(startDate < finishDate)
{
hours.Add(startDate.Hour);
startDate = startDate.AddHours(1);
}
return hours;
}
You can then group them:
var result = appointments.SelectMany(a => a.GetHours()).GroupBy(i => i);
Console.WriteLine("Total hours: {0}", result.Count()); //This is the count
foreach (var hour in result)
{
Console.WriteLine("{0} => {1}", hour.Key, hour.Count());
}
Output in console:
Total hours: 8
8 => 1
9 => 2
10 => 3
11 => 2
14 => 1
15 => 2
16 => 1
18 => 1

Declaring a range of dates with datetime

I would like to know the best way to set a range of dates. I have logic that checks what day a certain record is approved on and based on that day i set a date the next time that record needs to be re-approved
so if the record is approved in january or february it should be re evaluated in march if its approved in march it should be re evaluated in june.
i declare my ranges like this for now, but this i believe is not the best way to do it
DateTime quarterOneStart = new DateTime(DateTime.Now.Year,07,01);
DateTime quarterOneEnd = new DateTime(DateTime.Now.Year, 09, 15));
DateTime quarterTwoStart = new DateTime(DateTime.Now.Year, 10, 01);
DateTime quarterTwoEnd = new DateTime(DateTime.Now.Year, 12, 15));
DateTime quarterThreeStart = new DateTime(DateTime.Now.Year, 01, 01);
DateTime quarterThreeEnd = new DateTime(DateTime.Now.Year, 03, 15));
DateTime quarterFourStart = new DateTime(DateTime.Now.Year, 04, 01);
DateTime quarterFourEnd = new DateTime(DateTime.Now.Year, 06, 15));
is there a better way to set the date time variables above?
What about class for quarter
public class Quarter {
private readonly DateTime _startDate;
private readonly DateTime _endDate;
public Quarter(DateTime startDate, DateTime endDate) {
_startDate = startDate;
_endDate = endDate;
}
public DateTime StartDate => _startDate;
public DateTime EndDate => _endDate;
}
and use it
Quarter one = new Quarter(new DateTime(2017, 07, 01), new DateTime(2017, 09, 15));
Quarter two = new Quarter(new DateTime(2017, 09, 15), new DateTime(2017, 10, 01));
...
Rather than creating multiple variables, you can create a Dictionary of items key'ed by an enum. For example:
public enum Quaters
{
Q1_Start,
Q1_End,
Q2_Start,
Q2_End,
Q3_Start,
Q3_End,
Q4_Start,
Q4_End
}
Dictionary<Quaters, DateTime> dateRange = new Dictionary<Quaters, DateTime>
{
{Quaters.Q1_Start, new DateTime(DateTime.Now.Year, 07, 01)},
{Quaters.Q1_End, new DateTime(DateTime.Now.Year, 09, 15)},
{Quaters.Q2_Start, new DateTime(DateTime.Now.Year, 10, 01)},
{Quaters.Q2_End, new DateTime(DateTime.Now.Year, 12, 15)},
...
};
When you need to verify the value against any range parameter you can index the dateRange dictionary based on keys. It is just a proposal and there could be better solutions to your actual problem.
In the past I've written a FinancialYear class that internally holds a startYear (int) variable and offers various methods/properties, e.g. (among others)
public DateTime StartDate
{
get { return new DateTime(_startYear, 4, 1); } // April 1st
}
public static FinancialYear ForDate(DateTime dt)
{
DateTime finYearStart = new DateTime(dt.Year, 4, 1);
return (dt >= finYearStart) ? new FinancialYear(dt.Year) : new FinancialYear(dt.Year - 1);
}

C# - Searching Time between 2 DateTime Objects of different days

i have a list of "event" objects.
In every event i have "EventStartTime" and "EventEndTime" declared as DateTime objects.
I want to be able to search "events" by time , for example 10:00,
the "event" you see below shows that the festival starts at 22:00 on Feb 17th,
and ends at 15:00 the following day. i have a couple more like these.
new EventsManager.Event() //3
{
EventType = EventsManager.EventType.Festival,
EventName = "Twistival",
EventPlace = placeList[4],
EventStartTime =new DateTime(2017,02,17,22,0,0),
EventEndTime = new DateTime(2017,02,18,15,0,0),
EventNumberOfParticipants = 8000
},
So when i search for event that occur, or still occurring at at 10:00
i should get this event.
any suggestions?
Assuming that you have a specific time of day that you want to determine if the event covers regardless of the date it covers it on then there are 4 cases you need to consider. First if the dates are more than 1 day apart they cover all times of day. If the start is before the time of day and the end is after the time of day it will cover the time. The last two cases require that the end date be on the next day from the start date, then either the start date is before the time of day, or the end date is after the time of day. Note that this also assumes that the start date is before the end date.
var events = new List<Tuple<DateTime, DateTime>>
{
// start and end after time of day but on different days
Tuple.Create(
new DateTime(2017, 02, 17, 22, 0, 0),
new DateTime(2017, 02, 18, 15, 0, 0)),
// start and end before time of day but on different days
Tuple.Create(
new DateTime(2017, 02, 17, 9, 0, 0),
new DateTime(2017, 02, 18, 7, 0, 0)),
// start before and end after same day
Tuple.Create(
new DateTime(2017, 02, 17, 9, 0, 0),
new DateTime(2017, 02, 17, 11, 0, 0)),
// covers more than 1 day
Tuple.Create(
new DateTime(2017, 02, 17, 22, 0, 0),
new DateTime(2017, 02, 18, 22, 0, 1)),
// start after and end before on different days
Tuple.Create(
new DateTime(2017, 02, 17, 22, 0, 0),
new DateTime(2017, 02, 18, 10, 0, 0)),
// start and end before on same day
Tuple.Create(
new DateTime(2017, 02, 17, 7, 0, 0),
new DateTime(2017, 02, 17, 8, 0, 0)),
// start and end after on same day
Tuple.Create(
new DateTime(2017, 02, 17, 11, 0, 0),
new DateTime(2017, 02, 17, 12, 0, 0)),
};
var timeOfDay = new TimeSpan(0, 10, 0 ,0);
foreach (var x in events)
{
if (x.Item2 - x.Item1 > TimeSpan.FromDays(1)
|| (x.Item1.TimeOfDay < timeOfDay && x.Item2.TimeOfDay > timeOfDay)
|| (x.Item1.Date < x.Item2.Date
&& (x.Item1.TimeOfDay < timeOfDay || x.Item2.TimeOfDay > timeOfDay)))
{
Console.WriteLine(x);
}
}
Will output
(2/17/2017 10:00:00 PM, 2/18/2017 3:00:00 PM)
(2/17/2017 9:00:00 AM, 2/18/2017 7:00:00 AM)
(2/17/2017 9:00:00 AM, 2/17/2017 11:00:00 AM)
(2/17/2017 10:00:00 PM, 2/18/2017 10:00:01 PM)
Let's say you have a
List<Event> Events;
of your Events. You can create a simple LINQ query to get all events running at a special time with a simple method like
private IEnumerable<Event> GetRunningEvents(DateTime time)
{
return Events.Where(E => E.EventStartTime <= time && E.EventEndTime >= time);
}
Dont forget to add
using System.Linq;
to your file.
EDIT: Without LINQ a possible approach is
private List<Event> GetRunningEvents(DateTime time)
{
List<Event> RunningEvents = new List<Event>();
foreach(Event E in Events)
{
if (E.EventStartTime <= time && E.EventEndTime >= time)
{
RunningEvents.Add(E);
}
}
return RunningEvents;
}
Try Linq Where:
var list = new List<Event>();
var searchTime = DateTime.Now;
var result = list.Where(e => e.EventStartTime <= searchTime && searchTime <= e.EventEndTime).ToList();

How can i find all the times between two given dates and time? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
private void GetTimeBetween()
{
DateTime a = new DateTime(2010, 04, 24, 13, 10, 00);
DateTime b = new DateTime(2010, 04, 25, 13, 10, 00);
Console.WriteLine(b.Subtract(a).TotalMinutes);
double d = b.Subtract(a).TotalMinutes;
}
I'm getting TotalMinutes 1440
But how can i make now that it will create a List with all the dates and time between this two dates between a and b but in jumps of 10 minutes ?
For example in the List the first item will be:
24/4/2010 13:10:00
Then ext item will be
24/4/2010 13:20:00
And so on until b
25/4/2010 13:10:00
In this format in the List or in other formats but the idea to get all the dates+time between the two given dates.
Gee, sometimes its fun to overengineer things. There is an Aggregate function which turns a list into a scalar value - lets create one that goes the other way
public static class Extensions
{
public static IEnumerable<T> Explode<T>(this T value, Func<T,T> next, Func<T,bool> limit)
{
var n = value;
while(!limit(n))
{
yield return n;
n = next(n);
}
}
}
Usage:
DateTime a = new DateTime(2010, 04, 24, 13, 10, 00);
DateTime b = new DateTime(2010, 04, 25, 13, 10, 00);
var result = a.Explode(x => x.AddMinutes(10), x => x>b).ToList();
Live example: http://rextester.com/WCGZL87983
You could loop it:
var list = new List<DateTime>();
var start = new DateTime(2010, 04, 24, 13, 10, 00);
var end = new DateTime(2010, 04, 25, 13, 10, 00);
for (DateTime date = start; date <= end; date = date.AddMinutes(10))
list.Add(date);
Try this
var start = new DateTime(2010, 04, 24, 13, 10, 00);
var end = new DateTime(2010, 04, 25, 13, 10, 00);
for (DateTime date = start; date <= end; date = date.AddMinutes(10))
{
Console.WriteLine(date.ToString("dd/mm/yyyy HH:mm:ss"));
}

Linq to Entity Birthday Comparison

I have the requirement to create a query using Linq to Entities where the birthday must fall within 2 days ago and the next 30 days.
The following returns nothing:
DateTime twoDaysAgo = DateTime.Now.AddDays(-2);
int twoDaysAgoDay = twoDaysAgo.Day;
int twoDaysAgoMonth = twoDaysAgo.Month;
DateTime MonthAway = DateTime.Now.AddDays(30);
int monthAwayDay = MonthAway.Day;
int monthAwayMonth = MonthAway.Month;
var bdays = from p in db.Staffs where EntityFunctions.TruncateTime(p.BirthDate) > EntityFunctions.TruncateTime(twoDaysAgo) &&
EntityFunctions.TruncateTime(p.BirthDate) < EntityFunctions.TruncateTime(MonthAway)
orderby p.BirthDate select p;
return bdays;
The problem I'm having is that I need something where if the birthday falls from 11/3 to 12/5, it should return it. The reason it fails because the birthdays include the Year. However, when I use something like:
p.BirthDate.Value.Month
I receive the error that this isn't support with Linq to Entities. Any assistance would be appreciated.
Year-wrapping independent solution:
void Main()
{
var birthdays = new List<DateTime>();
birthdays.Add(new DateTime(2013, 11, 08));
birthdays.Add(new DateTime(2012, 05, 05));
birthdays.Add(new DateTime(2014, 05, 05));
birthdays.Add(new DateTime(2005, 11, 08));
birthdays.Add(new DateTime(2004, 12, 31));
foreach(var date in birthdays.Where(x => x.IsWithinRange(twoDaysAgo, MonthAway))){
Console.WriteLine(date);
}
}
public static class Extensions {
public static bool IsWithinRange(this DateTime #this, DateTime lower, DateTime upper){
if(lower.DayOfYear > upper.DayOfYear){
return (#this.DayOfYear > lower.DayOfYear || #this.DayOfYear < upper.DayOfYear);
}
return (#this.DayOfYear > lower.DayOfYear && #this.DayOfYear < upper.DayOfYear);
}
}
Output with
DateTime twoDaysAgo = DateTime.Now.AddDays(-2);
DateTime MonthAway = DateTime.Now.AddDays(30);
8/11/2013 0:00:00
8/11/2005 0:00:00
Output with
DateTime twoDaysAgo = new DateTime(2012, 12, 25);
DateTime MonthAway = new DateTime(2013, 01, 05);
31/12/2004 0:00:00
If you want to ignore the value of the year, what about using DayOfYear function ?
var bdays = from p in db.Staffs
where EntityFunctions.DayOfYear(p.BirthDate) > EntityFunctions.DayOfYear(twoDaysAgo) &&
EntityFunctions.DayOfYear(p.BirthDate) < EntityFunctions.DayOfYear(MonthAway)
orderby p.BirthDate select p;
You can change all the years to now since year is irrelevant and then you can check it this way
DateTime twoDaysAgo = DateTime.Today.AddDays(-2);
DateTime monthAway = DateTime.Today.AddMonths(1);
List<DateTime> checkDates = new List<DateTime>
{ new DateTime(2011, 11, 3), new DateTime(2011, 12, 5), new DateTime(2011, 12, 6), new DateTime(2011, 11, 2) };
checkDates = checkDates.Select(x => new DateTime(DateTime.Today.Year, x.Month, x.Day)).ToList();
var bdays = from p in checkDates
where (p >= twoDaysAgo && p <= monthAway) ||
(p>= twoDaysAgo.AddYears(-1) && p <= monthAway.AddYears(-1))
orderby p
select p;
This results in
11/3/2013 12:00:00 AM
12/5/2013 12:00:00 AM
This also works with the following list of dates when today is new DateTime(2013, 12, 31)
List<DateTime> checkDates = new List<DateTime>
{ new DateTime(2011, 12, 29), new DateTime(2011, 12, 28), new DateTime(2011, 1, 30), new DateTime(2011, 2, 2) };
Giving the results
1/30/2013 12:00:00 AM
12/29/2013 12:00:00 AM
How about if you add the the nr. of years from the birthdate to today?
Something like:
(untested)
var now = DateTime.Now;
var twoDaysAgo = now.AddDays(-2);
var monthAway = now.Now.AddDays(30)
var bdays =
from p in db.Staffs
let bDay = EntityFunctions.AddYears(p.BirthDate,
EntityFunctions.DiffYears(now, p.BirthDate))
where
bDay > twoDaysAgo &&
bDay < monthAway
orderby p.BirthDate
select p;

Categories