0

I have this if condition where I need to do some stuff if the difference is 15 min or so

if (DateTime.UtcNow - x.Timestamp == TimeSpan.FromMinutes(15))
{
    //Do something
}

The above condition never satisfies when I check with == but when I do >= it gets into the condition but that's not what I need, I want 15 min or so difference.

Can someone explain this behavior?

Sample Data:

x = 2/17/2020 8:45:17 PM

Sam
  • 471
  • 7
  • 24
  • 7
    You are saying "if the difference is exactly 15 minutes, 0 seconds, 0 milliseconds, 0 microseconds". Do you want to test if the difference is more than 15 but less than 16 minutes? – canton7 Feb 18 '20 at 14:05
  • 5
    What do you mean by "precise"? Surely not ±100 nanosecond precise, right? – Sweeper Feb 18 '20 at 14:06
  • Yes but if I do `>=` then it will keep executing the function, I want to execute if every 15 min or so – Sam Feb 18 '20 at 14:07
  • 1
    Check if the time difference is _between_ 14 and 16 minutes then. – Sweeper Feb 18 '20 at 14:08
  • 1
    Also, how frequently are you checking the condition? Perhaps, set a flag, if more than 15 minutes and flag not set, do action and reset the flag. – Peter Smith Feb 18 '20 at 14:08
  • Cool thnx :)... – Sam Feb 18 '20 at 14:08
  • @PeterSmith I'm checking it every second – Sam Feb 18 '20 at 14:09
  • 3
    Please be as precise in your language describing your question as you'd like your answer to be. You say "an exact 15 min difference" in your question, but in your comment you say "every 15 min or so". – Heretic Monkey Feb 18 '20 at 14:09
  • Does this answer your question? [Calculate relative time in C#](https://stackoverflow.com/questions/11/calculate-relative-time-in-c-sharp) – Alb Feb 18 '20 at 14:11
  • `if (Math.Abs(((DateTime.UtcNow - x.Timestamp) - TimeSpan.FromMinutes(15)).TotalSeconds) < 1.0) {...}` change `1.0` (second) for the correct *tolerance* – Dmitry Bychenko Feb 18 '20 at 14:14
  • @DmitryBychenko `Non-invocable member 'TimeSpan.TotalSeconds' cannot be used like a method.` – Sam Feb 18 '20 at 14:15
  • @Sam: Sorry for typo, `TotalSeconds` is a property – Dmitry Bychenko Feb 18 '20 at 14:16
  • Note: You can use `TimeSpan.Duration()` instead of `Math.Abs`. Then you can use `TimeSpans` all the way through – canton7 Feb 18 '20 at 14:17
  • @canton7 can you please give the example – Sam Feb 18 '20 at 14:19
  • Just porting @DmitryBychenko's code: `if (((DateTime.UtcNow - x.Timestamp) - TimeSpan.FromMinutes(15)).Duration() < TimeSpan.FromSeconds(1.0))` – canton7 Feb 18 '20 at 14:20

3 Answers3

1
//I cannot comment on the above answer i dont have enough Rep

I think a better solution for a time trigger to do something would be like so:

static System.Timers.Timer _t = new System.Timers.Timer();

void Init()
{
    //Start a timer trigger every 300000 milliseconds = 5 minutes
     _t.Interval = 300000;
     _t.Elapsed += fiveMinutesElapsed;
     _t.Enabled = true;
}    
public void fiveMinutesElapsed()
{
    t.Enabled = false;
    //Do Something
    t.Enabled = true;
}
Aurelius
  • 178
  • 1
  • 1
  • 14
  • As of [c# naming conventions](https://learn.microsoft.com/en-us/dotnet/standard/design-guidelines/general-naming-conventions) do not use underscores! Also `5MinutesElapsed` won't compile, as you cannot start a name with a numeral digit. And some info for those who want the 5 minutes to start **after** `5MinutesElapsed` executed (to avoid overlapping when execution takes more than 5 minutes): set `t.Enabled = false` at the beginning of `5MinutesElapsed` and `t.Enabled = true` at the end of `5MinutesElapsed` – Alb Feb 20 '20 at 12:46
  • @alb You're allowed to use underscores in private fields. For example, look at [Microsoft's own code for the `FileStream` class](https://referencesource.microsoft.com/#mscorlib/system/io/filestream.cs,e23a38af5d11ddd3) - note all the private fields beginning with underscores! – Matthew Watson Feb 20 '20 at 14:09
  • @MatthewWatson Good example. This [article](https://stackoverflow.com/questions/3136594/naming-convention-underscore-in-c-and-c-sharp-variables/3136618#3136618) states why: use underscores only for underlying private fields of public properties, to not use them accidentally! This is what you saw within Microsoft's code. – Alb Feb 21 '20 at 01:34
  • For *distinguishing globals from locals* (even methods from variables) topic: **the preferable way is to use IDE support**. There are extensions to Visual Studio to make them shown with different colors. If we don't let it to the IDE why we listen to compiler errors? Why we have shortcut to see parameter info for method invocation? We could go back to where *Vivado* was with VHDL prior to 2017: the only error type was: *build failed*. Even from 2017 we were happy to see in which **line** the syntax error is (not which char missing after which word). We ain't alone, use help instead of reinvent – Alb Feb 21 '20 at 02:21
  • @Alb So in the code in this answer where you are complaining about the underscores, note that the variable in question is indeed a private field, so it's perfectly OK to use underscores. You may disagree, and that's your prerogative, but you can't point to the Microsoft guidelines to support your claim! The most important thing for private fields is to follow the pattern defined by your organisation. – Matthew Watson Feb 21 '20 at 08:41
  • @MatthewWatson note that, in this answer where you don't like my (and Microsoft's) suggestion: the private field does not serve any *Property* so **it's NOT a good way to name it**. You can tell everybody it is **your** protocol at the Company, but that has nothing to do with this answer and *you can't point to it for your claim*. :) And yes, you are "allowed" to use underscores as you ARE "allowed" to use special characters (л / ű / 苹) even for public members but none of them are recommended! Have a great day! – Alb Feb 21 '20 at 10:05
  • @Alb I'm quite happy with Microsoft's guidelines - and indeed follow them - which of course only apply to public and protected items - and I'm also happy with doing the same as Microsoft do for private fields, i.e. use an underscore prefix. So, for example, if you inspect the Microsoft source code for FileStream that I linked, you will see variables such as `_exposedHandle` (and many others) that are NOT used for any property. As I said, this is an area where it is up to the organisation what naming convention they want to use, since it is not covered by any "official" guidelines. – Matthew Watson Feb 21 '20 at 10:17
  • @Alb Here's my last comment on this. :) Have a read of the [latest coding style guidelines for .Net Core](https://github.com/dotnet/corefx/blob/368fdfd86ee3a3bf1bca2a6c339ee590f3d6505d/Documentation/coding-guidelines/coding-style.md) and pay particular attention to the part that says `Prefix instance fields with _, static fields with s_ and thread static fields with t_` and the part that says `We avoid this. unless absolutely necessary.` – Matthew Watson Feb 21 '20 at 10:27
0

Can someone explain this behavior?

Yes: It is very unlikely that the elapsed time calculated from DateTime.Now is exactly equal to your specified TimeSpan.

From your comments, it seems that you want to periodically check if it's time to do something. One easy way to do this is to use a Stopwatch to keep track of the amount of time that has elapsed since the last time you did the thing:

using System;
using System.Diagnostics;
using System.Threading;

namespace ConsoleApp1
{
    class Program
    {
        static void Main()
        {
            throttleTimer.Start();

            // This loop simulates your periodic check to see if the action
            // needs to be performed:

            while (true)
            {
                doActionIfTimeElapsed(TimeSpan.FromSeconds(5));
                Thread.Sleep(1000);  // Simulate checking every 1 second or so.
            }
        }

        static Stopwatch throttleTimer = new Stopwatch();

        static void doActionIfTimeElapsed(TimeSpan period)
        {
            if (throttleTimer.Elapsed <= period)
                return;

            doAction();
            throttleTimer.Restart();
        }

        static void doAction()
        {
            Console.WriteLine("Doing the action.");
        }
    }
}

This sample program will perform doAction() whenever you call doActionIfTimeElapsed() and more than 5 seconds has elapsed since the last time it called doAction().

Alternatively, if you want to perform an action after every N seconds without having to call a method to periodically check if the action should be performed, then you can use a System.Threading.Timer instead.

Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
  • Use `Thread.Sleep()` only for debug purpose; otherwise, it is bad practice. (I'm not sure but I think it even blocks the main thread from executing anything until the time has passed). Btw: Thread.Sleep(1000) not guarantees it will sleep for 1 sec, but to sleep **at least** 1 sec which could be even 2. – Alb Feb 20 '20 at 12:56
  • @alb The Thread.Sleep is merely for simulating the checking in this example. The purpose of this example is to show the use of the throttle timer, not to show how to call something every N milliseconds... Note that there is nothing you can do in Windows to *guarantee* doing something exactly to the nearest millisecond, it not being a real-time operating system and all that. – Matthew Watson Feb 20 '20 at 14:05
  • I'm not telling this to you, I'm telling this to others when they read your answer without former knowledge. Your statement is perfectly fine with me. – Alb Feb 21 '20 at 09:57
0

Option 1:

If x.Timestamp is something you can reset (not a server-/client-side readonly value), then use >= (or > as = is less likely to ever happen) and reset x.Timestamp to the current time. Also, check this answer for determining relative time.

Option 2:

If you just want to raise a function in every 15 minutes, you have the answer here.

Note that 3 different timers exist, if you will need one that operate within seconds or milliseconds, you may want to avoid overlapping: which is (only?) possible with System.Timers.Timer via its Enabled property.

Option 3:

If you want to raise a function inside a while loop in every 15 minutes, I propose to use a StopWatch.

var watch = new StopWatch();
watch.Start();
while(...)
{
    if (watch.Elapsed > TimeSpan.FromMinutes(15))
    {
        // do your stuff
        watch.Restart();
    }
}
Alb
  • 412
  • 5
  • 12
  • Thank you for the answer but I have solved this problem here: https://stackoverflow.com/a/60291610/11958101 – Sam Feb 20 '20 at 13:52