I'm facing an issue which I can't find a proper and elegant solution. I have a List of Videos, which is a class that contains informations about a video. Among those informations there is a startDate,endDate and an cameraId property.
My current database has the following values:
startDate endDate
I want to iterate through those values and when a video is within 5 minutes difference from the last one and has the same cameraId it should be counted as one. But I can't find a proper nor elegant way to accomplish this task.
The output for the videos list shown above should be
1st: 2013:03:01 18:25:26 -> 2013-03-01 18:34:29
2nd: 2013:03:01 18:40:26 -> 2013:03:01 18:59:29
This is the code I have so far:
private void ProcessVideos(List<Video> videos)
{
bool isSameVideo = false;
Video lastVideo = null;
//debugar e ver esquema do ultimo valor do database
DateTime startDate = DateTime.MinValue;
DateTime endDate = DateTime.MinValue;
for (int i = 1; i < videos.Count; i++)
{
TimeSpan timeSpan = new TimeSpan(videos[i].DataInicio.Ticks - videos[i - 1].DataFim.Ticks);
if (timeSpan.Minutes > 0 && timeSpan.Minutes < 5 && videos[i].IdCamera == videos[i - 1].IdCamera)
{
if (!isSameVideo)
{
isSameVideo = true;
startDate = videos[i - 1].DataInicio;
endDate = videos[i].DataFim;
}
else
{
endDate = videos[i].DataFim;
}
}
else
{
if (isSameVideo)
{
i++;
isSameVideo = false;
Debug.WriteLine("inicio: {0} fim: {1}", startDate, endDate);
startDate = DateTime.MinValue;
endDate = DateTime.MinValue;
}
Debug.WriteLine("inicio: {0} fim: {1}", videos[i - 1].DataInicio, videos[i - 1].DataFim);
}
}
if (startDate != DateTime.MinValue)
{
Debug.WriteLine("inicio: {0} fim: {1}", startDate, endDate);
}
}
The main question is: What is a good logic to iterate through those values and output a combinations of values according to the timespan specification?
I created a small example to show you:
My container object:
internal class Container
{
public int Id { get; set; }
public DateTime Start { get; set; }
public DateTime Stop { get; set; }
public override string ToString()
{
return "ID " + Id + ": " + Start + " -> " + Stop;
}
}
My method:
private static IEnumerable<Container> DoMerge(List<Container> elements, TimeSpan maxDiff)
{
var closedContainers = new List<Container>();
var lastContainers = new Dictionary<int, Container>();
foreach (Container container in elements.OrderBy(e => e.Start))
{
//First case, no previous container
if (!lastContainers.ContainsKey(container.Id))
{
lastContainers[container.Id] = container;
}
else if (container.Start - lastContainers[container.Id].Stop > maxDiff)
//We have a container, but not in our windows of 5 minutes
{
closedContainers.Add(lastContainers[container.Id]);
lastContainers[container.Id] = container;
}
else
{
//We have to merge our two containers
lastContainers[container.Id].Stop = container.Stop;
}
}
//We have now to put all "lastContainer" in our final list
foreach (KeyValuePair<int, Container> lastContainer in lastContainers)
{
closedContainers.Add(lastContainer.Value);
}
return closedContainers;
}
And we just have to give our max timespan and list of elements:
private static void Main(string[] args)
{
var elements = new List<Container>
{
new Container {Id = 1, Start = new DateTime(2013, 3, 1, 18, 25, 26), Stop = new DateTime(2013, 3, 1, 18, 27, 29)},
new Container {Id = 1, Start = new DateTime(2013, 3, 1, 18, 30, 26), Stop = new DateTime(2013, 3, 1, 18, 34, 29)},
new Container {Id = 1, Start = new DateTime(2013, 3, 1, 18, 40, 26), Stop = new DateTime(2013, 3, 1, 18, 52, 29)},
new Container {Id = 1, Start = new DateTime(2013, 3, 1, 18, 55, 26), Stop = new DateTime(2013, 3, 1, 18, 59, 29)},
};
foreach (Container container in DoMerge(elements, TimeSpan.FromMinutes(5)))
{
Console.WriteLine(container);
}
Console.ReadLine();
}
This give me your expected results we two objects lefts.
Result with the mentionned data:
Here's a solution. The crux of the method is shown in the ExtractVidTimes method. The rest is just for creating the sample data
[TestFixture]
public class TestyMcTest
{
public class Vid
{
public int CamId;
public DateTime Start;
public DateTime End;
}
[Test]
public void Test()
{
var list = new List<Vid>
{
//=====Combination1=======
new Vid
{
CamId = 1,
Start = new DateTime(2000, 1, 1, 0, 0, 0),
End = new DateTime(2000, 1, 1, 0, 3, 0)
},
new Vid
{
CamId = 1,
Start = new DateTime(2000, 1, 1, 0, 5, 0),
End = new DateTime(2000, 1, 1, 0, 7, 0)
},
//=====Combination2=======
new Vid
{
CamId = 1,
Start = new DateTime(2000, 1, 1, 0, 15, 0),
End = new DateTime(2000, 1, 1, 0, 18, 0)
},
//=====Combination3=======
new Vid
{
CamId = 2,
Start = new DateTime(2000, 1, 1, 0, 0, 0),
End = new DateTime(2000, 1, 1, 0, 3, 0)
},
//=====Combination4=======
new Vid
{
CamId = 2,
Start = new DateTime(2000, 1, 1, 0, 10, 0),
End = new DateTime(2000, 1, 1, 0, 13, 0)
}
};
//here is your list of vids grouped by the cam id
var result = ExtractVidTimes(list);
}
//THE METHOD
private static List<List<Vid>> ExtractVidTimes(List<Vid> list)
{
//Group by cam ID
var vidGroups = list.GroupBy(vid => vid.CamId).ToList();
//extract vids with aggregate times
var result = vidGroups.Select(vids =>
{
var vidTimes = new List<Vid>();
var finalVid = vids.OrderBy(vid=> vid.Start).Aggregate((a, b) =>
{
if (a.End.AddMinutes(5) > b.Start)
{
a.End = b.End;
return a;
}
vidTimes.Add(a);
return b;
});
vidTimes.Add(finalVid);
return vidTimes;
}).ToList();
//return result.SelectMany(x=>x); //if you want a List<vid> return ed instead of a nested list
return result;
}
}
Related
I am wondering if anyone can help me, I have a collection of start times and end times for a work shift of a day. the hours can be spread across the day. I am trying group by the hour in day (like 0, 1, 2...23, 24) and show that hour in intervals of 10 minutes or worked or not worked. So, I would like to get the end result like below:
I want to able distinguish between worked and not on a hourly basis, the input provides the worked but I have calculate the not worked, I created a method for handling if a time falls outside a 10 minute interval it will set to the nearest one. Method called DoRounding:
Example:
9 am => 0 - 10 Worked
10 - 20 Not Worked
20 - 30 Worked
30 - 40 Worked
40 - 50 Worked
50 - 60 Worked
The time that fails out of the period can be be handled like so
private static int DoRounding(DateTime date)
{
if (Enumerable.Range(0, 10).Contains(date.Minute))
return 0;
if (Enumerable.Range(10, 20).Contains(date.Minute))
return 20;
if (Enumerable.Range(20, 30).Contains(date.Minute))
return 30;
if (Enumerable.Range(30, 40).Contains(date.Minute))
return 40;
if (Enumerable.Range(40, 50).Contains(date.Minute))
return 50;
return 60;
}
My method to explode the workblock (I was trying to break down the work period into hours here so I could add the missing parts in another method)
public static IEnumerable<Tuple<int, DateTime>> CalculateIntervals(WorkPeriod workBlock)
{
yield return new Tuple<int, DateTime>(workBlock.StartTime.Hour, workBlock.StartTime);
var dateTime = new DateTime(workBlock.StartTime.Year, workBlock.StartTime.Month, workBlock.StartTime.Day, workBlock.StartTime.Hour, workBlock.StartTime.Minute, 0, workBlock.StartTime.Kind).AddHours(1);
while (dateTime < workBlock.EndTime)
{
yield return new Tuple<int, DateTime>(dateTime.Hour, dateTime);
dateTime = dateTime.AddHours(1);
}
yield return new Tuple<int, DateTime>(workBlock.EndTime.Hour, workBlock.EndTime);
}
My attempt at grouping (I want to group into the time slots here to the hour and the intervals such as 1 pm, 0 - 10 minutes and mark it as worked but if an interval was missing from here add it as not worked)
public static void WorkingHourIntervalStrings(List<WorkPeriod> WorkingHours)
{
var output = new List<Tuple<int, DateTime>>();
foreach (var result in WorkingHours.Select(CalculateIntervals))
output.AddRange(result);
output = output.OrderBy(x => x.Item2).ToList();
var test = output.GroupBy(
p => p.Item1,
p => p.Item2.Minute,
(key, g) => new { Worked = key, Minute = g.ToList() });
}
Class
public class WorkPeriod
{
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
}
Calling
var input = new List<WorkPeriod>
{
new WorkPeriod { StartTime = new DateTime(2020, 5, 25, 9, 40, 56), EndTime = new DateTime(2020, 5, 25, 14, 22, 12) },
new WorkPeriod { StartTime = new DateTime(2020, 5, 25, 9, 50, 56), EndTime = new DateTime(2020, 5, 25, 14, 59, 12) },
new WorkPeriod { StartTime = new DateTime(2020, 5, 25, 13, 40, 56), EndTime = new DateTime(2020, 5, 25, 18, 22, 12) },
new WorkPeriod { StartTime = new DateTime(2020, 5, 25, 19, 40, 56), EndTime = new DateTime(2020, 5, 25, 23, 22, 12) }
};
TimeIntervals.WorkingHourIntervalStrings(input);
Possible output structure:
public class Interval
{
public Interval() => Contents = new List<Contents>();
public int Hour { get; set; }
public List<Contents> Contents { get; set; }
}
public class Contents
{
public bool Worked { get; set; }
public int Start { get; set; }
public int End { get; set; }
}
Based on your above explanations I would do the following:
public class Interval
{
public Interval() => Contents = new List<Contents>();
public int Hour { get; set; }
public List<Contents> Contents { get; set; }
}
public class Contents
{
public bool Worked { get; set; }
public int Start { get; set; }
//public int End { get; set; }
public int End => Start + 10;
}
public class WorkPeriod
{
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
}
Look at the Contents class. The End property is autocalculated from the Start one.
Then I would create the following Calculator class:
public class Calculator
{
public bool[] WorkedIntervals = new bool[24 * 6];
private void SetWork(int Hour, int Min)
{
int pos = Hour * 6 + Min / 10;
WorkedIntervals[pos] = true;
}
private void UpdateIntervals(WorkPeriod period)
{
var cur = period.StartTime;
while (cur < period.EndTime)
{
SetWork(cur.Hour, cur.Minute);
cur = cur.AddMinutes(10);
}
}
private void UpdateIntervals(List<WorkPeriod> periods)
{
foreach (var l in periods)
UpdateIntervals(l);
}
public IEnumerable<Interval> CalcIntervals(List<WorkPeriod> periods)
{
var minTime = (from p in periods
select p.StartTime).Min();
var maxTime = (from p in periods
select p.EndTime).Max();
UpdateIntervals(periods);
for(int h=minTime.Hour; h<=maxTime.Hour; ++h)
{
int pos = h * 6;
var intrvl = new Interval() { Hour = h };
for (int m=0; m<=5; m++)
{
if (WorkedIntervals[pos + m])
intrvl.Contents.Add(new Contents() { Start = m * 10, Worked = true });
else
intrvl.Contents.Add(new Contents() { Start = m * 10, Worked = false });
}
yield return intrvl;
}
}
}
The idea is that you have to flatten all your time intervals to an array of 144 boolean values (24*6) that represents if each of this 10 minute time interval has been worked or not. eg. if the 7th index of the array is true then it means that at Hour 1 (hour 0 is in indexes 0-5) the 10-20 min interval has been worked.
Then, on your main function you do the following.
var input = new List<WorkPeriod>
{
new WorkPeriod { StartTime = new DateTime(2020, 5, 25, 9, 40, 56), EndTime = new DateTime(2020, 5, 25, 14, 22, 12) },
new WorkPeriod { StartTime = new DateTime(2020, 5, 25, 9, 50, 56), EndTime = new DateTime(2020, 5, 25, 14, 59, 12) },
new WorkPeriod { StartTime = new DateTime(2020, 5, 25, 13, 40, 56), EndTime = new DateTime(2020, 5, 25, 18, 22, 12) },
new WorkPeriod { StartTime = new DateTime(2020, 5, 25, 19, 40, 56), EndTime = new DateTime(2020, 5, 25, 23, 22, 12) }
};
Calculator ints = new Calculator();
var res = ints.CalcIntervals(input).ToList();
The res list should contain the hour-intervals from the minimum StartTime to the maximum EndTime with their respected sub-lists.
I'd like to reverse a list of objects with a TimeSpan property, which should maintain it's TimeSpan difference when reversing.
To give an example, consider a route from A to D with the following TimeSpans:
(A 12:00), (B 12:15), (C 12:40), (D 13:40).
Between A and B there is a 15 minute difference, between B and C there is a 25 minute difference and so on. I'd like to reverse this list in an efficient manner, where the result list would look like:
(D: 12:00), (C 13:00), (B 13:25), (A 13:40).
My first idea was creating a list of time differences and using that and the start time to create the new objects with the correct times, however I feel like the solution could be better.
Edit: Added my (working) sample solution. Any feedback is appreciated.
private IList<Activity> ReverseActivities(IList<Activity> activities)
{
IList<TimeSpan> timeDifferences = GetTimeDifferences(activities);
IList<Activity> resultList = new List<Activity>();
TimeSpan timeOfDay = activities.First().TimeOfDay;
for (int i = activities.Count - 1; i >= 0; i--)
{
resultList.Add(new Activity(activities[i].Name, timeOfDay));
timeOfDay = timeOfDay.Add(timeDifferences[i]);
}
return resultList;
}
private IList<TimeSpan> GetTimeDifferences(IList<Activity> activities)
{
IList<TimeSpan> timeDifferences = new List<TimeSpan>();
Activity prev = activities.First();
if (activities.Count > 1)
{
foreach (var curr in activities)
{
timeDifferences.Add(curr.TimeOfDay - prev.TimeOfDay);
prev = curr;
}
}
return timeDifferences;
}
Activity looks as follows:
public class Activity
{
public Activity(string name, TimeSpan timeOfDay)
{
this.Name = name;
this.TimeOfDay = timeOfDay;
}
public string Name { get; }
public TimeSpan TimeOfDay { get; }
}
One trick we can use is to have a single loop that finds the corresponding item from the end of the list based on the current index. We can do this like:
for (int i = 0; i < activities.Count; i++)
var correspondingIndex = activities.Count - i - 1;
Notice that:
When i is 0, correspondingIndex is the last index in the array.
When i is 1, correspondingIndex is the second-to-last index in the array.
When i is activities.Count - 1 (the last index), correspondingIndex is 0
Using this trick, we can get the corresponding time differences at the same time as we populate a new list of Activity objects.
Hopefully this code makes it a little clearer:
public static IList<Activity> ReverseActivities(IList<Activity> activities)
{
// If activities is null or contains less than 2 items, return it
if ((activities?.Count ?? 0) < 2) return activities;
// This will contain the reversed list
var reversed = new List<Activity>();
for (int i = 0; i < activities.Count; i++)
{
// Get the corresponding index from the end of the list
var correspondingIndex = activities.Count - i - 1;
// Get the timespan from the corresponding items from the end of the list
var timeSpan = i == 0
? TimeSpan.Zero
: activities[correspondingIndex + 1].TimeOfDay -
activities[correspondingIndex].TimeOfDay;
// The new TimeOfDay will be the previous item's TimeOfDay plus the TimeSpan above
var timeOfDay = i == 0
? activities[i].TimeOfDay
: reversed[i - 1].TimeOfDay + timeSpan;
reversed.Add(new Activity(activities[correspondingIndex].Name, timeOfDay));
}
return reversed;
}
In use, this would look like:
var original = new List<Activity>
{
new Activity("A", new TimeSpan(0, 12, 0)),
new Activity("B", new TimeSpan(0, 12, 15)),
new Activity("C", new TimeSpan(0, 12, 40)),
new Activity("D", new TimeSpan(0, 13, 40))
};
var reversed = ReverseActivities(original);
Here's the output in the debug window (compare original and reversed):
This is quite simple using a bit of TimeSpan maths.
IList<Activity> input = new List<Activity>()
{
new Activity("A", TimeSpan.Parse("12:00")),
new Activity("B", TimeSpan.Parse("12:15")),
new Activity("C", TimeSpan.Parse("12:40")),
new Activity("D", TimeSpan.Parse("13:40")),
};
TimeSpan min = input.Min(x => x.TimeOfDay);
TimeSpan max = input.Max(x => x.TimeOfDay);
IList<Activity> output =
input
.Select(x => new Activity(
x.Name,
x.TimeOfDay.Subtract(max).Duration().Add(min)))
.OrderBy(x => x.TimeOfDay)
.ToList();
That gives me:
I tested this and it works:
DateTime[] times = { new DateTime(2020, 06, 17, 12, 00, 00),
new DateTime(2020, 06, 17, 12, 15, 00), new DateTime(2020, 06, 17, 12, 40, 00),
new DateTime(2020, 06, 17, 13, 40, 00) };
List<DateTime> newTimes = new List<DateTime>();
newTimes.Add(times[0]);
for (int i = 1; i < times.Length; i++) {
DateTime d = newTimes[i - 1].Add(times[times.Length - i] - times[times.Length - i - 1]);
newTimes.Add(d);
}
Using LinkedList:
static void Main(string[] args)
{
var list = new List<Location>
{
new Location{Name = "A", TimeOffset = DateTimeOffset.MinValue.Add(new TimeSpan(12, 0, 0)) },
new Location{Name = "B", TimeOffset = DateTimeOffset.MinValue.Add(new TimeSpan(12, 15, 0)) },
new Location{Name = "C", TimeOffset = DateTimeOffset.MinValue.Add(new TimeSpan(12, 40, 0)) },
new Location{Name = "D", TimeOffset = DateTimeOffset.MinValue.Add(new TimeSpan(13, 40, 0)) },
};
var route = new LinkedList<Location>(list);
WriteToConsole("Before: ", route);
var reversedRoute = Reverse(route);
Console.WriteLine();
WriteToConsole("After: ", reversedRoute);
Console.WriteLine(); Console.ReadKey();
}
public static LinkedList<Location> Reverse(LinkedList<Location> route)
{
LinkedList<Location> retVal = new LinkedList<Location>();
DateTimeOffset timeOffset = DateTimeOffset.MinValue;
var currentNode = route.Last;
while (currentNode != null)
{
var next = currentNode.Next;
if (next == null)
{
// last node, use the first node offset
timeOffset = DateTimeOffset.MinValue.Add(route.First.Value.TimeOffset - timeOffset);
}
else
{
timeOffset = timeOffset.Add(next.Value.TimeOffset - currentNode.Value.TimeOffset);
}
retVal.AddLast(new Location { Name = currentNode.Value.Name, TimeOffset = timeOffset });
currentNode = currentNode.Previous;
}
return retVal;
}
public static void WriteToConsole(string title, LinkedList<Location> route)
{
Console.Write($"{title}: ");
foreach (var i in route)
{
Console.Write($"\t({i.Name}, {i.TimeOffset.Hour:D2}:{i.TimeOffset.Minute:D2})");
}
}
I have a list of objects in which every object is containing a list itself. how do I get the the JellyFishID field or the Amount field for using an IF argument
(I'm currently using Foreach):`
public static List<Report> DataSorted = new List<Report> {
new Report() { IsGoldUser=true, Date=new DateTime(2016, 3, 12,11, 59, 33), IsBurningWater=true, Type=Type.Shore, ZoneID = 1 ,
ReportDetails =new List<ReportDetail> { new ReportDetail() { Amount = Amount.Few, Jellyfish = new Jellyfish { JellyfishID = 1, Venom = Venom.Strong } } } },
new Report() { IsGoldUser=true, Date=new DateTime(2016, 3, 12, 11, 59, 33), IsBurningWater=true, Type=Type.Shore, ZoneID = 1 ,
ReportDetails =new List<ReportDetail> { new ReportDetail() { Amount = Amount.Few, Jellyfish = new Jellyfish { JellyfishID = 1, Venom = Venom.Strong } } } },
new Report() { IsGoldUser=true, Date=new DateTime(2016, 3, 12, 11, 59, 33), IsBurningWater=true, Type=Type.Shore, ZoneID = 1 ,
ReportDetails =new List<ReportDetail> { new ReportDetail() { Amount = Amount.Few, Jellyfish = new Jellyfish { JellyfishID = 1, Venom = Venom.Strong } } } },
new Report() { IsGoldUser=true, Date=new DateTime(2016, 3, 12, 11, 59, 33), IsBurningWater=true, Type=Type.Shore, ZoneID = 1 ,
ReportDetails =new List<ReportDetail> { new ReportDetail() { Amount = Amount.Few, Jellyfish = new Jellyfish { JellyfishID = 1, Venom = Venom.Strong } } } },
foreach (var item in DataSorted)
{
if (item.ReportDetails....) //???I want here to Make an Argument about The Amount field or the JellyFishID field in the list above....
}
You don't describe exactly what you want to check, but with LINQ to Objects you have a lot of possiblities. At first, you need to reference the correct namespace with
using System.Linq;
at the top of your source code file.
Now, if you want to check if any items of your list contains a jellyfish with a given ID, you can use:
if (item.ReportDetails.Any(t => t.Jellyfish.JellyfishID == 1)) //...
Additionally you can have conditions inside a Where-function to filter your list and search only for jellyfish with a few amount:
if (item.ReportDetails.Where(t => t.Amount == Amount.Few).
Any(t => t.Jellyfish.JellyfishID == 1)) //...
There is a lot of information avaliable about LINQ, a lot of examples are in the MSDN (for example this intro page), but there are alternatives like this one: 101 Linq examples. It even has a tag on StackOverflow.
I have LINQ sql (see below, thanks to Cameron ). I am trying to get a property (ItemCode) from class First without using that in Group by clause.
How do I do that?
Don't use First.ItemCode in group by but still want it in output by First.Begin, First.End order by decending.
public class First
{
public string Account;
public DateTime Begin;
public DateTime End;
public decimal Amount;
public string ItemCode;
}
public class Second
{
public string Account;
public DateTime Begin;
public DateTime End;
public decimal Amount;
}
List<First> firstAccount = new List<First>();
List<Second> secondAccount = new List<Second>();
firstAccount.Add(new First()
{
Account = "1234",
Begin = new DateTime(2014, 5, 13),
End = new DateTime(2014, 6, 12),
Amount = 9999,
ItemCode = "AAA"
});
firstAccount.Add(new First()
{
Account = "1234",
Begin = new DateTime(2014, 6, 13),
End = new DateTime(2014, 7, 7),
Amount = 1000,
ItemCode = "AAA"
});
firstAccount.Add(new First()
{
Account = "1234",
Begin = new DateTime(2014, 6, 13),
End = new DateTime(2014, 7, 14),
Amount = 0,
ItemCode = ""
});
firstAccount.Add(new First()
{
Account = "1234",
Begin = new DateTime(2014, 7, 7),
End = new DateTime(2014, 7, 14),
Amount = 1000,
ItemCode = "BBB"
});
secondAccount.Add(new Second()
{
Account = "1234",
Begin = new DateTime(2014, 5, 13),
End = new DateTime(2014, 6, 12),
Amount = 9999
});
secondAccount.Add(new Second()
{
Account = "1234",
Begin = new DateTime(2014, 6, 13),
End = new DateTime(2014, 7, 14),
Amount = 2000
});
var result = from account in (from first in firstAccount
join second in secondAccount
on first.Account equals second.Account
where
((first.Begin >= second.Begin && first.Begin <= second.Begin) &&
(first.End >= second.Begin && first.End <= second.End))
select new
{
first.Account,
second.Begin,
second.End,
first.Amount,
first.ItemCode
})
group account by new {account.Account, account.Begin, account.End }
into groupedAccounts
select new
{
groupedAccounts.Key.Account,
groupedAccounts.Key.Begin,
groupedAccounts.Key.End,
Sum = groupedAccounts.Sum(a => a.Amount)
};
One way to get the itemcode is to change the last select.
Add this line
Itemcode = String.Join(" ",groupedAccounts.Select(q=> q.ItemCode))
after Sum = groupedAccounts.Sum(a => a.Amount),
It should produce itemcode
foreach (var data in result)
{
Console.WriteLine(data.Account + " " + data.Itemcode);
}
Output
1234 AAA
1234 AAA
I have a List with dates to show it in a grid and I would like add one hour to range2:
private void grid_loaded(object sender, RoutedEventArgs e)
{
var data = new List<EntityViewModel>
{
new EntityViewModel { aDay = new DateTime(1980, 1, 1, 12, 0, 12) },
new EntityViewModel { aDay = new DateTime(1983, 1, 1, 12, 23, 12) },
new EntityViewModel { aDay = new DateTime(1985, 6, 14, 12, 0, 12) },
new EntityViewModel { aDay = new DateTime(1990, 7, 3, 12, 23, 12) },
new EntityViewModel { aDay = new DateTime(1995, 8, 1, 4, 23, 12) },
new EntityViewModel { aDay = new DateTime(1996, 1, 1, 12, 0, 12) },
new EntityViewModel { aDay = new DateTime(2000, 1, 1, 12, 0, 12) },
new EntityViewModel { aDay = DateTime.Now }
};
var range = data.Where(i => i.aDay.Year >= 1983 && i.aDay.Year <= 1996).ToList();
var range2 = range.Where(i => i.aDay.Date.IsDaylightSavingTime() == true).ToList();
}
I tried this:
var range3 = range.Where(i => i.aDay.Date.IsDaylightSavingTime() == true).ToList();
range3.ForEach(i => i.aDay.AddHours(1));
this:
foreach (var item in range2.Where(x => x.aDay != null))
{
item.aDay.AddHours(1);
}
and this:
var range5 = range2.Where(i => i.aDay != null).Select(i => { i.aDay.AddHours(1); return i; }).ToList();
But it doesn't do anything, are always the same hour.
AddHours does NOT alter the initial date, but return a new one.
You need to select these dates:
var range5 = range2.Where(i => i.aDay != null).Select(i => i.aDay.AddHours(1));
To get the altered dates or
range3.ForEach(i => i.aDay = i.aDay.AddHours(1));
To alter the dates of the items in the list.
DateTime is a structure, so you have to do:
var date = DateTime.Now;
date = date.AddHours(1);
in your case:
range3.ForEach(i => i.aDay = i.aDay.AddHours(1));
AddHours returns a new DateTime, it does not change the current instance.
http://msdn.microsoft.com/en-us/library/system.datetime.addhours.aspx
for (int i = 0; i < range2.Count; ++i) {
range2[i].aDay = range2[i].aDay.AddHours(1);
}