I'm trying to create a downtown that will display times from 00:00 to 24:59 at a selected number of intervals (and this could change from 5 minutes to 10 minutes etc
so for example a list of
00:10
00:20
00:30
or could be
00:15
00:30
I'm using the following which works, but only for a selected number of iterations (33):
List<string> query = Enumerable
.Range(0, 33)
.Select(i => DateTime.Today
.AddHours(0)
.AddMinutes(i * (double)IntervalParameter)
.ToString())
.ToList();
*IntervalParameter = 10 for the example above.
I'm looking to adapt this so it runs the full 24 hours time frame. Just looking for the most efficient way to do this.
Why not compute the number of items?
int IntervalParameter = 5;
// .Range(0, 1440 / IntervalParameter) - see Zohar Peled's comment -
// is brief, but less readable
List<string> query = Enumerable
.Range(0, (int) (new TimeSpan(24, 0, 0).TotalMinutes / IntervalParameter))
.Select(i => DateTime.Today
.AddMinutes(i * (double)IntervalParameter) // AddHours is redundant
.ToString("HH:mm")) // Let's provide HH:mm format
.ToList();
Something like this?
public static IEnumerable<TimeSpan> Intervals(TimeSpan inclusiveStart, TimeSpan exclusiveEnd, TimeSpan increment)
{
for (var time = inclusiveStart; time < exclusiveEnd; time += increment)
yield return time;
}
Example usage:
foreach (var time in Intervals(TimeSpan.Zero, TimeSpan.FromDays(1), TimeSpan.FromMinutes(15)))
{
Console.WriteLine(time);
}
Related
I have a C# list of a model.
List<FooModel> myModel;
public class FooModel {
public int CreationTimeInMs;
}
My list is already sorted by CreationTimeInMs (DSC) and I would like to get a part of that list up to last 30 days.
For example:
If I have 1000 items in the list and the CreationTimeInMs goes back 2 months, I would like to a list of only the last 30 days.
What's the approach ?
30 Days means 1000 * 60 * 60 * 24 * 30 = 2.592.000.000ms
Use this in a simple Lambda expression to filter out the newest Models. Note that you need to know your "actual time".
UInt64 ActualTime = 12345; //Define the actual time in ms here
IEnumerable <myModel> NewestModels = myModel.Where(x => ActualTime - (Convert.ToUInt64(x.CreationTimeInMs)) > 2592000000);
Now your NewestModels contains all the Models you need.
A solution is the following:
long nowTimestamp = <compute now timestamp>;
long delta = 30 * 24 * 60 * 60 * 1000; // ms
var result = myModel.Where(item => nowTimestamp - item.CreationTimeInMs > delta);
However, this approach has a linear complexity (O(list_length)) and does not use the fact that it is sorted.
If the list is sorted descending you can just construct another list, as long as current timestamp is new enough:
var recentList = new List<FooModel>();
foreach (var item in myModel)
{
if (nowTimestamp - item.CreationTimeInMs > delta)
break;
recentList.Add(item);
}
This is the fastest approach, but requires the list to be ordered in a descending manner.
If the list comes in a ascending order, you must first find the item that is the last to be included. As already mentioned, the fastest way is to use a binary search approach, as indicated in this question.
Using provided index, you can get all subsequent elements:
int indexOfFirstElement = myModel.BinarySearchForMatch(item => item.CreationTimeInMs > nowTimestamp - delta);
var recentList = new List<FooModel>();
for (int i = indexOfFirstElement; i < myModel.Count; i ++)
{
recentList.Add(myModel[i]);
}
Binary search takes O(log(list_size)) and list construction is O(result_size).
I have an array of timespans that are in 15 minute intervals, e.g.:
00:00:00,
00:15:00,
00:30:00,
00:45:00,
01:00:00
etc.
I want to loop through and only show those which are of a 30 minute interval. I've tried using the .compare but this doesn't get exactly what I need.
For example:
var interval = TimeSpan.FromMinutes(30);
foreach(var t in MyArray)
{
if(TimeSpan.Compare(inteval, t.Time) == 0)
Do something
}
}
This technically works, but would only match 00:30:00. I can add the interval to the loop and use something like:
var interval = new TimeSpan(t.Hour, 30, 0)
but that only gets 00:30:00, 01:30:00.
Is there as way to make the hour like a wildcard and get every 30 min?
The output I'd want is:
00:00:00
00:30:00
01:00:00
01:30:00
etc.
What you want is a modulo operation, but since TimeSpans themselves don't define that, use TotalMinutes (or another property) to get a plain integer and then use modulo:
if ((int)t.TotalMinutes % 30 == 0)
You can also filter your array for every second item .. then use the new array and print is sequentially:
var newArray = MyArray.Where((t, index) => index % 2 == 0).ToArray();
This gives you every second item in the list.
I have a database that has the following records in a DateTime field:
2012-04-13 08:31:00.000
2012-04-12 07:53:00.000
2012-04-11 07:59:00.000
2012-04-10 08:16:00.000
2012-04-09 15:11:00.000
2012-04-08 08:28:00.000
2012-04-06 08:26:00.000
I want to run a linq to sql query to get the average time from the records above. I tried the following:
(From o In MYDATA Select o.SleepTo).Average()
Since "SleepTo" is a datetime field I get an error on Average(). If I was trying to get the average of say an integer, the above linq query works.
What do I need to do to get it to work for datetimes?
Internally, every DateTime is really stored as a number of ticks. The Ticks property of a DateTime is defined as the "number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001." (See http://msdn.microsoft.com/en-us/library/system.datetime.ticks.aspx)
You can convert the DateTimes to ticks, then average, then convert back to a datetime.
var averageTicks = (long) dates.Select(d => d.Ticks).Average();
var averageDate = new DateTime(averageTicks);
Using your data structures and formatting, it would look like this:
var averageTicks = (long)(from o in MYDATA select o.SleepTo.Ticks).Average();
var averageDate = new DateTime(averageTicks);
If you want to get the average time of each SleepTo value (ignoring the Date component), you can get the ticks of just the time:
var averageTicks = (long)(from o in MYDATA select o.SleepTo.TimeOfDay.Ticks).Average();
var averageTime = new TimeSpan(averageTicks);
Here are a couple extensions methods that can help with this... There is a core problem where if you have a lot of DateTimes in a list the LINQ average of a the ticks (long vars) will overflow.
public static long Average(this IEnumerable<long> longs)
{
long count = longs.Count();
long mean = 0;
foreach (var val in longs)
{
mean += val / count;
}
return mean;
}
public static DateTime Average(this IEnumerable<DateTime> dates)
{
return new DateTime(dates.Select(x => x.Ticks).Average());
}
The database LINQ provider doesn't seem to understand how to do averages on absolute dates. Which, if you think about it, makes sense (average is a sum divided by a count - what is the sum?).
So, if you're not able to run the following:
(From o In MYDATA Select o.SleepTo).Sum()
Then you won't be able to do .Average() also.
Since what you want is actually the average time of SleepTo, you need to get just the time component of the date as a TimeSpan (time minus midnight perhaps) and average that. Do you by any chance have SleepFrom?
In the meantime, you might find this post enlightening: LINQ Average TimeSpan?
I have a collection of class with a DateTime Property, I would like to get sum of Minutes and Seconds. Is there any easy way to do this using LINQ without manually summing the minutes and seconds?
I suppose you mean TimeSpan instead of DateTime? You can't add DateTime's...
To sum TimeSpan's:
list.Sum(span => span.TotalSeconds) ==> total seconds
TimeSpan.FromSeconds(...) ==> Convert total seconds back to time span
You can then use properties in TimeSpan to reformat it back to hours, minutes, seconds etc.
+1 for Stephen's answers.
Just for fun... if you really do want "to get sum of Minutes and Seconds" then:
class MyClass
{
public DateTime DateTimeMember {get;set;}
// other stuff
}
var myObjects = new List<MyClass>();
// fill list...
// 3 possible things you might be interested in
var myMinuteSum = myObjects.Sum(x => x.DateTimeMember.Minute);
var mySecondSum = myObjects.Sum(x => x.DateTimeMember.Second);
var myOddTotalOfMinutesAndSecondsInSeconds = myObjects.Sum(x => x.DateTimeMember.Minute * 60 + x.DateTimeMember.Second);
So, here's the scenario. I have a file with a created time, and I want to choose a time from a list of times that that file's created time is closest or equal too...what would be the best way to accomplish this?
var closestTime = listOfTimes.OrderBy(t => Math.Abs((t - fileCreateTime).Ticks))
.First();
If you don't want the performance overhead of the OrderBy call then you could use something like the MinBy extension method from MoreLINQ instead:
var closestTime = listOfTimes.MinBy(t => Math.Abs((t - fileCreateTime).Ticks));
Something like this:
DateTime fileDate, closestDate;
ArrayList theDates;
long min = long.MaxValue;
foreach (DateTime date in theDates)
if (Math.Abs(date.Ticks - fileDate.Ticks) < min)
{
min = Math.Abs(date.Ticks - fileDate.Ticks);
closestDate = date;
}
The accepted answer is completely wrong. What you want is something like this:
DateTime fileDate, closestDate;
List<DateTime> theDates;
fileDate = DateTime.Today; //set to the file date
theDates = new List<DateTime>(); //load the date list, obviously
long min = Math.Abs(fileDate.Ticks - theDates[0].Ticks);
long diff;
foreach (DateTime date in theDates)
{
diff = Math.Abs(fileDate.Ticks - date.Ticks);
if (diff < min)
{
min = diff;
closestDate = date;
}
}
var closestTime = (from t in listOfTimes
orderby (t - fileInfo.CreationTime).Duration()
select t).First();
How often will you be doing this with the same list of times? If you're only doing it once, the fastest way is probably to just scan through the list and keep track of the closest time you've seen yet. When/if you encounter a time that's closer, replace the "closest" with that closer time.
If you're doing it very often, you'd probably want to sort the list, then use a binary search.
get the difference of your file creatime and every time in your list and sort the absolute value of each time difference. the first one should be the answer you are looking for.
Use the minimum absolute time difference between the file time and the time in the list. You might get 2 entries being the same, and then you would need a different method to differ between these.
Not an answer, but a question regarding the various LINQ solutions proposed above. How efficient is LINQ? I have not written any "real" programs with LINQ yet, so I'm not sure on the performance.
In this example, the "listOfTimes" collection implies that we have already iterated over some file system based objects to gather the times. Would it have been more efficient to do the analysis during the iteration instead of later in LINQ? I recognize that these solutions may be more "elegant" or nicely abstract the "collection as database" idea, but I tend to choose efficiency (must be readable though) over elagance in my programming. Just wondering if the cost of LINQ might outweigh the elegance here?
var creationTimes = new [] {DateTime.Now.AddDays(-1), DateTime.Now.AddDays(-2)};
FileInfo fi = new FileInfo("C:/test.xml");
var closestTime = creationTimes
.OrderBy(c => Math.Abs(c.Subtract(fi.CreationTime).Days))
.First();
var min = listoftimes.Select(
x => new { diff = Math.Abs((x - timeoffile).Ticks), time = x}).
OrderBy(x => x.diff).
First().time;
Note: Assumes at least 1 entry in listoftimes.
I thought I would update this post to include a real world scenario. I wanted this sort of function as I have a blog showing news of the latest movie screenings.
However I don't want to list screening in the past (ie screening date past the current date) and as I wanted to show a record I needed some sort of ID passed to pick up the record.
I have left if simple so that you can follow the process and no doubt make it more efficient with LINQ et al.
First the model
public class LatestScreeeningsModel
{
public int Id { get; set; }
public DateTime Date { get; set; }
}
Then the code block you can call from your controller
private static LatestScreeeningsModel GetLatestScreening(IPublishedContent currentNode)
{
LatestScreeeningsModel latestScreening = new LatestScreeeningsModel();
DateTime fileDate;
// get a list of screenings that have not shown yet
var screenings = currentNode.AncestorsOrSelf("siteLanguage")
.FirstOrDefault().Descendants("screening")
.Select(x => new LatestScreeeningsModel() { Id = x.Id, Date = x.GetPropertyValue<DateTime>("date") })
.Where(x => x.Date > DateTime.Now).ToList();
fileDate = DateTime.Today;
long min = Math.Abs(fileDate.Ticks - screenings[0].Date.Ticks);
long diff;
foreach (var comingDate in screenings)
{
diff = Math.Abs(fileDate.Ticks - comingDate.Date.Ticks);
if (diff <= min)
{
min = diff;
latestScreening = comingDate;
}
}
return latestScreening;
}
I am using Umbraco to get the date items but it would work with any custom model, List et al.
Hope it helps
This is a generalized solution to the question, "Find the closest time from a list of times". This solution finds the closest time before and after a given search time.
//For finding the closest time in a list using a given search time...
var listOfTimes = new List<DateTime>();
listOfTimes.Add(DateTime.Parse("1/1/2000"));
listOfTimes.Add(DateTime.Parse("1/2/2000"));
listOfTimes.Add(DateTime.Parse("1/3/2000"));
listOfTimes.Add(DateTime.Parse("1/4/2000"));
listOfTimes.Add(DateTime.Parse("1/5/2000"));
var searchTime = DateTime.Parse("1/3/2000");
var closestBefore = listOfTimes.LastOrDefault(t => t < searchTime);
var closestAfter = listOfTimes.FirstOrDefault(t => t > searchTime);
Console.WriteLine(closestBefore);
Console.WriteLine(closestAfter);
/*
searchTime: 1/3/2000
before: 1/2/2000 12:00:00 AM
after: 1/4/2000 12:00:00 AM
searchTime: 1/1/1900 (edge case)
before: 1/1/0001 12:00:00 AM (DateTime.MinValue)
after: 1/1/2000 12:00:00 AM
searchTime: 1/1/2001 (edge case)
before: 1/5/2000 12:00:00 AM
after: 1/1/0001 12:00:00 AM (DateTime.MinValue)
*/