7

Here is the scenario, I need to know if current DateTime is between 08:00 PM (20:00) and 08:00 AM (08:00). If yes, I need to get the total hours left until 08:00 AM (08:00).

My attempt:

TimeSpan start = TimeSpan.Parse("20:00");
TimeSpan end = TimeSpan.Parse("08:00");  
TimeSpan now = DateTime.Now.TimeOfDay;

bool flag = false;
if (start <= end)
{
     if (now >= start && now <= end)
     {
         flag = true;
     }
}
else
{      
    if (now >= start || now <= end)
    {
        flag = true;
    }
}

if (flag)
{
    /// calculate hours?
}
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
user2818430
  • 5,853
  • 21
  • 82
  • 148

7 Answers7

22

Here is one simple way to do it:

var date = DateTime.Now;
if(date.Hour >= 20 || date.Hour < 8)
{
    var DateTime8 = date.Date.AddHours((date.Hour > 8) ? 24 + 8 : 8);
    TimeSpan diff = DateTime8 - date;
}
mjwills
  • 23,389
  • 6
  • 40
  • 63
Zohar Peled
  • 79,642
  • 10
  • 69
  • 121
3

This is what I came up with. First check if the current time is between the start and end times. If so, then do some TimeSpan math to determine how much time is left until 8AM. If it's currently before midnight, we subtract the current time from 24:00:00 and add 8; otherwise, we subtract the current time from 8:00:00:

Console.WriteLine($"The current time is {DateTime.Now.ToString("hh\\:mm\\:ss")}.");

var currentTime = DateTime.Now.TimeOfDay;
var start = new TimeSpan(20, 0, 0);
var end = new TimeSpan(8, 0, 0);
var midnight = new TimeSpan(24, 0, 0);

if (currentTime >= start || currentTime <= end)
{
    var hoursLeftUntil8 = currentTime.Hours >= 20
        ? midnight.Subtract(currentTime).Add(end)
        : end.Subtract(currentTime);

    Console.WriteLine("There are {0} hours, {1} minutes, and {2} seconds left until 8AM",
        hoursLeftUntil8.Hours, hoursLeftUntil8.Minutes, hoursLeftUntil8.Seconds);
}
else
{
    Console.WriteLine("It is not between 8PM and 8AM.");
}

Console.WriteLine("\nDone!\n\nPress any key to exit...");
Console.ReadKey();

Output

enter image description here

Rufus L
  • 36,127
  • 5
  • 30
  • 43
2

As far as I can see none of the answers provided so far take daylight savings into account. At least in the area where I live there is a night in the spring where the clock on the wall will skip from 2 AM to 3 AM and another night in the autumn where the clock will skip from 3 AM and back to 2 AM once. Different countries will have different rules (or no daylight savings at all).

The spring night has one less hour in the local time zone so if the timestamp is before 2 AM the time difference until 8 AM local time is 1 hour less than you get by doing simple calculations.

In the same way the autumn night has one more hour in the local time zone so if the timestamp is before 2 AM the time difference until 8 AM local time is 1 hour more than you get by doing simple calculations. And even worse: if the local timestamp is between 2 AM and 3 AM it is ambiguous. Was it the first 2:30 AM or the second?

To solve the ambiguity you need to switch from using local DateTime to DateTimeOffset. When you use the later there is no ambiguity between the first time during the night the wall clock is 2:30 AM and the second time because they have different UTC offsets and the UTC offset is part of the DateTimeOffset structure.

So here is some code that will take daylight savings into account:

var now = DateTimeOffset.Now;
if (now.Hour >= 20 || now.Hour < 8)
{
    var midnightDateTime =  now.Date.AddDays(now.Hour >= 20 ? 1 : 0);
    var offsetMidnight = TimeZoneInfo.Local.GetUtcOffset(midnightDateTime);
    var midnight = new DateTimeOffset(midnightDateTime, offsetMidnight);
    var eightAmDateTime = new DateTime(midnight.Year, midnight.Month, midnight.Day, 8, 0, 0);
    var offsetEightAm = TimeZoneInfo.Local.GetUtcOffset(eightAmDateTime);
    var eightAm = new DateTimeOffset(eightAmDateTime, offsetEightAm);
    var timeLeftUntilEightAm = eightAm - now;
}

When you work with DateTimeOffset you have to be very careful when you mix them with DateTime. There is an implicit conversion from DateTime to DateTimeOffset. If the kind of the DateTime is Local or Unspecified the offset of the resulting DateTimeOffset will be the offset of the local timezone. In the code above now.Date has kind Unspecified and if you do some arithmetic with this DateTime and another DateTimeOffset the conversion kicks in and the result may be off by the offset of your local timezone. That is probably not what you want and at least I have been bitten by this less than obvious conversion.

Martin Liversage
  • 104,481
  • 22
  • 209
  • 256
0

You can use something like that. If time is between 20:00 and 00:00 you should add 8 hours to difference between now and 00:00.

TimeSpan timeLeft = new TimeSpan(0);

if (now >= start)
{
    timeLeft = end + (TimeSpan.Parse("23:59:59.9999") - now);
}     
else if (now <= end)
{
    timeLeft = end - now;
}
Console.WriteLine(timeLeft);

Another approach can be:

DateTime now = DateTime.Now;
TimeSpan t = new TimeSpan(0);
if (now.Hour >= 20)
{
    DateTime nextDay = now.AddDays(1);
    t = new DateTime(nextDay.Year, nextDay.Month, nextDay.Day, 8, 0, 0).Subtract(now);
}
else if (now.Hour < 8)
{
    t = new DateTime(now.Year, now.Month, now.Day, 8, 0, 0).Subtract(now);
}
Console.WriteLine(t);
fofik
  • 998
  • 11
  • 17
0

The below code should do what you need. This solution will work for any value of start, end and now. The key is the addition of 24 hours if it goes negative.

var remainingTime = end - now;

if (remainingTime < TimeSpan.Zero)
    remainingTime = remainingTime + new TimeSpan(24, 0, 0);

Complete sample:

using System;

namespace Test
{
    public class Program
    {
        public static void Main()
        {
            var start = TimeSpan.Parse("20:00");
            var end = TimeSpan.Parse("08:00");
            var now = DateTime.Now.TimeOfDay;

            var flag = InTheTimeWindow(start, end, now);

            if (flag)
            {
                var remainingTime = end - now;

                if (remainingTime < TimeSpan.Zero)
                    remainingTime = remainingTime + new TimeSpan(24, 0, 0);

                Console.WriteLine(remainingTime);

            }
            Console.ReadLine();
        }

        private static bool InTheTimeWindow(TimeSpan start, TimeSpan end, TimeSpan now)
        {
            var flag = false;
            if (start <= end)
            {
                if (now >= start && now <= end)
                {
                    flag = true;
                }
            }
            else
            {
                if (now >= start || now <= end)
                {
                    flag = true;
                }
            }
            return flag;
        }
    }
}
mjwills
  • 23,389
  • 6
  • 40
  • 63
0

Based on this SO you may try something on the lines of following code:

TimeSpan start = TimeSpan.Parse("20:00:00");
TimeSpan end = TimeSpan.Parse("08:00:00");
TimeSpan now = DateTime.Now.TimeOfDay;

if (now.IsBetween(start, end))
{
     Console.WriteLine("Between 20 to 8");
}
else
{
     Console.WriteLine("Not Between 20 and 8");
}

Console.WriteLine("Time remaining before 8 AM is: {0} Hrs.", 
(now.Hours > start.Hours) ? TimeSpan.Parse("24:00:00").Subtract(now).Add(end).Hours : 
end.Subtract(now).Hours); //TimeSpan.Parse("24:00:00") is to compensate midnight hours.



public static class Extensions
{
        public static bool IsBetween(this TimeSpan timeNow, TimeSpan start, TimeSpan end)
        {
            var time = timeNow;
            // If the start time and the end time is in the same day.
            if (start <= end)
                return time >= start && time <= end;
            // The start time and end time is on different days.
            return time >= start || time <= end;
        }
}
Siva Gopal
  • 3,474
  • 1
  • 25
  • 22
-3

the if's first condition is never gonna be met. Anyways just garbage code, it doesn't affect results, just performance because of the extra comparison.

So, in order to make the 'gap measurement' take a look at TimeSpan.Subtract method

D Ie
  • 841
  • 7
  • 23
  • 1
    still no clues... should it have been a comment or what? I thought the 'if correction' and the TimeSpan link were clear enough to make it an answer – D Ie Sep 08 '17 at 06:27
  • At least someone agrees with me... Thanks mate, I thought I was going crazy :) btw I won't delete this answer, just to show it as an example of how helpful and sympathetic people can be... (yeah, this last one was sarcasm, now please, downvote me to hell xD) – D Ie Sep 08 '17 at 06:40
  • I suspect the downvoting was due to the fact that people thought this may have been more appropriate as a comment. – mjwills Sep 08 '17 at 06:46
  • I've seen answers with less information, but I could agree with that @mjwills Thanks! – D Ie Sep 08 '17 at 06:54