How to escape trial go-around with system time change? - c#

Hi have an application offering a 30 days trial. When installed, I am adding a registry key with the current DateTime.Now value.
installDate = DateTime.Now;
RegistryKey regKeyAppRoot = Registry.CurrentUser.CreateSubKey(registryKeyPath);
regKeyAppRoot.SetValue("InstallDate", installDate);
Whenever the application is started, I load the value from the registry and compare it to the current DateTime.Now value again and obviously depending on the result of the comparison I show appropriate messages.
RegistryKey regKeyAppRoot = Registry.CurrentUser.CreateSubKey(registryKeyPath);
installDate = (DateTime)regKeyAppRoot.GetValue("InstallDate");
if (installDate.AddDays(30) > DateTime.Now)
; //MessageBox.Show(...)
My problem is that a simple change of the system time (to the past) would just allow the usage of the application again as the condition will no longer be met. That is explicable as the DateTime.Now property gets a DateTime object that is set to the current date and time on this computer, expressed as the local time.
How can I escape that and get the exact number of days since when my application was installed?

You could save the date of the last check and compare the current date. If they are on different days, then increment a counter. In this way the user has "at most" 30 day uses.
So...
DateTime lastCheck = ... // Recover it from the registry
DateTime now = DateTime.Now.Date;
if (now != lastCheck.Date)
{
UsesCounter++;
}
lastCheck = now;
I'll add that normally it's a little better to use UtcNow, not Now, in this way you are safe from Daylight Time changes.
Another option is to use an Internet clock :-) There are many sites that give the exact time (this option is good only if your program normally connect to Internet)

One simple approach would be to save the date and time each time the program is started and quit. The next start compares the current date and time to the saved one. If it is less than the saved one, your application refuses to start.
This certainly wouldn't completely remove that problem, but it would make it harder for the user, because he would need to know what date and time he needs to set his computer to.

If you save time, when your application ended, you can check that current time is greater than ended time

Related

Convert time data to local time in C#

I've read a few posts about similar subjects but nothing seems to answer this question. My database has the following information about a time
Day of the week (a number between 0-6)
Time (a number of milliseconds since midnight in the users local time)
UTC offset ( number of hours different to UTC )
DST Observed (boolean stating if DST is observed in that time zone)
This data represents opening hours. So there is a time for each day. I want to display that time in the users local time making the assumption that each day is in the future
int dayOffset = availability.Day - (int)now.DayOfWeek
if (dayOffset < 0)
dayOffset += 7;
I'm really struggling to get my head around time zones and handling when one time zone might be observing DST while another maybe DOES observe DST but hasn't yet.
My main issue at the moment is I think I need to create a DateTimeOffset object for the non-local time but I'm not sure how to do that as I don't know if DST is in effect or not.
I hope I'm making myself clear. It really is a mind-bending experience working with dates and time!
As indicated by other answers, the usual solution to handling DateTime across time zones would be to store UTC times.
However, considering that you are not referencing an absolute time at a specific date, but instead are referring to a time at an infinite number of days in a specific time zone; storing the time as an UTC time doesn't make sense anymore, since the UTC time (even if we discard the date) would be different depending on the date, due to DST.
The best way to store the time is fairly close to what you have done already.
Your problem is that the time zone information you are storing at the moment is ambiguous, as it does not refer to a specific time zone, but instead refers to properties of the time zone.
To solve this problem, simply store the time zone identifier instead of the UTC offset and DST boolean.
It is now possible for us to construct the DateTime object and convert it to any time zone by using the TimeZoneInfo class:
int dayOffset = availability.Day - (int)DateTime.Today.DayOfWeek;
if (dayOffset < 0)
{
dayOffset += 7;
}
var openingHourStart = DateTime
.SpecifyKind(DateTime.Today, DateTimeKind.Unspecified)
.AddDays(dayOffset)
.AddMilliseconds(availability.Time);
var sourceTimeZone = TimeZoneInfo.FindSystemTimeZoneById(availability.TimeZoneId);
var userTimeZone = TimeZoneInfo.Local;
var convertedOpeningHourStart = TimeZoneInfo.ConvertTime(openingHourStart,
sourceTimeZone,
userTimeZone);
Give a try to Quartz.NET.
It implements evaluation of CronExpressions, and even triggers to fire events at the given time. It can evaluate the next time an event will occur. This may help you out calculating the opening times.
Also, take a look at the cronmaker website: there you can understand the full potential of CronExpressions.
The CronExpressionDescriptor is a DotNET library for transforming CronExpressions into human readable strings.
Another library which I haven't tried yet is [HangFire].(https://www.hangfire.io/)
In this forum post you can find some discussion on how HangFire implements evaluation of RecurringJobs in local timezone with DST, which I believe is a solution for what you are looking for.
A comment to another answer made the problem a little bit more clear.
So, first and foremost, do store only UTC in your database. Really.
Now, since you are not interested in the actual dates, since you are storing working schedules that repeat weekly, the date only becomes relevant once you want to present your times - and when you put them in your database.
So let's first see how you get your times into your database correctly. I'm assuming a user will enter times in their own locale.
Make sure you first create a (localised) DateTime consisting of the current date and the given time (from the user), and transform that to a UTC DateTime (you can keep the current date, it doesn't matter):
var utcDateTime = DateTime.Now.Date
.AddHours(userHours)
.AddMinutes(userMinutes)
.ToUniversalTime();
Now when you are presenting these times to the user, simply go the other way:
var userDateTime = DateTime.Now.Date
.AddHours(utcDateTime.Hour)
.AddMinutes(utcDateTime.Minute)
.ToLocalTime();
And then you can use the userDateTime.Hour and .Minute for display purposes.
You should be leveraging DateTime.ToLocalTime() and TimeZoneInfo.ConvertTimeToUtc() in C# - see https://msdn.microsoft.com/en-us/library/system.datetime.tolocaltime(v=vs.110).aspx.
If you want to store only times that you're open from Monday to Sunday, fine. Have a simple data table to describe only the time for each day (0 = Sunday through 7 = Saturday -- this is .Net's DayOfWeek enumeration). Your lookup table might look like:
0 null
1 08:00:00
2 08:00:00
3 08:00:00
4 08:30:00
5 08:30:00
6 10:30:00
(Use whatever data type works for you--SQL Server 2008+ has a TIME data type, for example. Null can be used for Closed on that day--i.e., no open time.)
When it comes time to display YOUR time to any other user, use must create your UTC time on-the-fly at the moment you are displaying information to the local user.
Conyc provided one approach. My approach uses simple date/time strings. To use my approach, just store time values per day in your database. Then you can look up the open time for any given day. To express that time for another user in any locale, use this code to convert your time to UTC (you can substitute the "08:00:00 AM" string value with a string variable that you populated after looking up the open time in your database):
var StoreOpenTimeInUtc = TimeZoneInfo.ConvertTimeToUtc(Convert.ToDateTime("08:00:00 AM"));
To look up the open time in your database for a particular day in the future, you will need to concatenate the date to your time value, like this:
var StoreOpenTimeInUtc = TimeZoneInfo.ConvertTimeToUtc(Convert.ToDateTime("04/28/2018 08:00:00 AM"));
Once you have an accurate StoreOpenTimeInUtc variable, you can use that as the UTC value on someone else's machine who is anywhere else on planet earth. To convert that UTC value to their local time, use the .NET ToLocalTime() method:
var OpenTimeForLocalUser = StoreOpenTimeInUtc.ToLocalTime();
Note that this approach requires you to store only the open times as shown above. You don't have to worry about dates, local offsets from UTC, or anything else. Just leverage ConvertTimeToUtc() and ToLocalTime() as shown.

DateTime.Now and Culture/Timezone specific

Our application was designed to handle user from different Geographic location.
We are unable to detect what is the current end user local time and
time zone operate on it. They select different culture like sv-se,
en-us, ta-In even they access from Europe/London timezone..
We hosted it in a hosting server in US, application users are from Norway/Denmark/Sweden/UK/USA/India
The problem is we used DateTime.Now to store the record created/updated date, etc.
Since the Server runs in USA all user data are saved as US time :(
After researching in SO, we decided to stored all history dates in DB as DateTime.UtcNow
PROBLEM:
There is a record created on 29 Dec 2013, 3:15 P.M Swedish time.
public ActionResult Save(BookingViewModel model)
{
Booking booking = new Booking();
booking.BookingDateTime = model.BookingDateTime; //10 Jan 2014 2:00 P.M
booking.Name = model.Name;
booking.CurrentUserId = (User)Session["currentUser"].UserId;
//USA Server runs in Pacific Time Zone, UTC-08:00
booking.CreatedDateTime = DateTime.UtcNow; //29 Dec 2013, 6:15 A.M
BookingRepository.Save(booking);
return View("Index");
}
We want to show the same history time to the user who logged in in India/Sweden/USA.
As of now we are using current culture user logged in and choose the timezone from a config file and using for conversion with TimeZoneInfo class
<appSettings>
<add key="sv-se" value="W. Europe Standard Time" />
<add key="ta-IN" value="India Standard Time" />
</appSettings>
private DateTime ConvertUTCBasedOnCulture(DateTime utcTime)
{
//utcTime is 29 Dec 2013, 6:15 A.M
string TimezoneId =
System.Configuration.ConfigurationManager.AppSettings
[System.Threading.Thread.CurrentThread.CurrentCulture.Name];
// if the user changes culture from sv-se to ta-IN, different date is shown
TimeZoneInfo tZone = TimeZoneInfo.FindSystemTimeZoneById(TimezoneId);
return TimeZoneInfo.ConvertTimeFromUtc(utcTime, tZone);
}
public ActionResult ViewHistory()
{
List<Booking> bookings = new List<Booking>();
bookings=BookingRepository.GetBookingHistory();
List<BookingViewModel> viewModel = new List<BookingViewModel>();
foreach (Booking b in bookings)
{
BookingViewModel model = new BookingViewModel();
model.CreatedTime = ConvertUTCBasedOnCulture(b.CreatedDateTime);
viewModel.Add(model);
}
return View(viewModel);
}
View Code
#Model.CreatedTime.ToString("dd-MMM-yyyy - HH':'mm")
NOTE: The user can change the culture/language before they login. Its a localization based application, running in US server.
I have seen NODATIME, but I could not understand how it can help with multi culture web application hosted in different location.
Question
How can I show a same record creation date 29 Dec 2013, 3:15 P.M for the users logged in INDIA/USA/Anywhere`?
As of now my logic in ConvertUTCBasedOnCulture is based user logged in culture. This should be irrespective of culture, since user can login using any culture from India/USA
DATABASE COLUMN
CreatedTime: SMALLDATETIME
UPDATE: ATTEMPTED SOLUTION:
DATABASE COLUMN TYPE: DATETIMEOFFSET
UI
Finally I am sending the current user's local time using the below Momento.js code in each request
$.ajaxSetup({
beforeSend: function (jqXHR, settings) {
try {
//moment.format gives current user date like 2014-01-04T18:27:59+01:00
jqXHR.setRequestHeader('BrowserLocalTime', moment().format());
}
catch (e) {
}
}
});
APPLICATION
public static DateTimeOffset GetCurrentUserLocalTime()
{
try
{
return
DateTimeOffset.Parse(HttpContext.Current.Request.Headers["BrowserLocalTime"]);
}
catch
{
return DateTimeOffset.Now;
}
}
then called in
model.AddedDateTime = WebAppHelper.GetCurrentUserLocalTime();
In View
#Model.AddedDateTime.Value.LocalDateTime.ToString("dd-MMM-yyyy - HH':'mm")
In view it shows the local time to user, however I want to see like dd-MMM-yyyy CET/PST (2 hours ago).
This 2 hours ago should calculate from end user's local time. Exactly same as stack overflow question created/edited time with Timezone display and local user calculation.
Example: answered Jan 25 '13 at 17:49 CST (6 hours/days/month ago) So the other viewing from USA/INDIA user can really understand this record was created exactly 6 hours from INDIA/USA current time
Almost I think I achieved everything, except the display format & calculation. How can i do this?
It sounds like you need to store a DateTimeOffset instead of a DateTime. You could just store the local DateTime to the user creating the value, but that means you can't perform any ordering operations etc. You can't just use DateTime.UtcNow, as that won't store anything to indicate the local date/time of the user when the record was created.
Alternatively, you could store an instant in time along with the user's time zone - that's harder to achieve, but would give you more information as then you'd be able to say things like "What is the user's local time one hour later?"
The hosting of the server should be irrelevant - you should never use the server's time zone. However, you will need to know the appropriate UTC offset (or time zone) for the user. This cannot be done based on just the culture - you'll want to use Javascript on the user's machine to determine the UTC offset at the time you're interested in (not necessarily "now").
Once you've worked out how to store the value, retrieving it is simple - if you've already stored the UTC instant and an offset, you just apply that offset and you'll get back to the original user's local time. You haven't said how you're converting values to text, but it should just drop out simply - just format the value, and you should get the original local time.
If you decide to use Noda Time, you'd just use OffsetDateTime instead of DateTimeOffset.
Standard approach is to always store any time data as UTC if particular moment in time is important. That time is not impacted by time zone changes and cultures.
Most common approach to showing time with time zone is to store time as UTC and convert to current user's culture/time zone combination when you display the value. This approach only requires single date time filed in the storage.
Note that for Web cases (like ASP.Net) you may need to figure out user's culture/time zone first and send it to server (as this information is not necessary available on GET requests) or do formatting of time in the browser.
Depending what "show the same history time" you may need to store additional information like current culture and/or current offset. If you need to show time exactly as original user seen it you may also save string representation (because formats/translations can change later and value will look different, also it is unusual).
Note: culture and time zone are not tied together, so you'll need to decide how you need to handle cases like IN-IN culture in US PST time zone.
I'm a little confused by the phrasing of your question, but it appears that you would like to determine the time zone of your user.
Have you tried asking them? Many applications have the user pick their time zone in user settings.
You could pick from a drop-down list, or a pair of lists (country, then time zone within the country), or from a map-based time zone picker control.
You could take a guess and use that as the default unless your user changes it.
If you go down that route, you will need to be able to use IANA/Olson time zones, which is where Noda Time comes into play. You can access them from DateTimeZoneProviders.Tzdb.
The hosting location is irrelevant if you are using UTC. That's a good thing.
Also, if you're using Noda Time, then you probably should use SystemClock.Instance.Now instead of DateTime.UtcNow.
See also here and here.
Also - an alternative solution would be just to pass the UTC time to the browser and load it into a JavaScript Date object. The browser can convert that to the user's local time. You could also use a library like moment.js to make this easier.
Update
Regarding your approach of mapping culture codes to time zones:
<appSettings>
<add key="sv-se" value="W. Europe Standard Time" />
<add key="ta-IN" value="India Standard Time" />
</appSettings>
That will not work, for several reasons:
Many people use a different culture setting on their computer than the area that they are physically in. For example, I might be an a US-English speaker living in Germany, my culture code is likely still en-US, not de-DE.
A culture code containing a country is used to distinguish between dialects of a language. When you see es-MX, that means "Spanish, as spoken in Mexico". It does not mean that the user is actually in Mexico. It just means that user speaks that dialect of Spanish, as compared to es-ES which means "Spanish, as spoken in Spain".
Even if the country portion of the culture code could be reliable, there are many countries that have multiple time zones! For example, what would you put in your mapping list for en-US? You can't just assume that we are all on Eastern Standard Time.
Now, I've explained why your current approach won't work, I strongly suggest you take my original advice. Very simply:
Determine the time zone of the user, preferably by asking them, perhaps with some assistance by one of the utilities I linked to above.
You're storing UTC, so just convert to that time zone for display.
Using Microsoft Time Zones
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time");
DateTime localDatetime = TimeZoneInfo.ConvertTimeFromUtc(yourUTCDateTime, tz);
Using IANA Time Zones and Noda Time
DateTimeZone tz = DateTimeZoneProviders.Tzdb["Europe/Stockholm"];
Instant theInstant = Instant.FromDateTimeUtc(yourUTCDateTime);
LocalDateTime localDateTime = theInstant.InZone(tz);
We faced a similar problem with an application I worked on recently. During development every one was in the same time zone and the issue wasn't noticed. And in any case there was a lot of legacy code that would have been a pain to change not to mention converting all the date time info that was already in the DB. So changing to DateTimeOffset was not an option. But we managed to get it all consistent by converting from server time to user time on the way out and converting from user time to server time on the way in. It was also important to do this with any date time comparisons that were a boundary. So if a user expected some thing to expire midnight their time then we would convert that time to server time and do all comparisons in server time. This sounds like a lot of work but was much less work then converting the entire application and DB to use DateTimeOffsets.
Hear is a thread that looks like has some good solutions to the time zone issue.
Determine a User's Timezone
If you want to show consistent date/time history to the user, regardless of the locale they are viewing the history from, then:
During Save, store not only UTC "creation" date/time, but also the detected locale
Use stored saved from locale to compute original date/time and emit a string to display (i.e. do not use current user locale when you're diplaying it)
If you don't have the ability to amend your storage, then perhaps you can change your submit to send the "current client time", store it literally (do not convert to UTC) and then display literally (do not convert to detected culture)
But as I say in my comment under your question, I am not certain I got your requirements right.

Representation of a DateTime as the local to remote user

Hello!
I was confused in the problem of time zones. I am writing a web application that will contain some news with dates of publication, and I want the client to see the date of publication of the news in the form of corresponding local time. However, I do not know in which time zone the client is located.
I have three questions.
I have to ask just in case: does DateTimeOffset.UtcNow always returns the correct UTC date and time, regardless of whether the server is dependent on daylight savings time? For example, if the first time I get the value of this property for two minutes before daylight savings time (or before the transition from daylight saving time back) and the second time in 2 minutes after the transfer, whether the value of properties in all cases differ by only 4 minutes? Or here require any further logic? (Question #1)
Please see the following example and tell me what you think.
I posted the news on the site. I assume that DateTimeOffset.UtcNow takes into account the time zone of the server and the daylight savings time, and so I immediately get the correct UTC server time when pressing the button "Submit". I write this value to a MS SQL database in the field of type datetime2(0).
Then the user opens a page with news and no matter how long after publication. This may occur even after many years. I did not ask him to enter his time zone. Instead, I get the offset of his current local time from UTC using the javascript function following way:
function GetUserTimezoneOffset()
{
var offset = new Date().getTimezoneOffset();
return offset;
}
Next I make the calculation of the date and time of publication, which will show the user:
public static DateTime Get_Publication_Date_In_User_Local_DateTime(
DateTime Publication_Utc_Date_Time_From_DataBase,
int User_Time_Zone_Offset_Returned_by_Javascript)
{
int userTimezoneOffset = User_Time_Zone_Offset_Returned_by_Javascript; // For
// example Javascript returns a value equal to -300, which means the
// current user's time differs from UTC to 300 minutes. Ie offset
// is UTC +6. In this case, it may be the time zone UTC +5 which
// currently operates summer time or UTC +6 which currently operates the
// standard time.
// Right? (Question #2)
DateTimeOffset utcPublicationDateTime =
new DateTimeOffset(Publication_Utc_Date_Time_From_DataBase,
TimeSpan.Zero); // get an instance of type DateTimeOffset for the
// date and time of publication for further calculations
DateTimeOffset publication_DateTime_In_User_Local_DateTime =
utcPublicationDateTime.ToOffset(new TimeSpan(0, - userTimezoneOffset, 0));
return publication_DateTime_In_User_Local_DateTime.DateTime;// return to user
}
Is the value obtained correct? Is this the right approach to solving this problem? (Question #3)
UPDATED Oct 19 at 6:58 (I tried post it as a comment but it's too long by 668 characters)
Matt Johnson, Thank You for such a detailed answer despite that of the fact that you are doing this not the first time. Thank you for taking the time to explain this particular case, and not just provide links to other posts.
I have read the information that you have provided. Maybe I'm still not fully aware of all the details, but if I understand it right, for the right convertion of DateTime (which was written many years ago in the database) from UTC to the same user's moment, I need to know UTC offset which he had at that moment. And it is difficult taking into account that transfer rules for DST change constantly. And even now, though the platform ".NET" contains some TZDB that is used for the TimeZoneInfo type, I can't take advantage of it without the exact position of the user.
But what if I am only interested in the date and time of starting this year, and only in Russia, where DST was canceled in 2011? As I understand it, this means that if properly configured clock on user's computer, located in Russia, this approach will always give the correct result. And since 2011, the offset to UTC of user's clock should always be the same. Accordingly, the shift indicators in different browsers will not be different for the Russian user's.
Answer to Question 1
... does DateTimeOffset.UtcNow always returns the correct UTC date and time, regardless of whether the server is dependent on daylight savings time?
Yes. As long is your clock is set correctly, UtcNow always refers to the UTC time. The time zone settings of the server will not affect it. The value in your example will always be 4 minutes, regardless of DST.
Answer to Question 2
var offset = new Date().getTimezoneOffset();
Since new Date() returns the current date and time, this will return you the current offset. You then proceed to apply this current offset to some past value, which may or may not be the correct offset for that specific time. Please read the timezone tag wiki, especially the section titled "Time Zone != Offset".
Answer to Question 3
Is the value obtained correct? Is this the right approach to solving this problem?
No. This is not the correct approach. You have a few options:
First Option
Just pass the UTC value to JavaScript without modification.
Send it in ISO8601 format, such as 2013-10-18T12:34:56.000Z. You can get this in .Net easily using yourDateTime.ToString("o").
Be sure the DateTime you are starting with has .Kind == DateTimeKind.Utc, otherwise it won't get the Z on the end, which is essential.
If you are targeting older browsers that can't parse ISO8601, then you will need a library such as moment.js to parse it for you.
Alternatively, you could pass the number of milliseconds since 1/1/1970 UTC as a number and load that into a JavaScript Date instead of parsing.
Now you can just display the Date object using JavaScript. Let the browser convert it from UTC to the users local time.
Warning, with this approach, some conversions might be incorrect due to the problem I describe here.
Second Option
Like the first option, pass the UTC timestamp to JavaScript
Use that to get the offset for that timestamp.
Pass the offset back to the server in a postback or ajax call.
Apply the offset on the server
Output the local time zone
I don't particularly like this option because of the round trip. You might as well calculate it in JavaScript like the first option.
Third Option
Get the user's time zone. The best way is to ask them for it, usually on a user setting page.
Use it to convert from the UTC time to their local time completely on the server.
You can use Windows time zones and the TimeZoneInfo class to do the conversions.
Or you can use IANA/Olson time zones and the Noda Time library.
If you do this, you can optionally use a map-based timezone picker.
You can take a guess at the user's time zone with jsTimeZoneDetect.
This approach is more accurate, but requires more user interaction.
Also, please in future posts, ask just one question at a time. And please search before you post - I've written most of this in one form or another many times before.

How to determine if it has been 60-days or not by comparing DateTime?

To provide a TRIAL period to my application when the user first runs the application I save the FirstRunTime like this:
string sFirstRunDate = DateTime.Today.ToShortDateString();
saveInfo.saveFirstRun(sFirstRunDate ); // saves as a string to a text file
Now everytime I run the application I want to see if it has been more then 60 days and if so terminate (60-day trial only). How can I do that compare?
string sFirstRunDate = saveInfo.getFirstRun(); // returns the string I saved earlier
DateTime dtFirstRunDate = DateTime.Parse(sFirstRunDate); // makes it a DateTime
DateTime now = DateTime.Today.ToShortDateString(); // why am I doing this?
So how can I take the two dates and compare them to see if it has been more then 60 days or not?
Thanks,
The following should do it:
var elapsed = DateTime.Today.Subtract(dtFirstRunDate);
if (elapsed.TotalDays > 60)
{
// trial expired
}
The advantage of this is when the trial hasn't expired you can tell them how far they are into their trial (using elapsed.TotalDays).
TimeSpan t = DateTime.Now.Subtract(dtFirstRunDate);
if (t.Days > 60)
{
//do something
}
Try
if(DateTime.Parse(sFirstRunDate).AddDays(60) < DateTime.Now) {
// trial has expired
}
This just takes the first run, adds 60 days to it, if the current time is greater than the time first run + 60 days, the trial is over.
All other answers are technically going to work for you, but they are wrong on a larger scale. Please read further.
// why am I doing this?
This tells me that you do not quite grasp the concepts you're trying to apply. Let's go one by one.
string sFirstRunDate = DateTime.Today.ToShortDateString();
There are two problems with that. First the DateTime.Today returns the local date/time. Never ever use local date/time for any kind of calculations because local time is not consistent. Daylight changes, travel through time zones, all affect the local time that is returned by this property. What you should use instead is DateTime.UtcNow.Date to get the current UTC time which is the global clock not affected by any of the aforementioned problems.
Second problem is the ToShortDateString method. It converts the date/time using current culture. Did you know that in other parts of the world, the date is reported as 'DD/MM/YYYY', or 'YYYY-MM-DD'? What will happen if the user changes current locale? To avoid those problems you should use the ToString(CultureInfo.InvariantCulture) method.
The correct code to serialize the first run date is
string sFirstRunDate = DateTime.UtcNow.Date.ToString(CultureInfo.InvariantCulture);
DateTime now = DateTime.Today.ToShortDateString(); // why am I doing this?
To calculate the difference between two dates, first you need to acquire those two dates. The first one would be the saved first run date, and the second would be today. You did the first part by deserializing the first run date into DateTime structure. For the second part you just need the current date, you don't need to serialize it into string. So
DateTime today = DateTime.UtcNow.Date;
Now that you have two dates, you have an array of options on how to actually get the difference. Any of the other answers do that part just fine. I personally like Timothy Walters' answer as it has a nice side effect of giving your the days left for trial. It will look like:
DateTime dtFirstRunDate = DateTime.Parse(saveInfo.getFirstRun());
DateTime today = DateTime.UtcNow.Date;
var elapsed = today.Subtract(dtFirstRunDate);
if (elapsed.TotalDays > 60)
{
// trial expired
}

Does Daylightsaving time cause DateTime calculations to become negative

We are currently rewritting the core of our services, basically we have scheduled tasks that can run on intervals, dates, specific times etc etc etc.
Currently we're wondering if daylightsaving might cause trouble for us, basically we calculate the next possible runtime, based on what days the task should execute and between what times, and what interval. We do this by taking the current time, and adding days/minutes/hours to this DateTime.
We then take this new run time and subtract DateTime.Now from this DateTime, leaving us with the timespan untill the next run.
How ever, what if the current time is 01:50 on a daylightsavings day, we add 20 minutes, which is our set interval, and end up with a time of 02:10, how ever since this is daylightsavinds, it's actually 01:10.
When i subtract the current time (01:50) from the 01:10 (which is actually 02:10) does this return a negative value which i need to work around or does this never ever return a negative value because DateTime is just a long underneath holding the proper information?
Basically, the following code, is the check needed or not?
//Get interval between nextrun and right now!
double interval = (NextRun - DateTime.Now).TotalMilliseconds;
//Check if interval is ever less or equal to 0, should never happen but maybe with daylight saving time?
if(interval <= 0)
{
//Set default value
interval = IntervalInMilliseconds;
}
We believe that this check isn't needed but our googling so far hasn't given us a definative answer.
Use DateTime.UtcNow instead of DateTime.Now EVERYWHERE
First of all, you can try it yourself as it will help you understand how it works.
Essentially, using your example above, if you have 20 minutes to a local time, it would be 2:10 and not 1:10 as the computation is done in local time. If you want to get 1:10, you need to convert local time to universal time, add 20 minutes and then convert back to local time.
If you want real elapsed time, then you have to convert time to universal time before computing time difference. Also, if you work in local time, you won't be able to differentiate ambiguous time when the clock goes back.

Categories