Convert to datetimeoffset from SQL query to local time based on TimeZoneInfo - asp.net

For whatever silly reason, I remain confused when dealing with Timezones.
When a record is created, I use:
getutcdate()
So for example, it's stored in a datetimeoffset column and looks like this:
2015-07-03 20:44:21.0300000 +00:00
So no offset, just raw UTC.
Now, in server code, I want to do a few things... I have a query that gets me just the CreatedDate for articles posted for a particular user. I'm storing this in a datatable:
Dim tz as TimeZoneInfo = GetUserTZInfo(User)
Dim dt as DataTable = GetArticleDates(User)
Dim MaxArticles As Integer = 5
Dim PostedThisMonth As Integer
Dim Remaining As Integer
I'm limited the user to 5 articles posted per/month, so you can see where time can get shaky toward the beginning or end of the month based on the user's timezone. It's tomorrow somewhere, yet same moment in time everywhere.
But I want it to be user-friendly and just base it on the user, not server time.
I'm having difficulties using some of the examples on converting to local times because of my datatype of datetimeoffset
Could anyone suggest a best practice/method on how to achieve the following:
Search the dt for any created dates that are equal to the user's month.
Generate count for PostedThisMonth based on what's found.
The only sticky area like I said is at the beginning or end of the month... basically that 12 hour window, and then of course DST, but I'm less concerned with that.

Congratulations, you're ahead of most folks. You're doing it right by storing UTC times in your database and tracking the user's time zone with TimeZoneInfo.
If you never deviate from +00:00, you could store juse a datetime or datetime2 instead of a datetimeoffset, but it doesn't hurt anything and it has the added benefit of being unambiguously UTC.
All you really need to do is:
Use the user's time zone to convert the start and end of the user's local month to their equivalent UTC points in time.
Query your database using that range of values.
// compute the start of this month and the next month, by the user's time zone
Dim today As DateTime = TimeZoneInfo.ConvertTime(DateTime.UtcNow, tz).Date
Dim startDateOfThisMonth As DateTime = New DateTime(today.Year, today.Month, 1)
Dim startDateOfNextMonth As DateTime = startDateOfThisMonth.AddMonths(1)
// convert those to UTC
Dim startUtc As DateTime = TimeZoneInfo.ConvertTimeToUtc(startDateOfThisMonth, tz)
Dim endUtc As DateTime = TimeZoneInfo.ConvertTimeToUtc(startDateOfNextMonth, tz)
Or, since you're using datetimeoffset in your database, you could just build a DateTimeOffset in the last step. SQL will use the offset to convert to UTC internally when scanning the index.
Dim start As DateTimeOffset = New DateTimeOffset(startDateOfThisMonth,
tz.GetUtcOffset(startDateOfThisMonth))
Dim end As DateTimeOffset = New DateTimeOffset(startDateOfNextMonth,
tz.GetUtcOffset(startDateOfNextMonth))
When you query your database, use table.dto >= #start AND table.dto < #end (a half-open interval).

Related

Should I use DateTime UTC for an international application

I am coding a MVC 5 internet application that is being deployed to an Azure website. This application is going to be used internationally, and I am wanting to know if storing any DateTime values should use UTC time?
Here is an example: I have an object that has a start date time value as well as an end date time value. These values are set by a user and are used to determine if data should be shown to a user. If the current date time value is between the start date time and end date time, then data is shown.
Because my application is going to be used internationally, and there are different time zones, should I store the start date time value and end date time value as a DateTime object with UTC, or a standard DateTime value would be all that is needed? Do I need to worry about setting and displaying DateTime values for different time zones, or is this incorporated into the DateTime object?
Thanks in advance.
EDIT
How about when editing a DateTime that is stored as UTC.
If I have a DateTime that is stored as UTC in an object, and the user wants to change this value, do I need to convert the DateTime (that is displayed as .ToLocalTime()) back to a UTC DateTime when I store this value back in the database after it has been edited?
EDIT2
Can you have a quick look at these functions that I have coded to ensure the coding is correct?
public DateTime ConvertUTCDateTimeToLocalTime(DateTime utcDateTime)
{
DateTime convertedDate = DateTime.SpecifyKind(utcDateTime, DateTimeKind.Utc);
return convertedDate.ToLocalTime();
}
public DateTime ConvertLocalDateTimeToUniversalTime(DateTime localDateTime)
{
DateTime convertedDate = DateTime.SpecifyKind(localDateTime, DateTimeKind.Local);
return convertedDate.ToUniversalTime();
}
public DateTime ConvertUTCDateTimeToLocalTime(string utcDateTime)
{
DateTime convertedDate = DateTime.SpecifyKind(DateTime.Parse(utcDateTime.ToString()), DateTimeKind.Utc);
return convertedDate.ToLocalTime();
}
public DateTime ConvertLocalDateTimeToUniversalTime(string localDateTime)
{
DateTime convertedDate = DateTime.SpecifyKind(DateTime.Parse(localDateTime.ToString()), DateTimeKind.Local);
return convertedDate.ToUniversalTime();
}
In general, you should prefer to use DateTime.UtcNow in your backend. First advantage is that you don't have to care about timezones and second, you don't have to do any calculations for Daylight Saving Times (read more in this article). .NET gives you great capabilities where you don't have to care much about the two points mentioned above. On the other side, you should never display the UTC time in your frontend. This can annoy your users, but here come the capabilities of .NET into play. If you have an UTC date you can easily convert it local time for displaying it to your user in the following way:
DateTime convertedDate = DateTime.SpecifyKind(
DateTime.Parse(dateStr),
DateTimeKind.Utc);
DateTime dt = convertedDate.ToLocalTime();
The snippet is taken from Drew Noakes answer on this thread, which is a great discussion about how you can convert your dates to local time.
EDIT
Regarding your edit: Yes, you have to do this. Otherwise the date will be stored in local time.

How to match client time with server time in datepicker control in asp.net

I have two text boxes each having date_picker control. In one text box the date with time is automatically populating while loading the page.That time its taking the server Date
-time.And in second text box a user have to select the date-time but it is taking system time.And it is mismatching.
I want while user select a date-time its automatically convert to server time.How is it possible ? Can anyone say me ?
Are you looking for the server's time but the user's selected date? If so, consider the following:
C#
DateTime ServerDateTime = new DateTime();
ServerDateTime = DateTime.Now;
DateTime ClientDate = clientDateControl.Value;
DateTime AdjustedDateTime = new DateTime(ClientDate.Year, ClientDate.Month, ClientDate.Day, ServerDateTime.Hour, ServerDateTime.Minute, ServerDateTime.Second);
VB
Dim ServerDateTime As DateTime = New DateTime()
ServerDateTime = DateTime.Now
Dim ClientDate As DateTime = clientDateControl.Value
Dim AdjustedDateTime As DateTime = New DateTime(ClientDate.Year, ClientDate.Month, ClientDate.Day, ServerDateTime.Hour, ServerDateTime.Minute, ServerDateTime.Second)
Using this, you can either continue using the second date picker control and substitute its value for the ServerDateTime variable or you can remove the second date picker control as you already know the server datetime serverside.
Can't say I fully understand what you are trying to accomplish, but generally speaking this is what we have UTC for.
UTC is the global baseline date and time. Using javascript or whatever server side language it should be very simple to convert both dates to UTC and compare them.
Best of luck.

Is there a performance or storage difference to consider when using Date vs DateTime?

When using SQL Server & ASP.NET, is there a performance / storage consideration when using Date vs DateTime?
Even if I don't need it, I've been using DateTime for most things
DateTime takes 8 bytes per value
Date is 3 bytes.
I can't speak for low level performance; however in general we've found it a mistake to store values as DateTime by default. Sooner or later you run into the UTC issue and have to start working out offsets for dates that have 00:00:00.000 in the time portion!
If you're just storing dates I'd stick to the Date datatype; you'll fit more rows per page and save yourself a lot of hassle
Depends how many rows you're storing, and what you're using it for. Date is 3 bytes, DateTime is 8 bytes. Can quickly add up when you have billions of rows of data, or are using it for an index. Naturally there is a difference in the resolution of the value stored too. There are other date-types between date and datetime too such as smalldatetime that are more compact, again with different compromises.
SQL Date/Time Types Documentation
Considerations:
Performance: less bits for date-type means more rows per sql page (data page or index page) means less pages to be read while executing query
Compatibility: DATE type was introduced in SQL Server 2008, so your app it's not compatibile with SQL Server 2005 any more
.NET: no Date Class in .NET - DATE is converted into DateTime .NET Class
LINQ: LINQ2SQL (and SQL Metal tool) goes well with DATE SQL type
You may crop hours and minutes from DATETIME doing CAST(#myDateTimeParam AS DATE)
From my experience: I like this new type and had no problems with it while programming T-SQL or C#
Be aware of this (mixing data types for date on comparition):
DECLARE #startDay DATE = '2012-04-11' -- day
DECLARE #endDay DATE = '2012-04-13' -- day
DECLARE #eventTime DATETIME = '2012-04-13 12:00' -- point in time (noon)
IF #eventTime BETWEEN #startDay AND #endDay PRINT 'In period.' ELSE PRINT 'Not in period!'
Result is:
Not in period!
On BETWEEN comparition #endDay was casted down to DATETIME (to point in time; the common type with #eventTime), I guess - what gives unintuitive result.
Compare with:
DECLARE #startDay DATE = '2012-04-11' -- day
DECLARE #endDay DATE = '2012-04-13' -- day
DECLARE #eventTime DATE = '2012-04-13' -- day
IF #eventTime BETWEEN #startDay AND #endDay PRINT 'In period.' ELSE PRINT 'Not in period!'
Result:
In period.
And with it:
DECLARE #startDay DATETIME = '2012-04-11' -- day, but point in time in fact 00:00.000
DECLARE #endDay DATETIME = '2012-04-13' -- day, but point in time in fact 00:00.000
DECLARE #eventTime DATETIME = '2012-04-13' -- day, but point in time in fact 00:00.000
IF #eventTime BETWEEN #startDay AND #endDay PRINT 'In period.' ELSE PRINT 'Not in period!'
Result:
In period.

How to insert or update data in datetime datafield in mssql2005

I have a textbox which displays the date as 01-May-2011 but the database coumis in format of datetime ... how to enter date in date time column of database. ..
how to wite the sqlquery for this ?
You can convert that format to a DateTime like this
string dateString = "01-May-2011";
string format = "dd-MMM-yyyy";
var result = DateTime.ParseExact(dateString, format, CultureInfo.InvariantCulture);
if you're using LINQ to SQL or even ADO with a parameter of type DateTime, the conversion to a format that SQL understands will be done automatically for you.
If you're building the SQL by concatenating a string manually (not recommended!) you should try to reconvert to a string in the format 'yyyyMMdddd' (corrected as per AdaTheDev's comment, notice the single quotes). Other formats may or may not be recognized by sql depending on the language settings on both your client and your SQL Server
SQL Server is pretty good about taking in datetime values. If you pass the date as a parameter you can put quotes around it ('01-May-2011') and ignore the time. The database will automatically fill in a default time so that you don't have to worry about it.
Pass field value as nvarchar to database and use following to cast it to datetime.
Declare #dt nvarchar(20)
SET #dt = '01-May-2011'
select cast(#dt as datetime)
One thing to be aware of is that dates w/o time will be interpreted as May 1 2011 12AM. IE, without a time specified, SQL Server will always set the time to midnight. So if you have just the date as a field and you want records from May 1, you can't do
WHERE datefield = '5/1/2011'
This will find records where the datefield is May 1st Midnight. You have to do
WHERE datefield >= '5/1/2011' and datefield < '5/2/2011'
This doesn't really pertain to your question, but I've seen it trip up a LOT of people. Myself included.
Just convert it to dateTime
DateTime _ConvertedDate = Convert.ToDateTime(txtDate.Text);
this converts into datetime

Convert.ToDatetime not adding timestamp

For example:
Dim testdate As String = "29/10/2010"
testdate = Convert.ToDateTime(testdate.ToString)
Response.Write(testdate)
expecting "29/10/2010 00:00:00" what I get is "29/10/2010"
You have to assign the result of Convert.ToDateTime to a DateTime object, not to the string.
Dim testdate As String = "29/10/2010"
Dim date As DateTime = Convert.ToDateTime(testdate)
Response.Write(date)
This will print the clock as well as the date in the default format for your machine.
The big problem is, as mentioned in other posts, you are implicitly assigning the DateTime result of the Convert operation to a string variable. This wouldn't even pass the compilier in C#, so your into the realm of how VB operates on these implicit assignments and you probably don't want to be there because if some part of the language specification changes in a new Framework version and you try to migrate your code, you could potentially have a nasty bug to try to find (maybe not as important here, but in other cases, yes). Best move would be to rewrite the code block to have the Convert operation assign to a DateTime object, but simplier solution would be to throw a .ToString() at the end of the Convert.ToDateTime(testdate) line (i.e. testdate = Convert.DateTime(testdate).ToString() which will leave testdate with the date and the timestamp formatted to the current culture (as you are now performing an explicit conversion between the DateTime and the destination String).
As clearly documented here, no, this is not the designed behaviour.
'05/01/1996' converts to 5/1/1996 12:00:00 AM.
'Tue Apr 28, 2009' converts to 4/28/2009 12:00:00 AM.
It's possible that this article might provide insight.

Resources