C# button pause - c#

I am making a digital clock in a GUI on C#. I have 5 buttons, 4 for the time zone conversions, and one for close forms.
My question is, when I press button one (Central Time conversion from my system time) it will flash the time in the label box for about 1 second and revert back to my current system time.
In console I know there is a pause execution to pause the program. How can I use a pause to hold the central time button on that setting yet keep the timer running? I am open to using multiple forms.
Here is my code for the button:
private void Central_Click(object sender, EventArgs e)
{
hr = DateTime.Now.Hour;
hr = DateTime.Now.Hour - 1;
min = DateTime.Now.Minute;
sec = DateTime.Now.Second;
if (hr > 12)
hr -= 12;
if (sec % 2 == 0)
{
time.Text = hr + ":" + min + ":" + sec;
}
else
{
time.Text = hr + " " + min + " " + sec;
}
}

If I understand correctly, maybe something like this will work for you:
private void Central_Click(object sender, EventArgs e)
{
// Here you could disable all the buttons
// endTime defines how long we will show this time zone (5 seconds)
var endTime = DateTime.Now.Add(TimeSpan.FromSeconds(5));
while (DateTime.Now < endTime)
{
// Show the short time format (hh:mm:ss AM|PM)
var displayText = DateTime.Now.Subtract(TimeSpan.FromHours(1)).ToString("T");
if ((DateTime.Now.Second % 2 == 1))
{
// Every other second, hide the colons
displayText = displayText.Replace(":", " ");
}
time.Text = displayText;
// Sleep for one second
Thread.Sleep(TimeSpan.FromSeconds(1));
}
// And here you can enable the buttons again
}
One other thing to note is that there are built-in methods for converting to another time zone. Basically, you get the UTC (universal) time, and then convert it to the time zone you're interested in. The code above could be converted to use this like so:
private void Central_Click(object sender, EventArgs e)
{
// endTime defines how long we will show this time zone (5 seconds)
var endTime = DateTime.Now.Add(TimeSpan.FromSeconds(5));
while (DateTime.Now < endTime)
{
// Get UTC time
DateTime utcTime = DateTime.UtcNow;
// Convert it to Central Time
var displayText = TimeZoneInfo.ConvertTimeFromUtc(utcTime,
TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time"))
.ToString("T");
if ((DateTime.Now.Second % 2 == 1))
{
// Every other second, hide the colons
displayText = displayText.Replace(":", " ");
}
time.Text = displayText;
// Sleep for one second
Thread.Sleep(TimeSpan.FromSeconds(1));
}
}

Your question is rather unclear. But I guess you are simply making a regular clock. For this all you need to do is to make the time zone settings persist. So you need to store them in a class level variable or two, maybe like this:
TimeSpan correction = new TimeSpan(0);
string zone = "ET";
private void timer1_Tick(object sender, EventArgs e)
{
// display the corrected time with its name
time.Text = (DateTime.Now + correction).ToString("h:mm:ss ") + zone;
}
private void Central_Click(object sender, EventArgs e)
{
correction = new TimeSpan(-1, 0, 0); // set the hours of the new zone
zone = "CT"; // set its name
}
I hope you have a nicer name for the Timer, like the other names you use.. (Although I always include a prefix that shows me the Type of the control..)
Please also have a look at the sleuth of predefined date and time formats, many of which will work according to your machines localization:
Standard Date&Time patterns
Long time pattern
If I didn't understand what you mean by 'pausing', please clarify! If maybe you want not to really switch to a new timezone but only display its time for a short while, you just need to add 3 or 4 lines..:
A new variable to hold the time yet to hold the zone:
int secondsToHold = 0;
One line in the click to set it to a few seconds, here I cose 3 seconds:
secondsToHold = (int) (3 * 1000f /timer1.Interval);
And finally code in the Tick event to check and reset the varaibles:
if (secondsToHold > 0) secondsToHold -= 1;
else { correction = new TimeSpan(0); zone = "ET"; }

Related

Trying to implement timer and perform tasks every x seconds but the tasks seem to get delayed

I'm writing an app where a user specifies a length of time, length of an interval and a length of time in between intervals. I want to have a timer label showing the user the total time but then I also want to have a label showing the work status (recording if in the interval, break if between interval time and break end).
Heres an Example: Total time = 2 min, Interval = 20 seconds, Break = 10 seconds
In this example there will be 4 intervals. So from 0:00-0:19 I want to display "Recording" and then from 0:20-0:29 I want to display break and then from 0:30-0:49 I display "Recording" and 0:50-0:59 I display "Break" and so on. All while the timer counts the time.
So I thought this would be pretty straightforward but what seems to happen is the timer increments properly but after the 1st interval the label doesnt switch from break to recording until 0:31 or 0:32 so it looks a little delayed.
Here is the code I am using currently (Note obs is an object Im passing in that has data from user input).
int TotalInterval = obs.Interval + obs.Break;
int WorkingInterval = obs.Interval;
int NumberOfIntervals = (obs.Duration*60) / TotalInterval;
DateTime ObservationEnd = obs.DateCreated.AddMinutes(obs.Duration);
Timer.Text = "Starting Timer";
int minutes = 0;
int seconds = 0;
int InIntervalCounter = 0;
Device.StartTimer(TimeSpan.FromSeconds(1), () =>
{
// called every 1 second
Timer.Text = "Started";
if (ObservationEnd < DateTime.UtcNow)
{
Timer.Text = "Time Over";
Results.IsVisible = true;
return false;
}
else
{
seconds++;
InIntervalCounter++;
if (InIntervalCounter > WorkingInterval)
IntervalOrBreak.Text = "Break";
if (InIntervalCounter > TotalInterval)
{
IntervalOrBreak.Text = "Recording";
InIntervalCounter = 0;
}
Timer.Text = "Time: " + minutes + ":" + seconds.ToString("D2");
return true;
}
});
I'm pretty new to app development/xamarin so any help is greatly appreciated.
Try using simple Threads with Thead.sleep() like this:
final long delay_millis = 100;
Thread thread_something;
thread_something = new Thread(new Runnable() {
#Override
public void run() {
while (true) {
try {
long start_time = SystemClock.elapsedRealtime();
// Do some task
long time_need_for_delay = (start_time + delay_millis) - SystemClock.elapsedRealtime();
if(time_need_for_delay > 0)
thread_something.sleep(time_need_for_delay);
} catch (Exception e) { }
}
}
});
thread_something.start();
after the 1st interval the label doesnt switch from break to recording
until 0:31 or 0:32 so it looks a little delayed.
If you want to display break from 0:20-0:29 and display "Recording" from 0:30-0:49, I think the if statement should change to InIntervalCounter >= WorkingInterval and InIntervalCounter >= TotalInterval, InIntervalCounter > WorkingInterval may cause the 1 second delay.

Get time between reaching target (above) and exiting target (below) on chart

The following chart updates its values using a winforms Timer every second. The red line represents a constant target testing pressure, the blue line is the actual pressure read from a PLC object.
Y Axis = Testing Pressure, X Axis = Current Time, chart is updated with winforms timer at Interval = 1000 (every second)
The requirement is showing how many seconds have passed between the blue line reaching the constant required testing pressure (red line) and falling below the
constant required testing pressure.
The block that sets the constant required testing pressure:
...
chart1.ChartAreas[0].CursorY.Position = d;
chart1.ChartAreas[0].CursorY.LineWidth = 1;
chart1.ChartAreas[0].CursorY.LineColor = System.Drawing.Color.Red;
The part where I am stuck (this block is inside the method which updates the chart every second):
double plcTestpressure = ((uint)plc.Read("MD220")).ConvertToDouble();
double reqTestPressure = Convert.ToDouble(txtTestingPressure.Text);
if (plcTestpressure > reqTestPressure && !isAboveReq)
{
DateTime aboveReq = new DateTime();
aboveReq = DateTime.Now;
isAboveReq = true;
//this is for checking the plc read pressure
string currentpressure = ((uint)plc.Read("MD220")).ConvertToDouble().ToString();
}
//check if current pressure is below required and that pressure WAS above required a second ago...
if(plcTestpressure < reqTestPressure && isAboveReq)
{
DateTime belowReq = new DateTime();
belowReq = DateTime.Now;
tickCounter = (belowReq - aboveReq).TotalSeconds;
isAboveReq = false;
}
I have tried and stepped through this block, but it gives me a misleading answer in tickCounter (33 seconds when you can visually see on the graph 5 seconds have passed) and after the first time the tickCounter is assigned to, the aboveReq datetime stamp does not want to change.
Is there a better way to accomplish this goal? Am I going about it wrong? Should I provide more detail?
I would have to assume you have multiple variables named "aboveReq" since variables declared in an "if" block are local to the block. That means that when you access the "aboveReq" variable in the second "if" block, you aren't accessing the same variable.
Also does string currentpressure = ((uint)plc.Read("MD220")).ConvertToDouble().ToString(); really need to be within the if block (only tracking current pressure while above target)?
//Outside of method, top of class
private DateTime? _startTime = null;
private DateTime? _endTime = null;
//In method
string currentpressure = ((uint)plc.Read("MD220")).ConvertToDouble().ToString();
bool breachPressure = plcTestpressure > reqTestPressure;
if (breachPressure && _startTime == null)
{
_startTime = DateTime.Now;
}
else if(!breachPressure && _startTime != null)
{
_endTime = new DateTime();
var tickCounter = _endTime.Value.Subtract(_startTime.Value).TotalSeconds;
}
-----------------------------Edit---------------------------------------
Am I going about it wrong?
It would be considered cleaner if you moved the pressure monitoring logic to a separate class, thus keeping true to the single responsibility principle.
You can do that by implementing a pressure monitoring class that would raise events when the threshold is breached - something along the lines of -
public class PressureObserver
{
public event EventHandler<double> OnRaisedAboveThreshhold;
public event EventHandler<double> OnFellBelowThreshhold;
public double ThresholdPressure{ get; }
private double _lastMeasured = 0; //Initial Pressure
public PressureObserver(double thresholdPressure)
{
ThresholdPressure = thresholdPressure;
}
public void Observe(double plcTestpressure)
{
double pressureDelta = plcTestpressure - _lastMeasured;
if (pressureDelta > 0) //Pressure climbed
{
if(_lastMeasured < ThresholdPressure && //Last measurement was below threshold
plcTestpressure > ThresholdPressure) //This one is above, cross made
{
OnRaisedAboveThreshhold?.Invoke(this, plcTestpressure);
}
}
else if(pressureDelta < 0) //Pressure declined
{
if (_lastMeasured > ThresholdPressure && //Last measurement was above threshold
plcTestpressure < ThresholdPressure) //This one is below, cross made
{
OnFellBelowThreshhold?.Invoke(this, plcTestpressure);
}
}
_lastMeasured = plcTestpressure;
}
}
Then in your main class you would have fields
private PressureObserver _pressureObserver;
private DateTime _raisedAboveTime;
private DateTime _fellBelowTime;
private double _overpressureDuration;
you would define two methods to react to threshold changes
private void Obs_OnRaisedAboveTreshhold(object sender, double e)
{
//Code to do on raised above
_raisedAboveTime = DateTime.Now;
}
private void Obs_OnFellBelowTreshhold(object sender, double e)
{
//Code to do on fell below
_fellBelowTime = DateTime.Now;
_overpressureDuration = _fellBelowTime.Subtract(_raisedAboveTime).TotalSeconds;
}
and in the constructor you would subscribe to the observer class
_pressureObserver = new PressureObserver(60); //replace 60 with threshold
_pressureObserver.OnRaisedAboveThreshhold += Obs_OnRaisedAboveTreshhold;
_pressureObserver.OnFellBelowThreshhold += Obs_OnFellBelowTreshhold;
and in your tick timer you would just add
_pressureObserver.Observe(plcTestpressure);

Timer once a minute on the minute

I can't get the timer to fire once a minute on the minue, 1:00, 1:01, 1:02 etc. Instead, when the timer executes drifts by a couple of seconds each iteration
internal void StartTimer()
{
DateTime nowEastern = CalendarEntity.Calendar.GetEasternTime();
int secondsInterval = 5;
double additionalSeconds = secondsInterval - nowEastern.TimeOfDay.TotalSeconds % secondsInterval;
if (additionalSeconds == 0)
{
additionalSeconds = 1;
}
var nearestOnOneMinutes = new DateTime(
nowEastern.Year,
nowEastern.Month,
nowEastern.Day,
nowEastern.Hour,
nowEastern.Minute,
nowEastern.Second
).AddSeconds(additionalSeconds);
TimeSpan timeToStart = nearestOnOneMinutes.Subtract(nowEastern);
TimeSpan tolerance = TimeSpan.FromSeconds(1);
if (timeToStart < tolerance)
{
timeToStart = TimeSpan.Zero;
}
timer_onem = new System.Threading.Timer(OnTimedEvent, null,
(int)timeToStart.TotalMilliseconds, Timeout.Infinite);
}
private static void OnTimedEvent(object o)
{
var minute = DateTime.Now.Minute;
var second = DateTime.Now.Second;
if (minute != lastMinute && second % 60 < 2)
{
lastMinute = minute;
CodeToExecute();
}
}
static void CodeToExecute()
{
double tms = 60000;
// code here
int wait = 60 - System.DateTime.Now.Second;
timer_onem.Change(Convert.ToInt64(tms) - wait, Timeout.Infinite);
}
EDIT 1
I changed the interval so that it fires once a second and then check that the minute has changed. Still drifts
timer_onem = new System.Threading.Timer(OnTimedEvent, null,
(int)timeToStart.TotalMilliseconds, 1000);
private static void OnTimedEvent(object o)
{
var minute = DateTime.Now.Minute;
if (minute != lastMinute)
{
lastMinute = minute;
CodeToExecute();
}
}
private static void CodeToExecute()
{
if (bGenerate)
{
double tms = 1000;
// code
timer_onem.Change(Convert.ToInt64(tms), 1000);
}
}
A Timer is only guaranteed to be no faster than Interval.
So you need to call it, say every second and check for the full minute.
For even better precision you would have to check every 1/2 second or better.
It is a basic rule of information theory that says that to measure with a given resolution (1 second in your case) you need to sample with better than twice that resolution. Hence to measure 20kHz you need a smpling rate better than 2x20kHz, say 44.1kHz. (Recognize the numbers?)
If you don't want to call it so often for simply getting one precise point in time, you could write a little more involved code that on each Tick resets the Timer.Interval to a little under half of the remaining time until the next full minute until it is under say 500ms..
There are rather complex things going on in your code wrt to setting up the expected time, though; do make sure they are not the real problem. There should not be a growing drift from the timer's lack of precision, unless you 'collect' the errors..

TimeSpan and DispatchTimer

I'm using a class to modify a DateTime and using a TimeSpan to display X hours, Y minutes, Z seconds to a WPF label every second with a DispatchTimer. The code itself gives the proper timespan, however the DispatchTimer is giving the wrong output. Can I get some input on what is going on here?
The ModifiedTime Minutes properties is still being queried during debug breaks (hovering over ModifiedTime.Minutes keeps giving an increasing number.), is this the norm?
Runtime output starts at 3 minutes, then displays 8 minutes, 13, 18, 23, 28, etc.
Library:
public Clock() {
load_ = DateTime.Now;
time_ = new DateTime();
time_ = DateTime.Now;
modifiedTime_ = new DateTime();
modifiedTime_ = DateTime.Now;
difference = TimeSpan.Zero;
}
public TimeSpan ModifiedTime {
//Convert the real time to timespan.
//display X Years, Y Days, Z Hours...
get {
modifiedTime_ = modifiedTime_.AddMinutes(1.0);
difference = modifiedTime_.Subtract(time_);
return difference;
}
set { difference = value; }
}
WPF:
DispatcherTimer dispatcherTimer;
public MainWindow() {
InitializeComponent();
dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
dispatcherTimer.Interval = new TimeSpan(0, 0, 1);
dispatcherTimer.Start();
}
private void dispatcherTimer_Tick(object sender, EventArgs e) {
lblModTime.Content = clock.ModifiedTime.Hours + " hours, " + clock.ModifiedTime.Minutes + " minutes, " + clock.ModifiedTime.Seconds + " seconds, " + clock.ModifiedTime.Milliseconds + " milliseconds.";
}
Right, every time you call clock.ModifiedTime. in your dispatcher (4 times!) you add a minute to the modified time, plus possibly once more for evaluating the statement in the debugger. That would explain your incrementing your display by 5 each time.
If I understand correctly, you want to add one minute to the time started for every second that passed. So take the difference in seconds, then add that as minutes to time started for your new time.
public TimeSpan ModifiedTime
{
get
{
TimeSpan elapsed = DateTime.Now - TimeStarted;
return TimeStarted.AddMinutes(elapsed.TotalSeconds);
}
}

C# Timer counter in xx.xx.xx format

I have a counter that counts up every 1 second and add 1 to an int.
Question
How can I format my string so the counter would look like this:
00:01:23
Instead of:
123
Things I've tried
Things I've tried so far:
for (int i = 0; i < 1; i++)
{
_Counter += 1;
labelUpTime.Text = _Counter.ToString();
}
My timer's interval is set to: 1000 (so it adds 1 every second).
I did read something about string.Format(""), but I don't know if it is applicable.
Thanks if you can guide me through this :D!
Use a TimeSpan:
_Counter += 1;
labelUpTime.Text = TimeSpan.FromSeconds(_Counter).ToString();
You could make it a TimeSpan (for that's what it is, a span of time), then format that:
labelUpTime.Text = TimeSpan.FromSeconds(_Counter).ToString();
Don't use a counter, and don't rely on the timer firing exactly every second. It won't. Do something like this.
class TimerTest
{
private DateTime _start = DateTime.Now;
private Timer _timer = new Timer(1000);
public TimerTest()
{
// (DateTime.Now - _start) returns a TimeSpan object
// Default TimeSpan.ToString() returns 00:00:00
_timer.Elapsed = (o, e) => labelUpTime.Text = (DateTime.Now - _start).ToString();
}
}
You can adjust the formatting with the TimeSpan.ToString method.
TimeSpan timer = new TimeSpan(0);
and on your interval:
timer += TimeSpan.FromSeconds(1);
Use timespan. To add a second use
mytimespan.Add(new TimespanFromSeconds(1));
Console.WriteLine(mytimespan); //Output in the form of xx:xx:xx
http://www.dotnetperls.com/timespan
it worked well for me
public TimeSpan ElapsedTimeFormatted
{
get
{
if (FinishedOn != null &&
StartedAt != null)
{
TimeSpan durationCount = new TimeSpan();
int hours = 0;
int minutes = 0;
int seconds = 0;
var times = Segments.Select(c => c.ElapsedTimeFormatted).ToList();
foreach (var time in times)
{
TimeSpan timeParse = TimeSpan.Parse(time);
hours = hours + (int)timeParse.Hours;
minutes = minutes + (int)timeParse.Minutes;
seconds = seconds + (int)timeParse.Seconds;
durationCount = new TimeSpan(hours, minutes, seconds);
}
return durationCount;
}
return new TimeSpan();
}
}

Categories

Resources