enable working with different timezones - c#

I have an asp.net + c# application that uses System.DateTime.now for logging working hours of employees. the application is online and recently I have users connecting to it from outside of my country.
I have a client that wants his employees working abroad to log their working hours according to their timezone.
All the dates and hours that are documented in the db are not in universal time so I don't want to try and change backwards everything to UTC (I also think that's not applicable).
I'm aware of ways to detect the user's timezone- js and geo-location. the thing is I don't trust the accuracy level of both. in conclusion I thought i'd let the admin define through an interface time-zones and the user will pick the one he wishes to use.
Is this a proper way? What is the best practice for this?
10q very much.

I think your approach of having an admin define the timezones for a group of users makes a lot of sense. You will quite often find that people have the wrong timezone defined on their desktop PCs, adding another complication. If you set it explicitly, you are safe.
I would urge you to use UTC in your database. If you start mixing DateTimes which are from different timezones in the same database this is going to come back to bite you!

Having the DateTimes stored in UTC is definitely a best practice in my book. It may be quite a bit of work to convert your existing data, but it's probably going to be worth it in the long term if you already have a few users in different time zones (today it's two, but soon it could be three, four....) It's also going to make it easier to avoid problems around things like daylight savings time conversions, especially if the groups are in regions where the start and end of daylight savings is different, which is the case between the US and UK (I have to deal with these DateTime issues in my system).
I would not rely on any automatic detection of a user's timezone when data is entered into your UI. The first thing I'd do is associate users in the database with a timezone property. It doesn't sound like your users are changing their timezones much, if ever.
It shouldn't be too difficult to associate locations with either users or groups of users if you're not already doing it. Just add the timezone information along with their location, and use that in your code when creating a DateTime object from the input from your. It means one more piece of data that someone will have to manage, but it's going to be less troublesome than trying to automatically detect the timezone through code.
It's going to be very easy to miss conversions now that you're adding a new time zone. I would recommend making sure all your DateTime logic is centralized (extension methods or a helper class, depending on your framework version). Keep all your conversions and string formatting in a single place and make sure all your code references it.
Good luck, and write lots of unit tests around your conversions.

Related

Date and time logic for an multi Time Zone Open/Close place system

I'm building a system where you got a lot of places, all around the world that need to show if they're open or close in real time.
The thing I've been debating on is how to do it, having never build this in any other project, I don't really know what is the best idea to achieve this goal.
I'd like to do it the right way so that I don't have to rebuild the entire date and time system later.
I use C# and .NET 5.0 for the API and Xamarin.Forms for the mobile app.
What I was thinking was:
Either I use regular DateTime for the times and input, let's say, oh this place closes at 11pm, doesn't matter if it's in Sweden or UK, basically their Time Zone doesn't matter. Compare the place's closing time to the user's phone's internal region and time and if the user's phone says it's 11pm and the place closes at 11pm, display it as closed on their phone. I don't think it's a good idea because I think this data should be changed at the API level, not run a method for each user running the app, but I might be wrong.
Or, I actually create times related to their Time Zones such as, I don't know what to use yet to be honest but, say DateTimeOffset or something and actually add the TimeZone as a property to the place's Address, then in the API compare it to the place's current time in its region and mark it as open or close for everyone in the world since it's on the server.
It might be a very simple question but I want to make sure I'm doing this right.
I'm building a system where you got a lot of places, all around the
world that need to show if they're open or close in real time.
That's great.
The thing I've been debating on is how to do it, having never build
this in any other project, I don't really know what is the best idea
to achieve this goal. I'd like to do it the right way so that I don't
have to rebuild the entire date and time system later.
Exactly, you don't need to reinvent the wheel. There a lot of example on the internet that you can use for that. Just be careful to create your system design based on your requirements.
Either I use regular DateTime for the times and input, let's say, oh
this place closes at 11pm, doesn't matter if it's in Sweden or UK,
basically their Time Zone doesn't matter. Compare the place's closing
time to the user's phone's internal region and time and if the user's
phone says it's 11pm and the place closes at 11pm, display it as
closed on their phone. I don't think it's a good idea because I think
this data should be changed at the API level, not run a method for
each user running the app, but I might be wrong.
Yes, that's not a great idea. Nowadays, actually smart phones are quite smart to update their local time when they have internet connection but "region" subject is still under users control. That's why the subject of "local time" will be always depends on user regions, phones time zone system and how up to date of "that" system. For example, you can still live in Turkey but you "can" set your region settings for another country, like Germany. In that case, "the place where user lives" and "region settings on the phone" matters. My 11:00PM can be easily different than your 11:00PM.
One of the solutions can be taking location information on the phone and calculating user's time zone and inform and/or compare phone's time.
A nice guy named Matt Johnson-Pint created 2 useful library for that. GeoTimeZone and TimeZoneConverter. You can find the time zone information of the user for longitude and latitude easily.
For example;
string tzIana = TimeZoneLookup.GetTimeZone(lat, lng).Result;
TimeZoneInfo tzInfo = TZConvert.GetTimeZoneInfo(tzIana);
DateTimeOffset convertedTime = TimeZoneInfo.ConvertTime(DateTimeOffset.UtcNow, tzInfo);
Remember, time zones matters!
Or, I actually create times related to their Time Zones such as, I
don't know what to use yet to be honest but, say DateTimeOffset or
something and actually add the TimeZone as a property to the place's
Address, then in the API compare it to the place's current time in its
region and mark it as open or close for everyone in the world since
it's on the server.
Yes, that sounds more logical.
Please let me know how I should do it and also explain how I should
implement it in detail
Sorry, Stack Overflow is for specific programming problems and this part of your question does not meet the standart of asking a proper question. Please read Help Center a few times before asking more questions.

How to convert existing dates to local browser date in c# and javascript and show them back in the browser [duplicate]

I am storing all the DateTime fields as UTC time. When a user requests a web page, I would like to take his preferred local timezone (and not the local timezone of the server machine) and automatically display all the DateTime fields in all the web forms as local dates.
Of course, I could apply the conversion on every DateTime.ToString() call in every form or implement some helper utility but it is a time consuming task, and also there are some 3rd party components which are tricky to configure with custom DateTime display templates.
Essentially, I would like to make the DateTime class to behave as follows:
from this moment on for this web request,
whenever some code calls DateTime.ToString(), convert it to the local time
using the timezone offset given at the very beginning of the web request,
but if possible, please keep .NET core library DateTime.ToString() calls intact
(I don't want to mess up event logging timestamps etc.)
Is there any way to do it?
BTW, I am using ASP.NET MVC 4, if it matters.
You can't do directly what you asked for, but I will suggest some alternatives. As Nicholas pointed out, there is nothing in HTTP that would give you the time zone directly.
Option 1
First, decide which type of time zone data you want to work with. There are two different types available, either the Microsoft time zones that you can access with the TimeZoneInfo class, or the IANA/Olson time zones that the rest of the world uses. Read here for more info. My recommendation would be the latter, using the implementation provided by NodaTime.
Then determine which time zone you want to convert to. You should allow your user a setting somewhere to pick their time zone.
You might show a drop-down list to pick one of several time zones, or you might do something more useful, like display a map of the world that they can click to select their time zone. There are several libraries that can do this in Javascript, but my favorite is this one.
You might want to guess a default time zone to use, so you can be as close to accurate as possible before they pick from the list (or map). There is a great library for this called jsTimeZoneDetect. It will interrogate the browser's clock and make a best guess assumption of what time zone it might be. It is fairly good, but it is still just a guess. Don't use it blindly - but do use it to determine a starting point. Update You can now also do this with moment.tz.guess(), in the moment-timezone component of moment.js.
Now that you know the time zone of the user, you can use that value to convert your UTC DateTime values to that local time zone. Unfortunately, there is nothing you can set on the thread that will do that. When you change the system time zone, it is global for all processes and threads. So you have no choice but to pass the time zone to each and every place you are sending it back. (I believe this was your main question.) See this almost duplicate here.
Before you convert it to a string, you will need to also know the user's locale (which you can get from the Request.UserLanguages value). You can assign it to the current thread, or you can pass it as a parameter to the DateTime.ToString() method. This doesn't do any time zone conversion - it just makes sure that the numbers are in the correct position, using the correct separators, and the appropriate language for names of weekdays or months.
Option 2
Don't convert it to local time on the server at all.
Since you said you are working with UTC values, make sure their .Kind property is Utc. You should probably do this when you load from your database, but if you have to you can do it manually:
myDateTime = DateTime.SpecifyKind(myDateTime, DateTimeKind.Utc);
Send it back to the browser as pure UTC, in an invariant format like ISO8601. In other words:
myDateTime.ToString("o"); // example: "2013-05-02T21:01:26.0828604Z"
Use some JavaScript on the browser to parse it as UTC. It will automatically pick up the local time settings of the browser. One way is to use the built-in Date object in JavaScript, like this:
var dt = new Date('2013-05-02T21:01:26.0828604Z');
However, this will only work in newer browsers that support the ISO-8601 format. Instead, I recommend using the moment.js library. It is consistent across browsers, and it has better support for ISO dates, and localization. Plus you get a lot of other useful parsing and formatting functions.
// pass the value from your server
var m = moment('2013-05-02T21:01:26.0828604Z');
// use one of the formats supported by moment.js
// this is locale-specific "long date time" format.
var s = m.format('LLLL');
The advantage of Option 1 is that you can work with times in any time zone. If you can ask the user for their timezone from a dropdown list, then you need not use any Javascript.
The advantage of Option 2 is that you get the browser to do some of the work for you. This is the best way to go if you're sending out raw data, such as making AJAX calls to a WebAPI. However, JavaScript is only aware of UTC and the browser's local time zone. So it doesn't work so well if you need to convert to other zones.
You should also be aware that if you choose Option #2, you may be affected by a flaw in the design of ECMAScript 5.1. This comes into play if you are working with dates that are covered by a different set of daylight saving time rules than are currently in effect. You can read more in this question, and on my blog.
It would be so much easier if we had some time zone information in the HTTP headers, but unfortunately we don't. These are a lot of hoops to jump through, but it's the best way to have both flexibility and accuracy.
The short answer is that you can't. HTTP doesn't require (or even provide a standard way) for the user agent (browser) to provide local time or timezone information in the HTTP request.
You either need to
ask the user for their preferred time zone, or
have client-side javascript report it to you somehow (cookie? ajax? other?)
Bear in mind that a client-side javascript solution isn't perfect, either. Javascript disabled (or non-existent, for some browsers). Javascript might not have access to timezone information. Etc.

Windows Phone 8 creating Calendar Application

I am new to creating Windows Phone 8 application. I want to create a Calendar application that tracks my daily activity. I know there is already a build in Calendar application but I want to try to create my self in my own User Interface.
Is there a way to get the date of the calendar. For example, a build in API to access the date where I don't have to create it my self such as create a whole new calendar application in my own function. I will have to think of the leap year and also which month has 31 days and which doesn't. I did some research but most I get was to be able to access appointments from the build in Calendar. If there is anything wrong regarding my theory do correct me.
I will have to think of the leap year and also which month has 31 days and which doesn't.
You shouldn't need to write any code for yourself which does that. You can either use the existing DateTime type, or potentially use my Noda Time library which separates out the various "kinds" of date and time values you might have into different types. Either way, there are methods which already understand month lengths etc - you should make sure that you don't reinvent the wheel. Instead, think about what your data model looks like, what the user interactions are, what the presentation should look like etc. (One thing to think about really early is what you want to do about time zones.)
I would personally suggest not trying to integrate with the existing calendar, at least to start with. The more code you integrate with, the harder it's going to be. It really depends on how much this app is aimed at creating a full real solution, and how much it's a learning process.

Globally convert UTC DateTimes to user specified local DateTimes

I am storing all the DateTime fields as UTC time. When a user requests a web page, I would like to take his preferred local timezone (and not the local timezone of the server machine) and automatically display all the DateTime fields in all the web forms as local dates.
Of course, I could apply the conversion on every DateTime.ToString() call in every form or implement some helper utility but it is a time consuming task, and also there are some 3rd party components which are tricky to configure with custom DateTime display templates.
Essentially, I would like to make the DateTime class to behave as follows:
from this moment on for this web request,
whenever some code calls DateTime.ToString(), convert it to the local time
using the timezone offset given at the very beginning of the web request,
but if possible, please keep .NET core library DateTime.ToString() calls intact
(I don't want to mess up event logging timestamps etc.)
Is there any way to do it?
BTW, I am using ASP.NET MVC 4, if it matters.
You can't do directly what you asked for, but I will suggest some alternatives. As Nicholas pointed out, there is nothing in HTTP that would give you the time zone directly.
Option 1
First, decide which type of time zone data you want to work with. There are two different types available, either the Microsoft time zones that you can access with the TimeZoneInfo class, or the IANA/Olson time zones that the rest of the world uses. Read here for more info. My recommendation would be the latter, using the implementation provided by NodaTime.
Then determine which time zone you want to convert to. You should allow your user a setting somewhere to pick their time zone.
You might show a drop-down list to pick one of several time zones, or you might do something more useful, like display a map of the world that they can click to select their time zone. There are several libraries that can do this in Javascript, but my favorite is this one.
You might want to guess a default time zone to use, so you can be as close to accurate as possible before they pick from the list (or map). There is a great library for this called jsTimeZoneDetect. It will interrogate the browser's clock and make a best guess assumption of what time zone it might be. It is fairly good, but it is still just a guess. Don't use it blindly - but do use it to determine a starting point. Update You can now also do this with moment.tz.guess(), in the moment-timezone component of moment.js.
Now that you know the time zone of the user, you can use that value to convert your UTC DateTime values to that local time zone. Unfortunately, there is nothing you can set on the thread that will do that. When you change the system time zone, it is global for all processes and threads. So you have no choice but to pass the time zone to each and every place you are sending it back. (I believe this was your main question.) See this almost duplicate here.
Before you convert it to a string, you will need to also know the user's locale (which you can get from the Request.UserLanguages value). You can assign it to the current thread, or you can pass it as a parameter to the DateTime.ToString() method. This doesn't do any time zone conversion - it just makes sure that the numbers are in the correct position, using the correct separators, and the appropriate language for names of weekdays or months.
Option 2
Don't convert it to local time on the server at all.
Since you said you are working with UTC values, make sure their .Kind property is Utc. You should probably do this when you load from your database, but if you have to you can do it manually:
myDateTime = DateTime.SpecifyKind(myDateTime, DateTimeKind.Utc);
Send it back to the browser as pure UTC, in an invariant format like ISO8601. In other words:
myDateTime.ToString("o"); // example: "2013-05-02T21:01:26.0828604Z"
Use some JavaScript on the browser to parse it as UTC. It will automatically pick up the local time settings of the browser. One way is to use the built-in Date object in JavaScript, like this:
var dt = new Date('2013-05-02T21:01:26.0828604Z');
However, this will only work in newer browsers that support the ISO-8601 format. Instead, I recommend using the moment.js library. It is consistent across browsers, and it has better support for ISO dates, and localization. Plus you get a lot of other useful parsing and formatting functions.
// pass the value from your server
var m = moment('2013-05-02T21:01:26.0828604Z');
// use one of the formats supported by moment.js
// this is locale-specific "long date time" format.
var s = m.format('LLLL');
The advantage of Option 1 is that you can work with times in any time zone. If you can ask the user for their timezone from a dropdown list, then you need not use any Javascript.
The advantage of Option 2 is that you get the browser to do some of the work for you. This is the best way to go if you're sending out raw data, such as making AJAX calls to a WebAPI. However, JavaScript is only aware of UTC and the browser's local time zone. So it doesn't work so well if you need to convert to other zones.
You should also be aware that if you choose Option #2, you may be affected by a flaw in the design of ECMAScript 5.1. This comes into play if you are working with dates that are covered by a different set of daylight saving time rules than are currently in effect. You can read more in this question, and on my blog.
It would be so much easier if we had some time zone information in the HTTP headers, but unfortunately we don't. These are a lot of hoops to jump through, but it's the best way to have both flexibility and accuracy.
The short answer is that you can't. HTTP doesn't require (or even provide a standard way) for the user agent (browser) to provide local time or timezone information in the HTTP request.
You either need to
ask the user for their preferred time zone, or
have client-side javascript report it to you somehow (cookie? ajax? other?)
Bear in mind that a client-side javascript solution isn't perfect, either. Javascript disabled (or non-existent, for some browsers). Javascript might not have access to timezone information. Etc.

Is there anything that reduces the Olson time zone list into a readable format for the UI (like Google Calendar does)?

I am writing an app that asks the user to choose a time zone. I am getting my list of time zones from the Olson database (via NodaTime) but that is a massive list with many redundant entries, for my purposes at least.
When you create an event on Google Calendar it lets you choose the time zone from a relatively small list with ordering by country where necessary. I would like to be able to achieve something as simple as that without creating a separate database, which is what
this person does.
Because I am writing this in C# MVC plus JavaScript on the front end, I am looking for a library in either of those languages that gives me a reduced list in a user-friendly format that I could display in a dropdown. Is there such a thing or do I have to create my own and regularly keep it up to date, like the example shown in the hyperlink?
Two possible answers here:
Information from the zone.tab file. As it happens, just today another contributor mailed the list with an hg clone which uses this data. I haven't looked at it yet, but hope to do so over the weekend - and after a bit of massaging, we'll hopefully get it into the 1.1 branch.
Information from CLDR. This provides suggested example cities to present to a user - it's designed for exactly this purpose (even localized, I believe). However, you'd need to integrate this with Noda Time yourself; we don't currently have any code for this, and just getting to grips with CLDR will take some time.
Apologies for this not being solved out of the box - but we're aware of it and hope to provide an answer over time.

Categories

Resources