views:

5133

answers:

6

I am working on an "online reminder system" project (ASP.NET 2.0 (C#) / SQL2005)

As this is a reminder service which will send the mail to users on a particular dates. But the problem is users are not from a specific countries, they are from all over the world and from different time zones. Now When I am registering I am asking for users time zone in the same way as windows asks our time zone at the time of installation.

But I am not getting the if the user selected (+5.30) or something timezone then how to handle this time zone in my asp.net application. How to work according to timezone.

And please suggest if there is any better way to handle timezones in this application ??

Thanks

+3  A: 

First thing is to make sure which time zone your data is in. I would recommend making sure that any DateTime that you store, is stored in UTC time (use the DateTime.ToUniversalTime() to get hold of it).

When you are to store a reminder for a user, you will need the current UTC time, add or remove the user's time zone difference, and convert that new time back to UTC; this is what you want to store in the DB.

Then, when you want to check for reminders to send, you simply need to look in the database for reminders to send out now, according to UTC time; essentially get all reminders that have a time stamp that is before DateTime.Now.ToUniversalTime().

Update with some implementation specifics: You can get a list of time zones from the TimeZoneInfo.GetSystemTimeZones() method; you can use those to show a list of time zones for the user. If you store the Id property from the selected time zone, you can create a TimeZoneInfo class instance from it, and calculate the UTC time for a given local date/time value:

TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById("<the time zone id>");
// May 7, 08:04:00
DateTime userDateTime = new DateTime(2009, 5, 7, 8, 4, 0);
DateTime utcDateTime = userDateTime.Subtract(tzi.BaseUtcOffset);
Fredrik Mörk
Ok, your idea sounds good, but I am feeling a problem there. You said "you will need the current UTC time, add or remove the user's time zone difference, and convert that new time back to UTC;" but now when I'll run my process which will send the reminders. I am located in Indian timezone (IST), so when should I run the reminders so that reminder will be sent to the users at correct time.
Prashant
Instead of storing in UTC, what I thought is: I'll have three columns in my reminder_schedule table which will be "Original_DateTime", "UTC_DateTime" and "IST_DateTime". Now Original_DateTime date time will store the exact date whatever user will set. UTC_DateTime will store the UTC DateTime on the basis of users timezone. and last "IST_DateTime" will store the datetime according to Indian Timezone by converting UTC_DateTime to Indian TimeZone. Then finally I'll run my reminders sending process accoridng to INdian tmezone and hence all reminder will be sent on exact time.
Prashant
I'm not sure that the idea I've given above is perfect but these are my thought, please tell me how should I proceed further ??
Prashant
As a minimum you need to store the time i a "server reference" time; I usually prefer UTC, but in your case I guess IST will work as well. If you use IST you will not tecnically need to store the UTC time (since you can easily get that one from the DateTime class. Same thing goes for the user's local time; technically you only need the time zone for the user; then you can go from IST to UTC to local time. Might be convenient to have it in the DB though.
Fredrik Mörk
hmmm.. sounds good. one more thing @Fredrik you have written "DateTime utcDateTime = userDateTime.Subtract(tzi.BaseUtcOffset);" line in you code, but how will we know that we have to substract or add the timezone to convert it to UTC ??
Prashant
Hi @Fredrik, any replies??
Prashant
@Prashant: sorry for not getting back to you: the answer is that the BaseUtcOffset should *always* be subtracted from the local time, since it is signed; in time zones that are before UTC (such as IST), BaseTimeOffset returns a TimeSpan with positive value, but for time zones that are after UTC, such as US Eastern Standard Time, it returns a negative time span; so if UTC is 12:00 and you have a time zone with a -1 hour offset (so local time is 11:00) you will get 11:00 - (-1) hour => 11:00 + 1 hour => 12:00.
Fredrik Mörk
A: 

Basically, all you need to do is add the offset (hours + minutes) to the local time that the user has entered. Adding in the offset basically gives you a DateTime in the UTC (basically GMT) timezone.

It's usually easiest to standardize all your times to UTC, so that your application logic doesn't have to deal with the offsets.

This page has a few good examples: http://msdn.microsoft.com/en-us/library/bb546099.aspx

Andy White
A: 

You may want to look at using the DateTimeOffset structure instead of the DateTime if you are on framework 2.0 or later.

The DateTimeOffset represents a point in time relative to UTC time, so it should be easier to work with in this case.

Rune Grimstad
+4  A: 

I would recommend to always use UTC (GMT) time on the server side (in code-behind, database, etc), and convert time from UTC to local time for display purposes only. This means that all time manipulations - including saving time in database, performing calculations, etc - should be be done using UTC.

The problem is: how does your code-behind know what is the time zone of the client browser? Say the user enters some date/time value (such as 12/30/2009 14:30) in the form and submits it to the server. Assuming that the user submitted local time, how does the server know how to convert this value to UTC?

The application can ask the user to specify the time zone (and save it in a persistent cookie or database), but it requires and extra effort from the user, and your app would need to implement the logic and screens for this. It would be nicer if the app could determine client's time zone automatically.

I have addressed this issue with the help of JavaScript's getTimezoneOffset function, which is the only API that can tell the server about the time difference between local time on the client and GMT. Since this is a client-side API, I did the following: on the server side check for a custom session cookie holding the time offset value, and if it's not available, reload the page (only during GET, and not POST, calls) with some JavaScript logic added to generate the time offset and save it in the cookie. From the client-side this is almost transparent (once during session I reload a page on GET). Once I have the offset in the cookie, I apply it to the time management functions depending on direction of time conversion (UTC to local time, or local time to UTC).

This may sound a bit complicated, and it is, but after I wrote helper functions, integrating this feature in the site was a matter of making a single call in Page_Load (of pages that needed time conversion), and using time conversion routines when sending and retrieving time values to and from the browser. Here is an example of how it can be used:

using My.Utilities.Web;
...

// Derive the form class from BaseForm instead of Page.
public class WebForm1: BaseForm
{
...
private void Page_Load(object sender, System.EventArgs e)
{
  // If we only want to load the page to generate the time
  // zone offset cookie, we do not need to do anything else.
  if (InitializeLocalTime())
    return;

  // Assume that txtStartDate is a TextBox control.
  if (!IsPostback)
  {
     // To display a date-time value, convert it from GMT (UTC)
     // to local time.
     DateTime startDate = GetStartDateFromDB(...);
     txtStartDate.Text  = FormatLocalDate(startDate);
     ...
  }
  else
  {
     // To save a date-time value, convert it from local
     // time to GMT (UTC).
     DateTime tempDate  = DateTime.Parse(txtStartDate.Text);
     DateTime startDate = ConvertLocalTimeToUtc(tempDate);
     SaveStartDateInDB(startDate, ...);
     ...
  }
}
...
}

If you need more specifics, check out the It’s About Time: Localizing Time in ASP.NET Applications article (sorry, but I do not have a direct link to the article on the publisher's site, since asp.netPRO restricts access to paid subscribers only; there are links to PDF copies, though). I wish I could post the sample from the article, but I don't want to violate the copyright; however, here is a project to build a helper library that has all necessary functionality and documentation (just ignore the stuff you do not need).

UPDATE: The article has been posted online with sample project by the new publisher here.

Alek Davis
I disagree with the statement that your app should determine user's timezone automatically. Users can set any timezone/date/time they want in theirs operating system and bypass your business rules. Never trust user input.
BrunoSalvino
I don't understand your point Bruno. First, there are no business rules associated with time zones. It's an issue of usability. We could've used GMT, but it's not convenient for users, so we use local time. If user changes the system clock (or whatever way they use to specify time zone), who cares? I don't see a problem here. I'm also not following a transition from your first statement to the second statement. Do you not like the "automatic" part, or do you not like the idea of using local time at all (if it's not done automatically, user must be able to change it somehow, right)?
Alek Davis
A: 

The problem with all of the answers so far is that they do not take into account what Prashant is trying to achieve. If the user of his system on the day before daylight savings changes has an offset of +12 and sets a reminder for the next day, his offset when the reminder is supposed to be triggered will be +13 instead.

That is why you can only use current offset for something that is happening now. Although I do agree with everyone else that all times server-side (except possibly those used only for display) should be stored in UTC.

A: 

The issue is that the offset from UTC will vary at different times of the year -- each time zone has its own rules. (I learned this the hard way when developing meeting room scheduling app.)

Looks like there is built-in support here: http://msdn.microsoft.com/en-us/library/system.timezoneinfo.converttime.aspx

Haven't tried it myself but it seems to promise the correct conversion, accounting for daylight savings.

If not, here is a (pricey) commercial tool I have used: http://www.worldtimeserver.com/time_zone_guide/

Matt Sherman