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);
}
}
Related
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.
Hi any ideas on how to calculate time left to a specific hour,
i.e. we start countdown with
if currentTime >= TimeSpan.Parse("06:40") && currentTime <= TimeSpan.Parse("07:25")
and then we parse current hour and end hour (in this example 7:25) and make a label show how many minutes and seconds are left.
I've tried making something with substracting timespan now and end time timespan but it didn't work out at all.
EDIT: The main idea is something like this, but I can't get it to work by using TimeSpan neither DateTime
string myTime;
void timer()
{
var endTime = DateTime.Parse(myTime);
var beginTime = DateTime.Now.TimeOfDay;
}
private void timer1_Tick(object sender, EventArgs e)
{
var endTime = DateTime.Parse(myTime);
var beginTime = DateTime.Now.TimeOfDay;
TimeSpan difference = endTime - beginTime;
TimeSpan currentTime = DateTime.Now.TimeOfDay;
if (currentTime >= TimeSpan.Parse("06:40") && currentTime <= TimeSpan.Parse("07:25"))
{
label5.Text = "0";
myTime = "07:25";
timer();
label6.Text = difference;
}
}
Use DateTime instead of TimeSpan when parsing points in time. TimeSpan is for durations. The difference between two points in time (DateTime) will be a duration (TimeSpan).
var end = DateTime.Parse("21:00");
var now = DateTime.Now; // Could also be some other point in time
TimeSpan timeLeft = end-now;
Console.WriteLine(timeLeft);
Result:
00:24:25.8581440
If you don't like the seconds and fractions of seconds, you can use a custom format, e.g.
Console.WriteLine(timeLeft.ToString("hh\\:mm"));
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..
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"; }
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();
}
}