Everything works with the exception if I pass in "15 minutes". I receive no errors, it's just that my where clause isn't working 100%. This is b/c I pass in time in 15 minute intervals.
Example:
Object 1 has a time of 00:20 (12:20 am) (24hr format)
Object 2 has a time of 02:15 (02:15 am) (24hr format)
The parsedTime param is a javascript 24hr format time - in this example is comes in as "00:15".
The problem is when I subtract the -30 minutes from the parsedTime, it puts it at 23:45, and therefore never gets the "00:20".
LINQ query
DateTime parsedTime = DateTime.ParseExact(time, "HH:mm", CultureInfo.InvariantCulture);
var activities = objects
.Where(x => (x.GetValue<DateTime>("startTime").TimeOfDay
>= parsedTime.AddMinutes(-30).TimeOfDay
&& x.GetValue<DateTime>("startTime").TimeOfDay
<= parsedTime.AddMinutes(30).TimeOfDay))
.ToList();
You just want to see if they're within 30 minutes of each other, right? Try using actual timespans
DateTime startTime;
DateTime parsedTime;
TimeSpan difference = startTime - parsedTime;
return difference.TotalMinutes < 30 && difference.TotalMinutes > -30;
It sounds like you also need to handle time ranges that could span across midnight, as in the 30 minutes that exists between "23:45" and "00:15". Here's how you can do that:
public static TimeSpan GetTimeDifference(string startTimeOfDay, string endTimeOfDay)
{
DateTime startDateTime = DateTime.ParseExact(startTimeOfDay, "HH:mm",
CultureInfo.InvariantCulture, DateTimeStyles.NoCurrentDateDefault);
DateTime endDateTime = DateTime.ParseExact(endTimeOfDay, "HH:mm",
CultureInfo.InvariantCulture, DateTimeStyles.NoCurrentDateDefault);
if (endDateTime >= startDateTime)
{
// values do not cross over midnight
return endDateTime - startDateTime;
}
else
{
// values cross over midnight
return endDateTime - startDateTime + TimeSpan.FromHours(24);
}
}
Or if you prefer something smaller:
public static int GetMinutesDifference(string startTimeOfDay, string endTimeOfDay)
{
DateTime startDateTime = DateTime.ParseExact(startTimeOfDay, "HH:mm",
CultureInfo.InvariantCulture, DateTimeStyles.NoCurrentDateDefault);
DateTime endDateTime = DateTime.ParseExact(endTimeOfDay, "HH:mm",
CultureInfo.InvariantCulture, DateTimeStyles.NoCurrentDateDefault);
return (((int)(endDateTime - startDateTime).TotalMinutes + 1440) % 1440);
}
Related
I am getting dates from the database and for each date I want to change the time forward starting from the DateTime that was obtained from the database until I get to a given Fixed Time (Y). However, (Y) might be in the next day.
For example if the date from the database is [7/6/2017 5:00:00 AM] and the given Fixed Time is 10:00 PM then I want to get [7/6/2017 10:00:00 PM].
However if the fixed time is 02:00 AM then I want to get [7/7/2017 02:00:00 AM] (notice that the date has increased by one)
Note: The code is running, but I modified the code to make it shorter and make more sense. Thus, there might be syntax or spelling mistakes.
My first solution was something like this:
private DateTime setTimeForeward(DateTime date) {
DateTime today = DateTime.ParseExact(FixedTime, "hh:mm tt", CultureInfo.InvariantCulture);
TimeSpan difference = today.TimeOfDay - date.TimeOfDay;
return date + difference;
}
That didn't work as expected when the fixed time is 02:00 AM. The difference becomes negative( it doesn't go around the clock) and the date will be [7/6/2017 02:00:00 AM].
I ended up with the following code
private DateTime setTimeForeward(DateTime date) {
DateTime today = DateTime.ParseExact(FixedTime "hh:mm tt", CultureInfo.InvariantCulture);
TimeSpan difference = today.TimeOfDay - date.TimeOfDay;
if (difference.Hours < 0) {
difference += new TimeSpan(24, 0, 0);
}
return date + difference;
}
I am not sure if my function is logically correct and I feel like I am overthinking it. Also,I am not sure if there's a better way or a built in function that does what I want for me. Basically, I am looking for a correct and an elegant solution.
Thank you very much in advanced.
In this method, I'm using DateTime fixedTime to represent a time. I don't really care about it's Day, Month, and Year values.
static DateTime GetClosingTime(DateTime fixedTime, DateTime dbTime)
{
var cutoff = new DateTime(dbTime.Year, dbTime.Month, dbTime.Day, fixedTime.Hour, fixedTime.Minute, fixedTime.Second);
if (dbTime < cutoff)
return cutoff;
else
{
cutoff = cutoff.AddDays(1);
return cutoff;
}
}
Here's calling it with your provided example input.
var FixedTime10PM = new DateTime(1, 1, 1, 22, 0, 0);
var FixedTime02AM = new DateTime(1, 1, 1, 2, 0, 0);
var dbTime = new DateTime(2018, 6, 20, 5, 0, 0);
var dt1 = GetClosingTime(FixedTime10PM, dbTime);
var dt2 = GetClosingTime(FixedTime02AM, dbTime);
Console.WriteLine(dt1.ToLongDateString() + " " + dt1.ToLongTimeString());
Console.WriteLine(dt2.ToLongDateString() + " " + dt2.ToLongTimeString());
And here's my output:
EDIT:
Simplified method based on suggestions in comments:
static DateTime GetClosingTime(DateTime fixedTime, DateTime dbTime)
{
var cutoff = new DateTime(dbTime.Year, dbTime.Month, dbTime.Day, fixedTime.Hour, fixedTime.Minute, fixedTime.Second);
return dbTime < cutoff ? cutoff : cutoff.AddDays(1);
}
Your logic is almost right but you shouldn't be checking for difference.Hours because there might be a difference in minutes (or even seconds if you changed the format later).
I adjusted your function and changed some variable names to make them easier to follow:
private DateTime SetTimeForward(DateTime originalDate)
{
TimeSpan newTime = DateTime.ParseExact(FixedTime,
"hh:mm tt",
CultureInfo.InvariantCulture).TimeOfDay;
TimeSpan diff = newTime - originalDate.TimeOfDay;
if (diff.Ticks < 0)
diff = diff.Add(new TimeSpan(24, 0, 0));
return originalDate.Add(diff);
}
Some remarks:
If your FixedTime is really fixed, you might want to store it directly as a TimeSpan so you don't have to parse it every time.
If you parse the FixedTime because it's changeable, you might pass it as a second argument instead:
private DateTime SetTimeForward(DateTime originalDate, string fixedTime)
Or:
private DateTime SetTimeForward(DateTime originalDate, TimeSpan newTime)
The current implementation does not change the date value if the newTime is equal to originalDate.TimeOfDay. I.E., If the originalDate is 7/6/2017 2:00 AM and the FixedTime/newTime is 02:00 AM, the returned date will be equal to the originalDate. If that's not your desired behavior, you might change diff.Ticks < 0 to diff.Ticks <= 0.
Slightly different approach:
private DateTime setTimeForeward(DateTime date)
{
var targetTimeOfDay = TimeSpan.ParseExact(FixedTime, "hh:mm tt", CultureInfo.InvariantCulture);
if (targetTimeOfDay < date.TimeOfDay)
{
date = date.AddDays(1);
}
return date.Date + targetTimeOfDay;
}
I'm getting target time as TimeSpan from the beginning instead of creating DateTime and getting TimeOfDay (which is TimeSpan).
Then I check if the target time of day is lower than time to be modified and if it is I add one day.
I use date.Date + targetTimeOfDay as return value as date.Date will return date with time set to 00:00 and adding target time to it will already set the target hour without calculating the difference.
when my starttime = "19:00" PM then my endtime ="01:30" AM
the answer is negative , how can i prevent negative result in time?
string startime = record.TimeStart;
string endtime = record.TimeFinish;
TimeSpan span = DateTime.Parse(endtime).Subtract(DateTime.Parse(startime));
string hours_spent = string.Format(
"{0:D2}:{1:D2}:{2:D2}",
span.Hours, span.Minutes, span.Seconds);
You are crossing midnight, so the actual comparison is (using today's date as an example):
[2015-10-12 01:30] - [2015-10-12 19:00]
which is -17 hrs and 30 minutes. If you want to convert that to a positive time then either add a date component or add 24 hours to the time span:
if(span.Hours < 0)
span = span.AddDays(1);
Add one day to endtime if it (or more precisely, its time component) is earlier than starttime's. Something like this:
var startDateTime = DateTime.Parse(starttime).Time;
var endDateTime = DateTime.Parse(endtime).Time;
if (endDateTime < startDateTime)
{
endDateTime += TimeSpan.FromDays(1);
}
TimeSpan timeSpent = endDateTime - startDateTime;
Is there a rapid and simple way to obtain a List<DateTime> given start and end dates?
I obviously know that I can achieve this by a loop, but I'm wondering if there is a smarter method using Linq or some other utility.
NOTE I need to get a DateTime instance for every single day between two given dates.
Iterator blocks are great for this.
I see no reason not to use a for loop here for this. You need to perform some operator for each date, given that you have that many outputs, no method will have any better asymptotic complexity.
public static IEnumerable<DateTime> GetDates(DateTime startDate, DateTime endDate
, TimeSpan interval)
{
for (DateTime date = startDate; date < endDate; date.Add(interval))
{
yield return date;
}
}
You can add an overload for a fixed interval as well:
public static IEnumerable<DateTime> GetDays(DateTime startDate, DateTime endDate)
{
return GetDates(startDate, endDate, TimeSpan.FromDays(1));
}
You can do like this to get a list from startDate to endDate:
List<DateTime> dates =
Enumerable.Range(0, (int)((endDate - startDate).TotalDays) + 1)
.Select(n => startDate.AddDays(n))
.ToList();
Assuming that you want daily granularity, and include the start and end dates:
var start = new DateTime(2012, 01, 01);
var end = new DateTime(2013, 01, 01);
var daysInBetween = Enumerable.Range(0, (int) (end - start).TotalDays + 1)
.Select(value => start.AddDays(value));
Lazy evaluated query might look like:
//inclusive start and inclusive end
public IEnumerable<DateTime> DateSequence(DateTime start, TimeSpan interval, DateTime end)
{
DateTime current = start;
while(current <= end)
{
yield return current;
current = current.Add(interval);
}
}
Now you can simply use it like following. To get every day set interval to TimeSpan.FromDays(1)
var start = DateTime.Now;
var end = DateTime.Now.AddDays(7);
var interval = TimeSpan.FromDays(1);
var sequence = DateSequence(start, interval, end);
//LinqPad specific call
sequence.Dump();
prints:
1/14/2013 5:34:57 PM
1/15/2013 5:34:57 PM
1/16/2013 5:34:57 PM
1/17/2013 5:34:57 PM
1/18/2013 5:34:57 PM
1/19/2013 5:34:57 PM
1/20/2013 5:34:57 PM
I am trying to calculate the time difference between 2 time and put the result into a text block.
For example,
Start time: 9:45 AM
End start: 5:15 PM
How can i calulate the time difference between it?
DateTime dt1 = DateTime.ParseExact(DateTime.Now.ToShortTimeString(), "hh:mm tt", new DateTimeFormatInfo());
DateTime dt2 = DateTime.ParseExact(timePicker1.ValueString, "hh:mm tt", new DateTimeFormatInfo());
TimeSpan ts1 = dt2.Subtract(dt1);
For time "11:12 PM" you should use format "h:mm tt". So, you parse two time strings and make Subtract or just (dateTime1 - dateTime2).
try:
DateTime dt1 = DateTime.ParseExact("22:22:22", "HH:mm:ss", new DateTimeFormatInfo());
DateTime dt2 = DateTime.ParseExact("11:11:11", "HH:mm:ss", new DateTimeFormatInfo());
TimeSpan ts1 = dt1.Subtract(dt2);
protected void Page_Load(object sender, EventArgs e)
{
// Declare and get DateTime values
DateTime StartDate = System.DateTime.Now;
DateTime EndDate = System.DateTime.UtcNow;
// Find time difference between two dates
TimeSpan TimeDifference = StartDate - EndDate;
// Write difference in hours and minutes
Response.Write("Time difference between server time and Coordinated Universal Time (UTC) is " +
TimeDifference.Hours.ToString() + " hours ");
if (TimeDifference.Minutes != 0)
Response.Write(" and " + TimeDifference.Minutes.ToString() + " minutes.");
}
or try
/* Read the initial time. */
DateTime startTime = DateTime.Now;
Console.WriteLine(startTime);
/* Do something that takes up some time. For example sleep for 1.7 seconds. */
Thread.Sleep(1700);
/* Read the end time. */
DateTime stopTime = DateTime.Now;
Console.WriteLine(stopTime);
/* Compute the duration between the initial and the end time.
* Print out the number of elapsed hours, minutes, seconds and milliseconds. */
TimeSpan duration = stopTime - startTime;
Console.WriteLine("hours:" + duration.Hours);
Console.WriteLine("minutes:" + duration.Minutes);
Console.WriteLine("seconds:" + duration.Seconds);
Console.WriteLine("milliseconds:" + duration.Milliseconds);
The method suggested by O.D. is what I use in my app that uses a time difference. I then use the method ng_ducnghia suggests to separate units of time (hours, min, sec - I don't need millisec for my purpose).
What's the preferred approach to compare a complete DateTime instance with an hour, minute, and second which represents an actual time of day, with the ability to operate over those triplets (eg add hours, minutes seconds..)?
My current approach is something like
DateTime startHour = new DateTime(1900,1,1,12,25,43);
DateTime endHour = new DateTime(1900,1,1,13,45,32);
// I need to, say, know if a complete DateTime instance
// is later than startHour plus 15 minutes
DateTime now = DateTime.Now();
startHour = startHour.addMinutes(15);
if (now.CompareTo(new DateTime(now.Year, now.Month, now.Day, startHour.Hour,
startHour.Minute, startHour.Second)) > 0)
{
//I can do something now
}
This is very cumbersome and even failure prone. TimeSpans are not a solution as far as I can see, because they represent spans and aren't bound by the 24 hours limit (a TimeSpan of 56 hours 34 minutes is valid.)
What's the preferred approach for this type of calculations?
It's not at all clear what you mean by "is greater than startHour"... but taking
TimeSpan startHour = new TimeSpan(12, 25, 43);
if (endHour.TimeOfDay > startHour)
{
...
}
... works pretty simply.
By all means add argument checking to make sure that you don't specify a value for startHour which is < 0 or > 23 hours, but that's all pretty easy.
.NET's date and time API is quite primitive (even in 3.5) compared with, say, Joda Time - but in this particular case I think it's not too bad.
A little hint - .NET supports arithmetic operations on DateTime objects, and returns a TimeSpan object. Thus, you can do the following:
DateTime fromDate = ....
DateTime toDate = ....
TimeSpan diff = toDate - fromDate;
and you can expand this to:
DateTime fromDate = DateTime.Now;
DateTime toDate = DateTime.Now.addMinutes(x);
if ((toDate - fromDate).TotalMinutes > 15) {
...
}
You should use TimeSpan for startHour and endHour.
When comparing with now, you should "convert" them to a full DateTime or get the Time with DateTime.TimeOfDay as mentioned by Jon Skeet.
TimeSpan startHour = new TimeSpan(12, 25, 43);
DateTime now = DateTime.Now;
if (now.CompareTo(DateTime.Today.Add(startHour)) > 0) {
//...
}
or
TimeSpan startHour = new TimeSpan(12, 25, 43);
DateTime now = DateTime.Now;
if (now.TimeOfDay.CompareTo(startHour) > 0) {
//...
}
So you're only interested in the time component of the date.
if(DateTime.Now.TimeOfDay > startHour.TimeOfDay)
{
// do stuff
}
What's wrong with doing this?