Automatic update custom DateTime object based on system time - c#

I think my question is a bit confusing as I'm not really sure how should I give it a proper title.
Anyway, my question is because I'm getting current date on my server instead of system time (or device's time). How can I make it to act like a "clock"?
For example:
// I have a string of date retrieved from server, let's call it as "stringFromServer"
myDate = Convert.ToDateTime(stringFromServer);
So after the above line of codes, I need myDate to update every seconds so that I can use it anytime I want.
Let say the current time (get from myDate) is 09:00 and after 5 seconds I expect it to be updated to 09:05.
One of the solution I have in mind is in my Update() function,
I'll do something like this:
myDate.Value.AddSeconds(deltaTime);
But I'm looking for better solution and hopefully I can get some help here.
PS: The reason I'm not using system time is to prevent user changing the time in device's settings. So I have to update myDate whenever the user exit or reopen the app.

In Unity3D, if you want an event to happen every X seconds, a good way to do that is to use an IEnumerator function. So for example, if you want to keep track of a custom time variable you could have an IEnumerator like this:
IEnumerator UpdateServerTime()
{
while(true)
{
myDate.Value.AddSeconds(1);
yield return new WaitForSeconds(1);
}
}
This example would continue to update your time varable by one second, every second. As other users have mentioned in the comments, this is not the perfect way to keep track of time. But it should achieve what you want, if you are looking to track time in unity.
It is important to remember that in order to use this method properly, you need to call it like so:
StartCoroutine(UpdateServerTime());

Related

Making A Cool Down Timer For Multiple Users

So I'm currently developing a Discord Bot, and I have a problem on how I could make a cool down timer for a command. So I want it so if they use a command, then they get added to a list, and have to wait amount of seconds until they can use the command. I have a somewhat idea on how to do this, but I'm mainly stuck at the part of having multiple cool down timers for different people. So lets say as a reference. User1 uses the command, now he has to wait 5 seconds until he uses it again. Then User2 uses the command, and he also has to wait 5 seconds. Well User2 used the command 3 seconds in of the cool down for User1. So basically I'm asking how could I make a timer that kept track of each users time. Then once that specific users cool down is done, he gets removed from a list. I planned to store the users that are on cool down into a list.
I might be overthinking this, so sorry.
The way that I did it was by making it so the program declares 2 empty lists near the start, one containing DateTimeOffset and the other SocketGuildUser. You could tie the two into a list of object instances, if you want your code to be a little more efficient and bug-resistant. For the sake of the example however:
Declare your lists at the start of your program.
public static List<DateTimeOffset> stackCooldownTimer = new List<DateTimeOffset>();
public static List<SocketGuildUser> stackCooldownTarget = new List<SocketGuildUser>();
Here's the rate limit code:
//Check if your user list contains who just used that command.
if (Program.stackCooldownTarget.Contains(Context.User as SocketGuildUser))
{
//If they have used this command before, take the time the user last did something, add 5 seconds, and see if it's greater than this very moment.
if (Program.stackCooldownTimer[Program.stackCooldownTarget.IndexOf(Context.Message.Author as SocketGuildUser)].AddSeconds(5) >= DateTimeOffset.Now)
{
//If enough time hasn't passed, reply letting them know how much longer they need to wait, and end the code.
int secondsLeft = (int) (Program.stackCooldownTimer[Program.stackCooldownTarget.IndexOf(Context.Message.Author as SocketGuildUser)].AddSeconds(5) - DateTimeOffset.Now).TotalSeconds;
await ReplyAsync($"Hey! You have to wait at least {secondsLeft} seconds before you can use that command again!");
return;
}
else
{
//If enough time has passed, set the time for the user to right now.
Program.stackCooldownTimer[Program.stackCooldownTarget.IndexOf(Context.Message.Author as SocketGuildUser)] = DateTimeOffset.Now;
}
}
else
{
//If they've never used this command before, add their username and when they just used this command.
Program.stackCooldownTarget.Add(Context.User as SocketGuildUser);
Program.stackCooldownTimer.Add(DateTimeOffset.Now);
}
From here, type whatever you want your code to do if they pass.

Quartz.net - Issues with Adjusting and Speeding up SystemTime causing Misfires

For testing reasons I want to be able to adjust what time Quartz.Net currently thinks it is so I do not necessarily have to wait hours, days, or weeks in order to check that my code is working.
For this purpose I created the following simple function (it is in F# but could be easily be done in C# or another language) :
let SimulateTime = fun () ->
currentTime <- DateTimeOffset.UtcNow
timeDifferenceInSeconds <- (currentTime - lastCheckedTime).TotalSeconds
simulatedTime <- simulatedTime.AddSeconds((timeDifferenceInSeconds *scaleTimeBy))
lastCheckedTime <- currentTime
simulatedTime
Where currentTime, lastCheckedTime, and simulatedTime would all be of type DateTimeOffset and both timeDifferenceInSeconds and scaleTimeBy are of type float.
I then change SystemTime.Now and SystemTime.UtcNow to use the above function as follows :
SystemTime.Now <-
Func<DateTimeOffset>(
fun () -> SimulateTime())
SystemTime.UtcNow <-
Func<DateTimeOffset>(
fun () -> SimulateTime())
Which was shown by Mark Seemann in a previous question of mine that can find here.
Now this mostly works except it seems like the longer function causes it to be off by a decently wide margin. What I mean by this is that all of my triggers will misfire. For example if I have a trigger set to occur every hour and set scaleTimeBy to 60.0 so that every second passed counts as a minute, it will never actually trigger on time. If I have a misfire policy, the trigger can then go off but the time it lists for when it activated will be as late as the half hour mark (so takes a full 30 seconds slower than what it should have been in this example).
However I can do this :
Console.WriteLine(SimulateTime())
Thread.Sleep(TimeSpan.FromSeconds(60.0))
Console.WriteLine(SimulateTime())
And the difference between the two times output to the screen in this example will be exactly an hour so the call doesn't seem like it should be adding as much of a time difference than it does.
Anyone have any advice on how to fix this issue or a better way of handling this problem?
Edit :
So the C# version of the SimulateTime function would be something like this :
public DateTimeOffset SimulateTime() {
currentTime = DateTimeOffset.UtcNow;
double timeDifference = (currentTime - lastCheckedTime).TotalSeconds;
simulatedTime = simulatedTime.AddSeconds(timeDifference * scaleTimeBy);
lastCheckedTime = currentTime
return simulatedTime;}
If that helps anyone with solving this problem.
So this issue is misfires caused by the fact that Quartz.net will idle and wait when it thinks it doesn't have any triggers occurring any time soon to avoid making too many calls. By default it waits about 30 seconds give or take if it doesn't have any triggers occurring in the time span. The idleWaitTime variable is a Timespan set in the QuartzSchedulerThread. Now when checking for triggers that might occur soon it also uses the BatchTimeWIndow from QuartzSchedulerResources.
Both idleWaitTime and BatchTimeWindow can be set in configuration/properties files where they'd be called "org.quartz.scheduler.idleWaitTime" and "org.quartz.scheduler.batchTriggerAcquisitionFireAheadTimeWindow."
Based off what it is called in BatchTimeWindow I thought it was just a bit of look ahead for grabbing a variable (which would like since if I'm speeding things up, I'd want a small idleWaitTime but I would want it to look further ahead for triggers because the few seconds your waiting is actually minutes so will trigger sooner than it thinks), but the description of "org.quartz.scheduler.batchTriggerAcquisitionFireAheadTimeWindow" on pages going over configuration properties implies that it can cause things to fire early and be less accurate. So to start here is the code for just modifying idleWaitTime
let threadpool = Quartz.Simpl.SimpleThreadPool()
let jobstore = Quartz.Simpl.RAMJobStore()
let idleWaitTime = TimeSpan.FromSeconds(30.0/scaleTimeBy)
let dbfailureretryinverval = TimeSpan(int64 15000)
Quartz.Impl.DirectSchedulerFactory.Instance.CreateScheduler("TestScheduler","TestInstance",threadpool,jobstore,idleWaitTime,dbfailureretryinverval)
let scheduler = Quartz.Impl.DirectSchedulerFactory.Instance.GetScheduler("TestScheduler")
You can create a Scheduler that has the idleWaitTime you want by using the DirectSchedulerFactory which probably could use a little bit better documentation. It takes also a bunch of stuff you may or may not want to modify depending on what you are working on. For threadpool I just use Quartz.net's default SimpleThreadPool because I do not care about messing with the threading at this time and would not want to explain how you go about doing so unless that was the whole point of the question. Information on jobstores is available here. I am using RAMJobStore here because it is simpler than AdoJobStore but it shouldn't matter for this example. The dbfailureretryinterval is another value that don't care about for this example so I just looked up what it is set to by default. Its value should matter the least for this example because not connecting to a database. For idleWaitTime might want to do more tests to figure out what is a good value for it, but I chose to go with just scaling its default value of 30 seconds by scaleTimeBy since that is what I'm using to scale how fast things are going by. So this should make it so if I am having the program simulate time going by at a much faster rate, then it should only remain idle for smaller periods of time. One important thing to note is that when create a scheduler in this way, it is not returned as well so need to make a separate call to get the scheduler I just created. I have no idea why this is this way, I'm guessing that if you are creating several Schedulers and not necessarily using all of them it is better this way.
Now after all that you are likely to still get a bit of a misfire rate. While it is now idling for much smaller units of time (only a few seconds so potentially an acceptable margin depending on what your use case is), it still has the issue of it is only then checking to see if it has a coming trigger in the next few fractions of a second.
So lets see if adding time to BatchTimeWindow helps matters?
let threadpool = Quartz.Simpl.SimpleThreadPool()
let threadexecutor = Quartz.Impl.DefaultThreadExecutor()
let jobstore = Quartz.Simpl.RAMJobStore()
let schedulepluginmap = System.Collections.Generic.Dictionary<String,Quartz.Spi.ISchedulerPlugin>()
let idleWaitTime = TimeSpan.FromSeconds(30.0/timeScale)
let maxBatchSize = 1
let batchTimeWindow = TimeSpan.FromSeconds(timeScale)
let scheduleexporter = Quartz.Simpl.RemotingSchedulerExporter()
Quartz.Impl.DirectSchedulerFactory.Instance.CreateScheduler("TestScheduler","TestInstance",threadpool,threadexecutor,jobstore,schedulepluginmap,idleWaitTime,maxBatchSize,batchTimeWindow,scheduleexporter)
let scheduler = Quartz.Impl.DirectSchedulerFactory.Instance.GetScheduler("TestScheduler")
Now this has even more variables that don't really care about for the purposes of this example and won't even bother going over because adjusting batchTimeWindow actually makes it worse. Like getting you back to misfiring by 30 minutes. So no, batchTimeWindow while looks like might be useful is not. Only modify idleWaitTime.
Ideally for this use would want a small wait time and a larger look ahead time, but the option for that does not seem like its available.

C# Timer to run even if system is switched off or restarted

I am trying to create a script which does something say show a popup after 1 day. As far as I know I can do this using Thread.Stop or using System.Timers or many other ways. But the problem with each is that the computer has to be continuously running for each of these methods to give desired result at the time I want. Basically I want the script to start with installation of my program, wait for exactly 24 hours, then display a message box. If the computer is switched on at that time i.e. after 24 hours it should show the message box on next start up but only if 24 hours or more have passed. Please help, i am unable to find suitable solution for this. any help will be highly appreciated. I think that it may be achieved by getting the dateTime.Now and putting it in a file, and then compare current system time to the time in file every hour or so, and if 24 hours or more have passed, show the message box. Please help
If a message box is what you need to pop up, then you'll need a Windows Forms application. Here is the workflow of how it'll work:
Application will need to save data, either through a database or to a file.
When the application first loads, it will check either the database or the file for a TriggerDate entry.
If the TriggerDate exists, pull this date and compare it to today's date and time. If the current date and time is past our TriggerDate, display the message box. Recreate the TriggerDate with the current date and time plus 24 hours.
If TriggerDate does not exist, create it, filled with the current date and time plus 24 hours (e.g. DateTime.Now.AddHours(24)).
Use Threading.Thread.Sleep() to sleep for 5 minutes.
Jump to step 3 and repeat.
EDIT
Code will be something like this:
private const string TriggerFile = #"C:\TriggerData\trigger.txt";
private DateTime _triggerDate;
if (!File.Exists(TriggerFile))
{
using (StreamWriter sw = File.CreateText(TriggerFile))
{
sw.WriteLine(DateTime.Now.AddHours(24));
}
}
using (StreamReader sr = File.OpenText(TriggerFile))
{
_triggerDate = DateTime.Parse(sr.ReadToEnd());
}
while (true)
{
if (DateTime.Now >= _triggerDate)
{
MessageBox.Show(#"Alert!");
using (StreamWriter sw = File.CreateText(TriggerFile))
{
sw.WriteLine(DateTime.Now.AddHours(24));
_triggerDate = DateTime.Now.AddHours(24);
}
}
System.Threading.Thread.Sleep(60000*5); // Sleep for 5 minutes
}
You may not want to do while(true). You way want to implement a way to get out of the program.
If I understand correctly, what you can use is a way to save the "start date". You can save the start date of the timer and read the value from your script, that way you can calculate if 24 hours or more has passed since the moment you assigned a value to the start date. You can use a simply TXT file to save the value.
I see two ways of achieving this :
Easy way (but not strictly related to C#) is to use the task scheduler and create a task that will run your C# program every 24 hours. One way to do this from an installer would be to use the SchTasks.exe tool. This method allows you to just exit the program after your work is done without having to explicitely wait for the next run.
Harder way: Create a Windows Service, which is a program specifically designed to run permanently on the host computer. These programs are slightly more technical to write though. You can find more explanations about services here. However, you may not want to take this route as service cannot display user interfaces like popups.

How to evaluate when two DateTimes are equal to one another

This is the situation: I have a TimePicker in my application. I would like the user to be able select a time with the TimePicker, then the app will send the user a notification at the time entered with the TimePicker. I'm writing an application for Windows Phone in C#. So far, this is my code (I don't that any of this is correct)
DateTime now = DateTime.Now;
DateTime? get = timePicker1.Value;
if (now == get)
{
ShellToast toast = new ShellToast();
toast.Title = "Title";
toast.Content = "The Time Has Come!";
toast.Show();
}
But every time I run the code, it either gives me an exception, the app doesn't load at all, and every time the notification (toast) never shows. (I also know that the app cannot be running in the foreground for the notification to show). (I know that the notification works because I can get it to work with other situations).
Basically, my questions is: how can I trigger a notification at a specific time defined by the end user?
First of all the Toast notification won't show up if the app is running in foreground. It should be only used in background agents or when application is running under lock screen.
Second, if your goal is to show the notification in selected time of day, then you must not compare the DateTime values, but rather the TimeOfDay part. Also make sure user has entered valid value by checking the "get.HasValue"
Line 1 : DateTime now = DateTime.Now;
Line 2 : DateTime? get = timePicker1.Value;
in Line 1 , you get the system current date-time, "now" is date-time and not null.
but in Line 2, "get" is null-able variable and you are getting the timepicker.value and compare date-time with time.
i do not know what exception you have but with 2 extra checking you can have more safe code
null checking for "get"
make sure that in your development environment you can compare date-time with time value.
You have to remember that Date.Now has a full time AND DATE!
So comparing to the get variable you must ignore the Date part, or probably will not work.
Try changing your if to look something like this:
if (get.HasValue && now.TimeOfDay == get.Value.TimeOfDay)
{
// your remaining code
}
Also, the ShellToast class only works with background services, not on foreground apps (check the Remarks here)!
If you want to show a Toast in your app, use the Toast Prompt from Coding4Fun Toolkit.
You could compare the day, month, year values of the two DateTimes. Take minutes and seconds in account, if you want to be more precise (because I don't know on what detail level you want to compare the values).
If you want to be notified at a specific time, try using the Alarm class.

Set Expiring Date To .NET Output (Without Hardware Dongles)

My first solution for this problem is to use OS/BIOS timer and check it with encrypted date file ( see below pseudocode )
public void CheckFrequently()
{
DateTime registeredDate = ReadFromBiosOrOSTimer();
DateTime readEncryptedDate = ReadFromEncryptedFile();
if(registeredDate >= readEncryptedDate)
{
ShowExpireDateForm();
CloseProgram();
}
}
In this case its obvious that user could change OS/BIOS timer easily and my method not works.
my questions are :
Is there any way to fix user OS/BIOS timer change problem?
Is there any better way to set expiration date to .Net projects?
(My answer is assuming you want to have an "expiring" program of some sort.)
The end-all-be-all big brother answer would be to retrieve a trusted time from an external source, say, a web service. Of course, connectivity (or lack thereof) may make this impossible.
Other than that, knowing that if someone is going to cheat the clock, they would likely do it very close to the expiration, periodically write, somewhere, a timestamp of the current time. If you ever encounter a case where the retrieved (via system call) time is less than the last timestamp, someone might be trying to trick the clock and you can invalidate the session/instance with the appropriate error message. Once you've detected the "expired" case, it's simple to flip a switch and refuse to run anymore.
All of that said, a countermeasure like this will most likely always be beaten by an adversary who is determined enough.

Categories