GetLastInputTime shows impossible time? - c#

To determine, if PC was not used for certain amount of time, I'm using Win32API.GetLastInputTime() method. I'm just subtracting its value from DateTime.Now, and compare it with some value, stored in settings.
It worked perfectly before, but recently GetLastInputTime started to show completely ridiculous results - it shows me future time. Today it shows me July 2nd of 2016.
So, does anyone has any idea, what's happening? How does GetLastInputTime get time, and how it is possible, that this time is future one?

Since GetLastInputTime returns ticks as UInt32 (DWORD)
https://msdn.microsoft.com/en-us/library/windows/desktop/ms724408(v=vs.85).aspx
you can have an integer overflow:
The elapsed time is stored as a DWORD value. Therefore, the time will
wrap around to zero if the system is run continuously for 49.7 days.
To avoid this problem, use the GetTickCount64 function. Otherwise,
check for an overflow condition when comparing times.
And thus have future dates:
13 May 2016 + 49.7 days == 2 July 2016

I think you can not use DateTime.Now because it depends on the time zone.
As described here, you have to use Environment.TickCount to get the idle time.

Related

Best practice for adding/subtracting from universal or local DateTime

I'm trying to add a wrapper around DateTime to include the time zone information. Here's what I have so far:
public struct DateTimeWithZone {
private readonly DateTime _utcDateTime;
private readonly TimeZoneInfo _timeZone;
public DateTimeWithZone(DateTime dateTime, TimeZoneInfo timeZone) {
_utcDateTime = TimeZoneInfo.ConvertTimeToUtc(DateTime.SpecifyKind(dateTime, DateTimeKind.Unspecified), timeZone);
_timeZone = timeZone;
}
public DateTime UniversalTime { get { return _utcDateTime; } }
public TimeZoneInfo TimeZone { get { return _timeZone; } }
public DateTime LocalTime { get { return TimeZoneInfo.ConvertTimeFromUtc(_utcDateTime, _timeZone); } }
public DateTimeWithZone AddDays(int numDays) {
return new DateTimeWithZone(TimeZoneInfo.ConvertTimeFromUtc(UniversalTime.AddDays(numDays), _timeZone), _timeZone);
}
public DateTimeWithZone AddDaysToLocal(int numDays) {
return new DateTimeWithZone(LocalTime.AddDays(numDays), _timeZone);
}
}
This has been adapted from an answer #Jon Skeet provided in an earlier question.
I am struggling with with adding/subtracting time due to problems with daylight saving time. According to the following it is best practice to add/subtract the universal time:
https://msdn.microsoft.com/en-us/library/ms973825.aspx#datetime_topic3b
The problem I have is that if I say:
var timeZone = TimeZoneInfo.FindSystemTimeZoneById("Romance Standard Time");
var date = new DateTimeWithZone(new DateTime(2003, 10, 26, 00, 00, 00), timeZone);
date.AddDays(1).LocalTime.ToString();
This will return 26/10/2003 23:00:00. As you can see the local time has lost an hour (due to daylight saving time ending) so if I was to display this, it would say it's the same day as the day it's just added a day to. However if i was to say:
date.AddDaysToLocal(1).LocalTime.ToString();
I would get back 27/10/2003 00:00:00 and the time is preserved. This looks correct to me but it goes against the best practice to add to the universal time.
I'd appreciate it if someone could help clarify what's the correct way to do this. Please note that I have looked at Noda Time and it's currently going to take too much work to convert to it, also I'd like a better understanding of the problem.
Both ways are correct (or incorrect) depending upon what you need to do.
I like to think of these as different types of computations:
Chronological computation.
Calendrical computation.
A chronological computation involves time arithmetic in units that are regular with respect to physical time. For example the addition of seconds, nanoseconds, hours or days.
A calendrical computation involves time arithmetic in units that humans find convenient, but which don't always have the same length of physical time. For example the addition of months or years (each of which have a varying number of days).
A calendrical computation is convenient when you want to add a coarse unit that does not necessarily have a fixed number of seconds in it, and yet you still want to preserve the finer field units in the date, such as days, hours, minutes and seconds.
In your local time computation, you add a day, and presuming a calendrical computation is what you intended, you preserve the local time of day, despite the fact that 1 day is not always 24 hours in the local calendar. Be aware that arithmetic in local time has the potential to result in a local time that has two mappings to UTC, or even zero mappings to UTC. So your code should be constructed such that you know this can never happen, or be able to detect when it does and react in whatever way is correct for your application (e.g. disambiguate an ambiguous mapping).
In your UTC time computation (a chronological computation), you always add 86400 seconds, and the local calendar can react however it may due to UTC offset changes (daylight saving related or otherwise). UTC offset changes can be as large as 24h, and so adding a chronological day may not even bump the local calendar day of the month by one. Chronological computations always have a result which has a unique UTC <-> local mapping (assuming the input has a unique mapping).
Both computations are useful. Both are commonly needed. Know which you need, and know how to use the API to compute whichever you need.
Just to add to Howard's great answer, understand that the "best practice" you refer to is about incrementing by an elapsed time. Indeed, if you wanted to add 24 hours, you'd do that in UTC and you'd find you'd end up on 23:00 due to there being an extra hour in that day.
I typically consider adding a day to be a calendrical computation (using Howard's terminology), and thus it doesn't matter how many hours there are on that day or not - you increment the day in local time.
You do then have to verify that the result is a valid time on that day, as it very well may have landed you on an invalid value, in the "gap" of a forward transition. You'll have to decide how to adjust. Likewise, when you convert to UTC, you should test for ambiguous time and adjust accordingly.
Understand that by not doing any adjusting on your own, you're relying on the default behavior of the TimeZoneInfo methods, which adjust backward during an ambiguous time (even though the usually desired behavior is to adjust forward), and that ConvertTimeFromUtc will throw an exception during an invalid time.
This is the reason why ZonedDateTime in Noda Time has the concept of "resolvers" to allow you to control this behavior more specifically. Your code is missing any similar concept.
I'll also add that while you say you've looked at Noda Time and it's too much work to convert to it - I'd encourage you to look again. One doesn't necessarily need to retrofit their entire application to use it. You can, but you can also just introduce it where it's needed. For example, you might want to use it internally in this DateTimeWithZone class, in order to force you down the right path.
One more thing - When you use SpecifyKind in your input, you're basically saying to ignore whatever the input kind is. Since you're designing general purpose code for reuse, you're inviting the potential for bugs. For example, I might pass in DateTime.UtcNow, and you're going to assume it's the timezone-based time. Noda Time avoids this problem by having separate types instead of a "kind". If you're going to continue to use DateTime, then you should evaluate the kind to apply an appropriate action. Just ignoring it is going to get you into trouble for sure.

Converting DateTimes that are near DayLight Savings time?

I'm working on software that runs reports for GPS devices that are running 24/7/365. Part of the report output requires that we convert our stored database times (kept in Central Standard Time) to user timers (any requested time zone). Twice a year we run into an issue with DST when people run reports that start before and finish after the time change. It fails at one line:
return TimeZoneInfo.ConvertTime(dateToConvert, DatabaseTime, UserTime);
dateToConvert is a DateTime to be converted. DatabaseTime and UserTime are both TimeZoneInfo objects. I'm not doing anything tricky or complicated but DateTimes near the DST time change throw exceptions. Such as 3/10/2013 2:02:11 AM even though it's being "converted" from Central Time to Central Time.
What is the best method for handling DateTimes near DST time changes?
You have garbage in your database, 3/10/2013 2:02:11 AM never existed. The minute after 1:59 AM that morning was 3:00 AM, the clock was moved by an hour. .NET is not going to put up with that junk date.
You will need to find out how that garbage timestamp ended up in your dbase. Clearly a conversion of a time from one timezone to another that disregards daylight savings rules, like active in one but not the other, is a highly likely source of that garbage. If you can't fix your dbase to use UTC then at least do it in your code. First going to UTC in the one timezone and then back to local time in the other. Use the TimeZoneInfo class, ConvertTimeFrom/ToUtc methods.
I ran into this problem. I fixed it by adding a new GMT time column. This allowed the application to work with the original data and any fixes to work with GMT. Then I changed the application so that any code that was having problems with daylight savings would access this new column. Also, as time went on, I re-pointed any code that was used for calculation to this new column leaving the displays to work with the old column. It's not elegant, but it works and it is easy.
Conversion should work properly as the time is not truly junk, as Hans stated, rather it is just non-adjusted (a term I just invented). 3/10/2013 2:02:11 AM CDT == 3/10/2013 8:02:11 AM UTC == 3/10/2013 3:02:11 AM CDT...they are ALL semantically equivalent. If you do not believe me, do the conversion at timeanddate.com and see they all equate (round to nearest 5 minutes for their calculator though). Whether .NET code will allow this semantic equivalence, I have not tried it because I am not in front of my dev box currently.
UPDATE #1:
Run the following code on a computer set to CST time zone:
using System;
namespace TimeZoneSample
{
public static class Program
{
public static void Main()
{
DateTime t = DateTime.Parse("3/10/2013 2:02:11 AM");
Console.WriteLine(t);
Console.WriteLine(t.ToUniversalTime());
Console.WriteLine(t.ToUniversalTime().ToLocalTime());
}
}
}
This yields the following console output:
3/10/2013 2:02:11 AM
3/10/2013 8:02:11 AM
3/10/2013 3:02:11 AM
Proof that my original explanation is correct. quod erat demonstrandum
I would follow one of the other answers if that's at all possible - you want to fix this properly. If your time is incorrect during the fall transition it won't generate an exception, it's just going to randomly be an hour off.
There's a workaround to get you out of your current jam. Since it's only the missing hour during the spring that will cause the exception, you can catch the exception and add an hour into the time before repeating the conversion.

if displaying HH:MM:SS as HH:MM, better to truncate seconds or round to nearest minute?

Is there a standard or accepted best practice for how times should be displayed as HH:MM when the source time has HH:MM:SS precision? Should seconds be truncated or rounded to the nearest minute?
Socially, if I looked at a digital clock and saw that it was 4:00:45, I would never tell someone it was 4:01. But I didn't know if this convention is universal or if it applies in computing too.
Also, rounding to the nearest minute might produce unexpected behavior, e.g. if the rounding causes the hour or date to change. This doesn't necessarily apply to the particular use-case we're dealing with today, but I can easily imagine another use case where a list of "Sales in January" includes a sale on 31-Jan 23:59:59 that would be displayed as 1-Feb 00:00
If context is relevant to the answer, this use-case is a SQL Server app that converts a datetime to a smalldatetime, which SQL Server will round to the nearest minute. The result will be displayed as HH:MM in a C# web application. The conversion happens in legacy code that we can't change right now, but we can force truncation of seconds instead of rounding.
But I'm not sure if we should do this.
In general with dates and times it's best to round down.
To me "1 week ago" means "at least 7 days, but less than 14 days". A similar idea applies to times.
Unless it's critical for ordering of the parent object I really wouldn't bother. If you don't need the seconds; they can be considered low-priority. I'd personally round it because I like the precision, even if fractal.
If you're aware that it can cause unexpected behaviour; whomever interprets the data should account for it - but you can make it easier on them by adding a note in your code that it can cause this so that they are aware.

Difference in usage of DateTime.Now vs DateTime.UtcNow

As this Question's Answer from hightechrider mentions that code block as below is more right
var start = DateTime.Parse("08/10/2011 23:50:31").Utc;
if(start.AddMinutes(20) > DateTime.UtcNow)
then using as this by TimeSpan
var start = DateTime.Now;
var oldDate = DateTime.Parse("08/10/2011 23:50:31");
if(start - oldDate).TotalMinutes >= 20)
Here since the DateTime is executed and also parsed in the same culture then, How it will make difference ??
I am feeling very Phoney by this answer.
In a nutshell: UTC is a continuous, single-valued time scale, whereas local time is not continuous or single-valued. The primary reason is Daylight Savings Time, which doesn't apply to UTC. So UTC never jumps forward or back an hour, whereas local time does. And when it jumps backward, the same time value occurs twice.
Making comparisons is best done using the continuous, single-valued time scale, unless you want to mess around with DST yourself. Even if you do, there is no way to distinguish between the first and second "2am" when Daylight Savings Time ends and the clocks are set back an hour.
Technical note: even though UTC is continuous, it does have the occasional extra leap second inserted to keep up with the slowing down of the Earth's rotation. Those seconds are usually added at the end of the day and are listed with 60 seconds. So you'd have 23:59:59, 23:59:60, 00:00:00.
The United States transitions from Daylight Savings Time to Standard Time at 2AM on November 6th, 2011. If, at 2:10AM, I ask how far in the past 1:50AM was, .NET will tell me 20 minutes. In truth, it was an hour and 20 minutes, since we set our clocks back an hour at 2AM. I won't run into these issues if I use UTC - libraries like the .NET Framework have all the logic needed to correctly deal with discontinuities like this.
The whole Daylight Savings Time scheme is a mess, and it's hard for anyone whose country, like yours, (sensibly) doesn't implement it, to understand the issues that arise. It gets even more interesting when governments start changing the switchover days around.

C# - calculate if a date is six months older

I am trying to calculate if the given specified date is at least six months old. I am doing this:
if(DateTime.Now.AddMonths(-6)>date)
{
//Do something
}
Is this correct?
Some people say that this approach is wrong and will not give accurate results. Is the above is correct?
"6 months" is not a precise amount of time. It depends on the length of the months. In particular, you may well get different results from your calculation compared with date.AddMonths(6) < DateTime.Now. (Consider adding 6 months from August 30th vs taking away 6 months from February 28th... You may be okay, but you need to think about this carefully.)
You need to consider a few things carefully:
You're currently using DateTime.Now instead of DateTime.Today; how do you want the current time of day to affect things?
Is the "kind" of date UTC, unspecified or local? It makes a difference - DateTime is confusing, unfortunately.
How do you want to handle situations like the ones in the first paragraph?
Ultimately, if people are telling you it will not give accurate results, you should ask them for specific examples - you need to get a wealth of input data and desired results, add automated tests for them, and get them to pass. Then if anyone claims your code isn't working correctly, you should be able to challenge them to create another test case which fails, and justify their decision.
If you are only concerned about the date and not the time, use DateTime.Now.Date instead. Apart from that, I do not see any problems with the code you already have.

Categories

Resources