Checking multiple DateTime of Interferences - c#

I got a list of DateTime which contains StartDate and EndDate,
User Should Select one or more TimeSpans from this list.
They are also have a structure class Named Courses.
How can I check if any overlaps is Happening or not
For example I got this
Start Date End Date
#1 7/20/2016 7/27/2016 Selected
#2 6/18/2016 7/25/2016 Selected
#3 7/20/2016 7/27/2016
#4 6/5/2016 6/10/2016
In this Example user has selected 2 dates that contains overlaps .
I want to warn the user with a message box or some Using C#.
Any opinion
Thanks

Ok, first created a class TimePeriod like this:
public class TimePeriod
{
public int Id;
public DateTime FromDate
{
get; set;
}
public DateTime ToDate
{
get; set;
}
public static DateTime Parse(string date)
{
var dt = DateTime.Parse(date,
CultureInfo.CreateSpecificCulture("en-US"), DateTimeStyles.RoundtripKind);
return dt;
}
}
Then created a List with items of this class:
List<TimePeriod> list = new List<TimePeriod>();
Then added your examples of Dates (added all of them, for your need just add selected one's):
list.Add(new TimePeriod() { Id = 1, FromDate = TimePeriod.Parse("7/20/2016"), ToDate = TimePeriod.Parse("7/27/2016") });
list.Add(new TimePeriod() { Id = 2, FromDate = TimePeriod.Parse("6/18/2016"), ToDate = TimePeriod.Parse("7/25/2016") });
list.Add(new TimePeriod() { Id = 3, FromDate = TimePeriod.Parse("7/20/2016"), ToDate = TimePeriod.Parse("7/27/2016") });
list.Add(new TimePeriod() { Id = 4, FromDate = TimePeriod.Parse("6/5/2016"), ToDate = TimePeriod.Parse("6/10/2016") });
And last check with LINQ for overlapping:
var overlaps = from current in list
from compare in list
where
(
(compare.FromDate > current.FromDate &&
compare.FromDate < current.ToDate) ||
(compare.ToDate > current.FromDate &&
compare.ToDate < current.ToDate)
)
select new
{
Id1 = current.Id,
Id2 = compare.Id,
};
The result will be in this case 1/2 & 2/1 and 2/3 & 3/2. In your case it will be 1/2 & 2/1.

There is a very good library for working with time periods and their intersection on nuget.
Time Period Library
There is also an article on code project for it.
Time Period Library for .NET

You need to store which dates have been selected and if they occur in multiple selections right?
Store startedate and enddate of each selected timespan to a Tuple selectedTimeSpans
then:
List<int> useddays =new List<int>();
foreach (Tuple<DateTime, DateTime> selected in selectedTimeSpans)
{
DateTime start = selected.Value1;
DateTime end = selected.Value2;
DateTime current = start;
while(current <=end)
{
if(useddays.Contains((current-DateTime.MinValue).TotalDays)
MessageBox. Show("Already used!");
else
useddays.Add((current-DateTime.MinValue).TotalDays);
current.AddDays(1);
}
}

Thanks To all #c0d3b34n and #ThomasVoß ,
Also to this article https://stackoverflow.com/a/325964/3970128
This is All I Have Done
Ok, first created a class TimePeriod like this:
public class TimePeriod
{
public int Id;
public DateTime FromDate
{
get; set;
}
public DateTime ToDate
{
get; set;
}
public static DateTime Parse(string date)
{
var dt = DateTime.Parse(date,
CultureInfo.CreateSpecificCulture("en-US"), DateTimeStyles.RoundtripKind);
return dt;
}
}
Then created a List with items of this class:
List<TimePeriod> list = new List<TimePeriod>();
Then added your examples of Dates (added all of them, for your need just add selected one's):
list.Add(new TimePeriod() { Id = 1, FromDate = TimePeriod.Parse("7/20/2016"), ToDate = TimePeriod.Parse("7/27/2016") });
list.Add(new TimePeriod() { Id = 2, FromDate = TimePeriod.Parse("6/18/2016"), ToDate = TimePeriod.Parse("7/25/2016") });
list.Add(new TimePeriod() { Id = 3, FromDate = TimePeriod.Parse("7/20/2016"), ToDate = TimePeriod.Parse("7/27/2016") });
list.Add(new TimePeriod() { Id = 4, FromDate = TimePeriod.Parse("6/5/2016"), ToDate = TimePeriod.Parse("6/10/2016") });
Then
foreach (var variable in list)
{
foreach (var VARIABLE in list)
{
if (variable.Id == VARIABLE.Id)
{
continue;
}
if ((variable.FromDate <= VARIABLE.ToDate) && (variable.ToDate >= VARIABLE.FromDate))
{
Console.WriteLine("Problem Hapendes!! {0} <= {1} , {2} >= {3}", variable.FromDate.ToString(), VARIABLE.ToDate.ToString(), VARIABLE.ToDate.ToString(), VARIABLE.FromDate.ToString());
}
}
}

Related

Merging and ordering data using Linq

I have a list of objects as such:
public class ExceptionFolderEntries
{
public int Id { get; set; }
public string Data { get; set; }
public DateTime? StartTime { get; set; }
public DateTime? EndTime { get; set; }
}
I am trying to get the next "Time" whether it be a starttime of endtime so that I can take action.
I know how to order the list using LINQ based on either StartTime OR EndTime but don't know how to merge the data and then sort the new merged list.
Example:
With the data:
"ABC","1/1/2018 01:00", "1/2/2018 13:00"
"MNO","1/1/2018 01:30", "1/1/2018 08:00"
"XYZ","1/1/2018 09:00", "1/2/2018 13:00"
Would result in
ABC 1/1 01:00
MNO 1/1 01:30
MNO 1/1 08:00
XYZ 1/1 09:00
ABC 1/2
13:00
XYZ 1/2 13:00
Any suggestions?
You can try to make two FolderEntries new create collection one is for StartTime, another is for EndTime, then use linq Concat to combine two collections. then do order by
public class FolderEntries {
public string Data { get; set; }
public DateTime? FolderDateTime { get; set; }
}
var result =
(from s1 in list select new FolderEntries(){
Data = s1.Data,
FolderDateTime = s1.StartTime
}).Concat
(from s2 in list select new FolderEntries {
Data = s2.Data,
FolderDateTime = s2.EndTime
}).OrderBy(x=>x.FolderDateTime);
Result
ABC 1/1/2018 1:00:00 AM
MNO 1/1/2018 1:30:00 AM
XYZ 1/1/2018 9:00:00 AM
MNO 1/1/2018 1:08:00 PM
ABC 1/2/2018 1:00:00 PM
XYZ 1/2/2018 1:00:00 PM
c# online
My answer is perhaps too similar to Eriks answer, but one way to do it would be to select a new ExceptionFolderEntries (which should really be renamed ExceptionFolderEntry since it only represents a single item) for every non-null StartTime and EndTime, preserving whichever one we're reading (start or end) and leaving the other field null.
Then you can order that new (sizeable) list by the non-null value: StartTime ?? EndTime.
For example:
var sortedItems =
// First select a new item for all non-null StartTimes
items.Where(i => i.StartTime.HasValue)
.Select(i => new ExceptionFolderEntries {Data = i.Data, StartTime = i.StartTime})
// Then concat with a new item for all non-null EndTimes
.Concat(items
.Where(i => i.EndTime.HasValue)
.Select(i => new ExceptionFolderEntries {Data = i.Data, EndTime = i.EndTime}))
// And finally, order by the non-null field
.OrderBy(i => i.StartTime ?? i.EndTime)
.ToList();
// Now we can write out the data and the non-null field for each item
sortedItems.ForEach(i => Console.WriteLine($"{i.Data} {i.StartTime ?? i.EndTime}"));
Output
In the sample above, items was initialized as:
var items = new List<ExceptionFolderEntries>
{
new ExceptionFolderEntries
{
Data = "ABC",
StartTime = DateTime.Parse("1/1/2018 01:00"),
EndTime = DateTime.Parse("1/2/2018 13:00")
},
new ExceptionFolderEntries
{
Data = "MNO",
StartTime = DateTime.Parse("1/1/2018 01:30"),
EndTime = DateTime.Parse("1/1/2018 08:00")
},
new ExceptionFolderEntries
{
Data = "XYZ",
StartTime = DateTime.Parse("1/1/2018 09:00"),
EndTime = DateTime.Parse("1/2/2018 13:00")
},
};
ExceptionFolderEntries[] entries = [];
entries.Select(e => new DateTime?[] {e.StartTime, e.EndTime).SelectMany(dt => dt).OrderBy(//ordery by logic)
First select out the datetimes into an array (creating you an array of arrays) then use select many to flatten it.
Edit: can also shorten too
ExceptionFolderEntries[] entries = [];
entries.SelectMany(e => new DateTime?[] {e.StartTime, e.EndTime).OrderBy(//ordery by logic)
First off, your class should probably not end in an (s) because it's not a collection, so I'll be using ExceptionFolderEntry in my example.
I'd probably do something like:
class ExceptionFolderEntryMeta
{
public ExceptionFolderEntry ExceptionFolderEntry { get; set; }
public DateTime SortBy { get; set; }
public bool IsStartTime { get; set; }
}
var exceptionFolderEntries = new List<ExceptionFolderEntry>();
var mergeList = exceptionFolderEntries
.Where(efe => efe.StartTime.HasValue)
.Select(efe => new ExceptionFolderEntryMeta
{
ExceptionFolderEntry = efe,
SortBy = efe.StartTime,
IsStartTime = true,
})
.Concat(exceptionFolderEntries
.Where(efe => efe.EndTime.HasValue)
.Select(efe => new ExceptionFolderEntryMeta
{
ExceptionFolderEntry = efe,
SortBy = efe.EndTime,
IsStartTime = false,
}))
.OrderBy(efem => efem.SortBy)
.ToList())
I created the new class to allow correct sorting and to denote if it's a start time or end time (because you'll probably need to know that at some point). I'm also taking into account that you've created those properties as nullable, so if one property is null, it only appears once and if both are null then it never appears.

how to get the month name

using (DataAccessAdapter adapter = new DataAccessAdapter())
{
LinqMetaData meta = new LinqMetaData(adapter);
var datas = (from x in meta.Table
where x.DateCreated >= startDate && x.DateCreated <= endDate && x.ViaTo > 0 && !x.Cancelled
group x by new { month = x.DateCreated.Value.Month } into g
select new
{
MonthNr = g.Key,
//MonthName = ?
TotalMonthAmount = g.Sum(x => x.Amount)
});
.....
}
And startDate & endDate are valid Dates.
I only get the month number, how to get the month name for the DateCreated?
You can get the month name using this function:
CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(monthNumber);
new { month = x.DateCreated.Value.Month.ToString("MMM") }
I think you are asking about Month property. Check this:
using System;
class Program
{
static void Main()
{
DateTime now = DateTime.Now;
//
// Write the month integer and then the three-letter month.
//
Console.WriteLine(now.Month); //outputs 5
Console.WriteLine(now.ToString("MMM")); //outputs May
}
}

Find a range inside a range using LINQ

I've a date list
StartDate EndDate
1-Nov-2011 31-Jan-2012
3-Mar-2012 1-Apr-2012
1-May-2012 31-Dec-2012
1-Jan-2013 1-Dec-2013
Get all the records which falls in this range
1-Jan-2012 31-Dec-2012
The answer would be the first three records from the above list
How could i do it using Linq.
Thanks
This should work:
var rangeStart = new DateTime(2012, 1, 1);
var rangeEnd = new DateTime(2012, 12, 31);
var res = list
.Where(item => (item.StartTime < rangeStart ? rangeStart : item.StartTime) < (item.EndTime < rangeEnd ? item.EndTime : rangeEnd) )
.ToList();
The condition is "the larger of the two left ends needs to be less than the smaller of the two right ends".
I Suggest the following wrapper
public struct DateInterval
{
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public bool HasIntersection(DateInterval secondInterval)
{
return HasIntersection(this.StartDate, this.EndDate,secondInterval.StartDate,secondInterval.EndDate);
}
private bool HasIntersection(DateTime dateStart1, DateTime dateEnd1, DateTime dateStart2, DateTime dateEnd2)
{
if (dateEnd1 < dateStart2) return false;
if (dateEnd2 < dateStart1) return false;
return true;
}
}
usage:
var targetInterval = new DateInterval() {StartDate = new DateTime(2012, 1, 1), EndDate = new DateTime(2012, 1, 1)};
var listOfIntervals =GetIntervals();//retrieve data
var filteredList = listOfIntervals.Where(targetInterval.HasIntersection).ToList();

Need the sequence Order of Quarters of FY2011-12 based on a date given as input

ASP.NET using C#
The following are the Quarters for the financial year 2011-12
April 2011 to June2011 - Q1
July2011 to Sep2011 - Q2
Oct2011 to Dec2011 - Q3
Jan2012 to March 2012 - Q4
EDIT:
If i give a date as input then i need the output interms of the Quarter of that month:
Lets consider a date as input is 02-Jan-2012.
then i need the output as Q4
Lets take another date as input: 31May2012.
For this i need the output as Q1
Please help!!
Here is the function
public string GetQuarter(DateTime date)
{
// we just need to check the month irrespective of the other parts(year, day)
// so we will have all the dates with year part common
DateTime dummyDate = new DateTime(1900, date.Month, date.Day);
if (dummyDate < new DateTime(1900, 7, 1) && dummyDate >= new DateTime(1900, 4, 1))
{
return "Q1";
}
else if (dummyDate < new DateTime(1900, 10, 1) && dummyDate >= new DateTime(1900, 7, 1))
{
return "Q2";
}
else if (dummyDate < new DateTime(1900, 1, 1) && dummyDate >= new DateTime(1900, 10, 1))
{
return "Q3";
}
else
{
return "Q4";
}
}
Hope this could help.
static void Main(string[] args)
{
List<DateRange> range = new List<DateRange>();
//temp filling the data
DateTime start = new DateTime(2011, 4, 1);
range.Add(new DateRange() {From=start,To = start.AddMonths(3).AddMilliseconds(-1),Name="Q1"});
start = range.LastOrDefault().To.AddMilliseconds(1);
range.Add(new DateRange() { From = start, To = start.AddMonths(3).AddMilliseconds(-1), Name = "Q2" });
start = range.LastOrDefault().To.AddMilliseconds(1);
range.Add(new DateRange() { From = start, To = start.AddMonths(3).AddMilliseconds(-1), Name = "Q3" });
start = range.LastOrDefault().To.AddMilliseconds(1);
range.Add(new DateRange() { From = start, To = start.AddMonths(3).AddMilliseconds(-1), Name = "Q4" });
var order = range.OrderByDescending(r => r.IsCurrentQuater(DateTime.Now));
foreach (var itm in order)
Console.WriteLine(itm);
}
}
public class DateRange
{
public string Name { get; set; }
public DateTime From { get; set; }
public DateTime To { get; set; }
public bool IsCurrentQuater(DateTime date)
{
return date >= From && date <= To;
}
public override string ToString()
{
return string.Format("{0} - {1} to {2}", Name, From, To);
}
}
Regards.

How to check all values in List of Class are same or not?

I need help to write a function or logic to find if all values in my List of type class (named Stack) are equal or not. So it will return either true or false.
public class Stack
{
public string Key { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
I have created a class with 3 properties as above.
List<Stack> Stack = new List<Stack>();
Stack WOKey = new Stack() { Key = Resource, StartDate = WorkOrderST, EndDate = WorkOrderED };
Stack.Add(WOKey);
I have created 2 objects with StartDate and EndDate assigned to them through variables.
So I need a logic or function that will return true, if all StartDate have all same values (eg DateTime(2018, 1, 1)) and as case for EndDate (eg DateTime (2018, 1, 30)).
Should I use foreach or is it possible with LINQ? I am new to C# so I am not sure how to implement it.
This is pretty simple with LINQ:
bool allSame = Unavailability.All(s => s.StartDate == new DateTime(2018, 1, 1) &&
s.EndDate == new DateTime(2018, 1, 30));
The .All returns true if every item in the sequence satisfies the condition. See .NET Enumerable.All.
If you want to see if they are all equal, just use the first value...
bool allSame = Unavailability.All(s => s.StartDate == Unavailability[0].StartDate &&
s.EndDate == Unavailability[0].EndDate);
I would use Linq
You can can do the following:
Don't forget to import using System.Linq;
List<Stack> Unavailability = new List<Stack>
{
new Stack{ Key = "A", StartDate = new DateTime(2018,1,1), EndDate = new DateTime(2018,1,30) },
new Stack{ Key = "B", StartDate = new DateTime(2018,1,1), EndDate = new DateTime(2018,1,30)},
new Stack{ Key = "C", StartDate = new DateTime(2018,1,1), EndDate = new DateTime(2018,1,30)}
};
bool allUnique = Unavailability.Select(_ => new { _.StartDate, _.EndDate }).Distinct().Count() <= 0;
What I did here was project the Stack list using the Select to a anonymous type with the objects in it that you want to compare.
Now we can use the Distinct operator to determin all the distinct values.
If the result is less than or equal to 0 that means all the values are unique and if it is something else that means multiple unique values were found.

Categories