I want to filter an array of objects. The goal is to filter the objects between two timespan objects:
TimeSpan tsFrom = TimeSpan.Parse("16:00");
TimeSpan tsTo = TimeSpan.Parse("00:59");
For example I have this object:
TimeSpan dateObject = TimeSpan.Parse("22:05:22");
The problem comes when I try to compare if the dateObject is between tsFrom and tsTo:
if (dateObject > tsFrom && dateObject < tsTo)
{
// do something ....
}
This won't work for cases like that. Do you have any ideas how I can make this work ?
You're wanting to works with times of day. The TimeSpan data type works with time spans (somewhat obvious to say). These are distinct concepts.
Times of day are precisely what motivated the creation of the new TimeOnly type in .NET 6. It has an IsBetween method:
Determines if a time falls within the range provided. Supports both "normal" ranges such as 10:00-12:00, and ranges that span midnight such as 23:00-01:00.
Note that IsBetween use the more sensible convention of inclusive start, exclusive end which means that you'd use 01:00 as the to moment and not accidentally exclude e.g. 00:59:17 from your period
For older versions, I'd suggest you realise that if To is less than From (e.g. it's representing a period that crosses midnight) you should check:
if ((tsTo > tsFrom && dateObject >= tsFrom && dateObject < tsTo) ||
(tsFrom > tsTo && (dateObject < tsTo || dateObject >= tsFrom)))
{
}
Note, again, that this logic is assuming inclusive From and exclusive To (Your original logic treated both ends as exclusive which is rarely correct)
The problem with this one is that you're trying to use the timeSpan method in the wrong way, if I got it right you are trying to check if the dateObject time comes between tsFrom and tsTo, the problem is that you are trying to refer to a different day with the tsTo, something that timespan can not handle.
I fixed it using dateTime to specify at least the day the time is taken from, i suggest changing the code to this
string datevalue = #"15/03/2021 16:00:00";
DateTime start = DateTime.Parse(datevalue);
datevalue = #"16/03/2021 00:59:00";
DateTime end = DateTime.Parse(datevalue);
datevalue = #"15/03/2021 22:05:22";
DateTime obj = DateTime.Parse(datevalue);
if (obj > start && obj < end)
{
//Do something
}
Related
I have two time spans like so:
TimeSpan Starttime : 16:37:00
TimeSpan EndTime: 17:37:00
current time:
DateTime currentDate = DateTime.Now;
TimeSpan now = currentDate.TimeOfDay;
Problem:
I can't figure out how to know if the current time is between starttime and endtime. i want to send mesages only between those two timespans.
How do i do this?
My attempt:
if(startTime.Hours < now.Hours && endTime.Hours > now.Hours)
// do stuff
This does not cover all scenarios since I need it to be exactly between starttime and endtime to the last second but I dont know how to do this.
You can just use:
if (startTime < now && now < endTime)
Note that:
This doesn't check the date; doesn't look like that's an issue here
Depending on why you're doing this, you may want to consider intervals such as "10pm-2am" at which point you effectively want to reverse the logic
In most cases, it's worth making the lower-bound inclusive and the upper-bound exclusive, e.g.
if (startTime <= now && now < endTime)
That's useful because then you can have several intervals where the end of one interval is the start of the next interval, and any one time is in exactly one interval.
To handle the "10pm-2am" example, you'd want something like:
if (interval.StartTime < interval.EndTime)
{
// Normal case, e.g. 8am-2pm
return interval.StartTime <= candidateTime && candidateTime < interval.EndTime;
}
else
{
// Reverse case, e.g. 10pm-2am
return interval.StartTime <= candidateTime || candidateTime < interval.EndTime;
}
I have a DateTime variable called "lastActivated", that is set to DateTime.Now when the Form_Activated event fires. The goal is to make sure something doesn't happen within the first 1 second of a user clicking the screen from another screen.
DateTime? lastActivate = null; //used to determine the last time the screen was focused.
private void Form1_Activated(object sender, EventArgs e)
{
lastActivate = DateTime.Now;
}
The code for determining whether it has been longer than 1 second looks like
TimeSpan oneSec = new TimeSpan(0,0,1);
if (lastActivate == null || (TimeSpan)(lastActivate - DateTime.Now) > oneSec)
{
//stuff
}
The above if statement always, ALWAYS fails. Even when the values are:
lastActivate {11/30/2013 10:23:21 AM} System.DateTime?
now {11/30/2013 10:32:48 AM} System.DateTime
(I made a temp value DateTime now = DateTime.Now so I could paste the value here, since I couldn't directly access DateTime.Now's value)
Does anyone have any suggestions on what I'm doing wrong, and what I should change to get it to accomplish the goal I am after?
Thanks!
You can test the time between two dates by doing this:
var lastActivated = DateTime.Now;
if (DateTime.Now.Subtract(lastActivated).TotalSeconds > 1)
{
// Do whatever you need.
}
DateTime.Subtract(DateTime) returns a TimeSpan of the time difference between the two given dates.
Last active date is less than current time, you should subtract it from current time:
if (!lastActivate.HasValue || (DateTime.Now - lastActivate.Value).TotalSeconds > 1)
{
//stuff
}
Problem : You are subtracting in reverse order, you should subtract the lastActivate Time from the current Time(DateTime.Now).
otherwise you will always get -ve value when you subtract DateTime.Now from lastActivate as lastActivate time is always less than the Current Time (DateTime.Now).
Solution :
This:
(TimeSpan)(lastActivate - DateTime.Now)
Should be :
(TimeSpan)(DateTime.Now - lastActivate)
Complete Code:
TimeSpan oneSec = new TimeSpan(0,0,1);
if (lastActivate == null || (TimeSpan)(DateTime.Now - lastActivate) > oneSec)
{
//stuff
}
I have 2 inputs in an mvc application:
date_from and date_to (this are Date only on view, not DateTime)
when I call a service to get the result filtered by those values I call
Result result = client.GetResults(from = date_from, to = date_to);
the logic in the GetResults do a linq on a EF5 like this:
context.Results.Where(r=> r.date >= date_from && r.date <= date_to);
since the view only have the date part of the DateTime, if I pass
from : 2013-12-01
to : 2013-12-01
The only results i get are those on hour 0:0:0
What I want to do is call the service with the to as the end of the date.
NOTE: I don't want to change service logic because time is used in other places.
NOTE2: I don't want to send date_to.AddDays(1) since it will show me data from another date at 0:0:0 hour.
What's a good solution ? I came up with date_to.AddDays(1).AddMilliseconds(-1) but don't think is a good way to do it.
Thanks.
The simplest approach would be to add a day but change the upper bound to be exclusive:
var lowerBoundInclusive = date_from;
var upperBoundExclusive = date_to.AddDays(1);
context.Results.Where(r=> r.date >= lowerBoundInclusive &&
r.date < upperBoundExclusive);
Half-open intervals like this are nice, as they naturally abut - you can use the exclusive upper bound of one interval as the inclusive lower bound of the next one, etc - and every value will fall into exactly one interval. It also means that each boundary is nice round value, which is easy to read.
EDIT: Okay, with the comments it sounds like we're getting somewhere - the problem is that .NET uses DateTime when you're dealing with both "just dates" and "dates and times". Typically when expressing an interval with dates, you use an inclusive interval ("I'm on holiday Monday to Friday") whereas with dates and times you use an exclusive upper bound ("My first meeting is 3:00-4:00, my second is 4:00-5:00." - at 4:00 your first meeting has finished and the second one has started.)
I would recommend writing two methods, one of which can call the other:
// This is *inclusive* of both bounds
public XYZ GetResultsByDate(DateTime fromDate, DateTime toDate)
{
return GetResultsByDateAndTime(fromDate.Date, toDate.Date.AddDays(1));
}
// This is *exclusive* of the upper bound
public XYZ GetResultsByDateAndTime(DateTime from, DateTime to)
{
var results = context.Results.Where(r=> r.date >= from && r.date < to);
...
}
I have a query with how datetimes are compared/stored in C#. Consider the following code:
var createdDate = DateTime.Now;
using (cr = new LanguageDictionaryRepository(ds)) {
cr.Add(new Sybrin10.Data.DTO.LanguageDictionary() {
Active = true,
CreatedDate = createdDate,
CultureCode = cultureCode,
Data = new System.Text.UTF8Encoding().GetBytes("Test")
});
cr.Save();
var y = cr.FindBy(x => x.CultureCode == cultureCode && x.CreatedDate == createdDate).FirstOrDefault();
Assert.IsNotNull(y);
The Assert.IsNotNull is failing because of the datetime check. I would expect that as the LanguageDictionary instance is created with the variable's value that the two would be equal. This is using Telerik.OpenAccess and MSSQL as a DB layer so I'm assuming the problem comes in there. Can anyone tell me if there is anything I'm missing with this and how to correctly compare these values.
EDIT: The tick values are different but I don't know why as they both come from the same variable which I only assign to once.
Try using DateTime.Equals(x.CreatedDate, createdDate), it might help.
Other than that, proper DateTime comparing is a massively complicated subject with timezones, offsets, utc, local time and whatnot. I wouldn't at all be suprised at a simple == compare between two seemingly identical dates to return false.
If the Ticks value differs on write and read, you're might be facing a DateTimeKind problem, where you're writing a DateTimeKind.Local to the database, but getting back an DateTimeKind.Unspecified.
The other option could be (if the difference is small enough) that the DateTime field in your database is not significant enough to store the same amount of milliseconds as the .net DateTime:
A single tick represents one hundred nanoseconds or one ten-millionth of a second. There are 10,000 ticks in a millisecond.
Depending on your data storage, it might not be as detailed as this. Your DateTime values do not come from the same source, one is read from memory, the other is read from database.
SqlServer stores a datetime in (about) 3-millisecond increments.
datetime values are rounded to increments of .000, .003, or .007 seconds
A roundtrip of a DateTime through the database could thus be off by a few ms.
So you should not test for "exactly equal", but for "close enough"
var y = cr.FindBy(x => x.CultureCode == cultureCode &&
x.CreatedDate >= createdDate.AddMilliseconds(-5) &&
x.CreatedDate <= createdDate.AddMilliseconds(5))
.FirstOrDefault();
Late edit: an extension method
public static class Extensions
{
public static bool IsAboutEqualTo(this DateTime target, DateTime other)
=> Math.Abs((target - other).TotalMilliseconds) <= 4;
}
Usage
var y = cr.FindBy(x => x.CultureCode == cultureCode &&
x.CreatedDate.IsAboutEqualTo(createdDate))
.FirstOrDefault();
Do note that Entity Framework will not be able to translate this into SQL, it will only work in linq-to-objects.
I think it might be better for you to use DateTime.UtcNow when you store the data and then you don't have to worry about daylight saving time issues etc. You can then display it how you want later using the culture you pick.
I would like to write: if the result of the difference of 2 DateTimes is longer than 3 hours then.... stuff in the if statement happens. But I only need properties in seconds or minutes, can I extract just that from the DateTime object?
if(diffResult > DateTime.Hour(3))
{
}
I also want to know if its possible to divide DateTime by periods. Say I want to split my diffResult (which is the difference between 2 DateTimes) into 3 periods or perhaps for every 3 seconds my counter gets one added to it.
For the first part:
You can subtract two DateTimes to get a TimeSpan there you can get the total of various units - for example:
if ( (secondTime - firstTime).TotalMinutes > 180.0) ...
or you could use TimeSpan directly:
if (secondTime - firstTime > TimeSpan.FromHours(3)) ...
for the secondpart you have to do some calculation yourself:
var diff = secondTime - firstTime;
var period = TimeSpan.FromSeconds(diff.TotalSeconds / 3.0);
for (var time = firstTime; time < secondTime; time += period)
{ /* do your stuff */ }
U can compare using the follow code:
DateTime dt = new DateTime();
dt = DateTime.Now;
dt.AddHours(3);
int h = (int)DateTime.Now.Hour;
if (dt.Hour == h )
//Do something
else
//do otherthing
You can do this:
TimeSpan time = new TimeSpan(3, 0, 0);
if (date1.Subtract(date2) > time)
{
//YourCode
}
For the second, this article should be useful:
http://www.blackwasp.co.uk/TimespanMultiplication.aspx
The methods your asking about return integer results. What exactly is your question? DateTime.Hour(3) would not even compile.
I think you are looking for DateTime.Now.AddHours(3.0)
I should be clear, the only reason this answer is this sparse, is because of the invalid code in the author's question which. Since I don't attempt to guess at what people actually want, its up to the author, to clarify what he wants exactly.
All he has to do is subtract two DateTime values and compare it to a TimeSpan