Cry about...
C# Development How To Notes
Localization in a nutshell
The purpose of these notes are to provide a guide on how to localize a C# application.
Contents:
- Why Localize?
- Localization and Culture
- How to get the current culture
- How to set the culture in code
- How to reset the culture
- How to create and use localized strings (resource files)
- The easy way to localize dates
- Localized currency format
- Web apps: Detecting browser language
- Time Zones
- Further Reading
Why Localize?
I am writing this article in English, and when I develop software I develop it using English - so all my forms, dialogs, messages etc are in English. This is great for a native English speaker/reader, but what if a need arises to release say a German version of my software?
It would be undesirable to have two versions of an application, one English and one German, a more maintainable approach would be to have one application which supported by English and German. That is what localization can do for you.
Localization can also provide a means to deal with minor variations between different dialects. For example, I mostly write using British-English but sometimes I have a need to support American-English. The differences are minor, but include things like "colour" (British-English) instead of "color" (American-English). Again localization provides a means to allow for these differences.
Localization covers more than just language translation, but also time zone, date format, currency, reading-order, etc. If done properly (which does require effort) a localized application should look as though it was developed for the local culture. Sometimes localization will also require a partial redesign - but that is outside the scope of this article.
Localization and Culture
Culture defines the language settings and how dates, numbers and currency should be formatted.
So whilst Localization is the process of making an application appear localized, the culture is what is used to specify much of how the localization should be done.
Cultures are usually specified by name. For example (and this is only a sample, it is not intended to be complete):
Culture name | English name |
---|---|
(empty string) | Invariant culture |
en | English |
en-CA | English (Canadian) |
en-GB | English (United Kingdom) |
en-US | English (United States) |
fr | French |
fr-CA | French (Canadian) |
fr-FR | French (France) |
There is an MSDN article which gives a list of the pre-defined culture names.
This table does illustrate three important divisions within cultures:
- "invariant culture"
The invariant culture (there is only one) is culture insensitive. It is generally associated with English but not with any country or region. Think of the invariant culture as being the default culture for an application. - "neutral culture"
A neutral culture is associated with a language but not with a country. For example "en" is a neutral culture for English, and "fr" is a neutral culture for "French". - "specific culture"
A specific culture is associated with both a language and a country (or region). For example "en-GB" is a specific culture for English, United Kingdom, and "en-US" is a specific culture for English, United States.
If you can, always opt for a specific culture as that will give better localization.
How to get the current culture?
Getting the current culture is fortunatly quite simple. Less so
is understanding which culture you want, because the framework
maintains not one but two culture settings: CurrentCuture
and
CurrentUICulture
.
CurrentCulture
reflects the user locale settings. This defaults
to the regional options in Control Panel. This is used to control
the presentation of date and time settings.
Where as CurrentUICulture
reflects the user interface language.
This defaults to the language used by Windows. This is the culture
used by the resource manager when retrieving resources.
Obtaining the current culture is very simple (once you appreciate which of the above you need), and is either:
CultureInfo currentCulture = Thread.CurrentThread.CurrentCulture;
or
CultureInfo currentUICulture = Thread.CurrentThread.CurrentUICulture;
Both of these will return the appropriate culture used on the current thread, which (unless you have changed it in code) will be the culture in use when Windows open the application.
You will need to use/import the module System.Globalization
to
use CultureInfo
. You can also access the culture
information via System.Globalization.CultureInfo.CurrentCulture
and
System.Globalization.CultureInfo.CurrentUICulture
.
The CultureInfo
class has a number of useful properties, a few
of which are worth highlighting:
string Name
- Returns the name of the culture. This is in the code for the
culture.
For example "en-GB". string EnglishName
- Returns the name of the culture in English.
For example "English (United Kingdom)" string NativeName
- Returns the name of the culture in the native language.
For example "English (United Kingdom)"
You can see the full list on the MSDN page.
How to set the culture in code
Thread.CurrentThread.CurrentCulture
is a property, so it can be
assigned to as well as read from. So to set the culture is simply:
Thread.CurrentThead.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB");
ditto for Thread.CurrentThread.CurrentUICulture
.
When localisaing an application the ability to set the culture is probably only going to be useful if as a developer you want to override the culture setting specified in control panel, or for web applications where the culture information should be specific to the user and not the server it is running on.
How to reset the culture
Once you have changed the culture there is no simple way to reset it back! So if you want to temporarily change the culture then it might be best to either:
- Keep a reference to the original culture object and set back again.
- Keep a reference to the original culture object at application startup, so it is always available.
- Use a new culture object directly without changing the thead's culture.
Whenever a new thread is started it will use the default culture. So you can take advantage of this as a means to get the default. The following class illustrates how to read the default culture at run-time, it uses the fact that a new thread thread picks up the default culture:
internal static class DefaultCulture
{
private static
CultureInfo defaultCulture = null;
private static CultureInfo
defaultUICulture = null;
private static void
EnsureCultureLoaded()
{
if (defaultCulture == null)
{
CultureInfo.CurrentCulture.ClearCachedData();
CultureInfo.CurrentUICulture.ClearCachedData();
Thread
readCulture = new Thread(() =>
{
defaultCulture =
Thread.CurrentThread.CurrentCulture;
defaultUICulture =
Thread.CurrentThread.CurrentUICulture;
});
readCulture.Start();
readCulture.Join();
}
}
/// <summary>
/// Returns the default culture.
/// </summary>
public
static CultureInfo GetCulture()
{
EnsureCultureLoaded();
return defaultCulture;
}
/// <summary>
/// Returns the default UI culture.
/// </summary>
public static CultureInfo
GetUICulture()
{
EnsureCultureLoaded();
return
defaultUICulture;
}
}
How to create and use localized strings (resource files)
Resource files provide a simple but effective means of defining constants (typically strings), where the string value used varies automatically according to the current culture.
Whether you are working on a desktop application or a web application the way to create a new resource file is very similar.
- In Visual Studio, select Project > Add New Item ...
- Select "Resources File"
Note: You must add a resource file, you cannot use the application's resource file for this purpose. - Give the file a suitable name. The name of the file will be
used each time you refer to one of the resources in the file, so
remember that when you name it.
For example: "LocalizedText.resx". - Add one or more text strings to this resource file.
For example: Name=Welcome, Value=Welcome
Remember that these are in English, or rather they specify the default (invariant-culture) values that your application will use. - In your code you can now reference any resource simply
by using the name of the resource file and the name of the
string.
For example: LocalizedText.Welcome - To create a localized version of the resource file simply
add another resource file with the same name as the original but
with the language code appended.
For example: "LocalizedText.fr.resx"
The only other thing to be aware of before using this is that the
values pulled back will depend on the CurentUICulture
.
The following example shows the effect of this. This assumes that I have defined two resource files "LocalizedText" and "LocalizedText.fr" both of which define a value for "Welcome":
Console.WriteLine(
"Welcome in " +
Thread.CurrentThread.CurrentUICulture.EnglishName +
" is " +
LocalizedText.Welcome);
Thread.CurrentThread.CurrentUICulture =
CultureInfo.CreateSpecificCulture("fr");
Console.WriteLine(
"Welcome in " +
Thread.CurrentThread.CurrentUICulture.EnglishName
+
" is " +
LocalizedText.Welcome);
and this produces:
Welcome in English (United Kingdom) is Welcome
Welcome in French (France) is Bienvenue
Whilst my UICulture is en-GB, I don't have a resource file defined for en-GB, nore do I have one for en, so the application pulls back the text from my culture-invariant one (i.e. LocalizedText.resx).
You can use resource files in this way with images and even files.
The easy way to localize dates
The easiest way to localize dates is to use the built in
functions ToShortDateString()
or ToLongDateString()
. For example:
Console.WriteLine(
"Short date now: " +
DateTime.Now.ToShortDateString());
Console.WriteLine(
"Long
date now: " + DateTime.Now.ToLongDateString());
Alternatively you can extract the date string from the current culture and use that to format the date, so the following is longer but equivalent to the above:
Console.WriteLine(
"Short date now: " +
DateTime.Now.ToString(
Thread.CurrentThread.CurrentCulture.DateTimeFormat.ShortDatePattern));
Console.WriteLine(
"Long
date now: " + DateTime.Now.ToString(
Thread.CurrentThread.CurrentCulture.DateTimeFormat.LongDatePattern));
To illustrate the effect of changing the culture consider the following example:
Console.WriteLine(
"Culture: " +
Thread.CurrentThread.CurrentCulture.EnglishName);
Console.WriteLine(
"Short date now: " +
DateTime.Now.ToShortDateString());
Console.WriteLine(
"Long
date now: " + DateTime.Now.ToLongDateString());
Thread.CurrentThread.CurrentCulture =
CultureInfo.CreateSpecificCulture("en-US");
Console.WriteLine(
"Culture: " +
Thread.CurrentThread.CurrentCulture.EnglishName);
Console.WriteLine(
"Short date now: " + DateTime.Now.ToShortDateString());
Console.WriteLine(
"Long
date now: " + DateTime.Now.ToLongDateString());
which produces:
Culture: English (United Kingdom)
Short date now: 12/06/2013
Long date now: 13 June 2013
Culture: English (United States)
Short date now: 6/12/2013
Long date now: Thursday, June 13, 2013
The local culture on my PC is English UK. The above does show one of the common causes of misunderstanding between British English speakers and American English speakers - that British English express dates as day/month/year whereas American's use month/day/year. Which all goes to illustrate the need for localization even across different regions which notionally speak the same language.
If you require a custom date format, yet one which is still localizable, then the other option is to define your own date formats in the resource files and to use those when formatting dates.
Localized currency format
Currency is a good example of where a number needs to be displayed for different cultures.
To display a currency amount using the current culture simply use the number format string "C", i.e.:
Console.WriteLine(money.ToString("C"));
or
Console.WriteLine("Money: {0:C}",money);
For more information on the "C" format string for currency see The Currency ("C") Format Specifier on the Microsoft website.
For example:
double money = 12345.67;
Console.WriteLine(
"Culture:
" +
Thread.CurrentThread.CurrentCulture.EnglishName);
Console.WriteLine(String.Format("Money: {0:C}", money));
Thread.CurrentThread.CurrentCulture =
CultureInfo.CreateSpecificCulture("en-US");
Console.WriteLine(
"Culture: " +
Thread.CurrentThread.CurrentCulture.EnglishName);
Console.WriteLine(String.Format("Money: {0:C}", money));
produces:
Culture: English (United Kingdom)
Money: £12,345.67
Culture: English (United States)
Money: $12,345.67
If you need to display multiple currencies then it probably makes more sense to use:
money.ToString("C",culture)
where "money" is your variable holding the amount and culture is the culture you want to use.
It is important to recognise that whilst this will allow you to display the amount in the correct format for the culture, it does not do currency convesions (say Pounds-Sterling to US-Dollars). Currency conversions are down to you.
Web apps: Detecting browser language
On a website (as with a desktop application) the default culture is defined by the settings in Control Panel. If a website is aimed at a particular country then that may be sufficient, but if a website is aimed at people from different countries then the need to support different cultures quickly arises.
One way round this is to have a different website for each country or region that is being targetted. There are pros and cons of that. A simpler approach is to have one website for which you can switch cultures appropriatly for each visitor.
Of course the obvious question is which culture to use for a new visitor? You may well want to allow the visitor to change the language the website appears in, but what should be the initial choice? You can try to work it out from the browser. One of the messages the browser sends to the server when it requests a webpage is "Accept-Language" which notionally indicates the browsers preference for which language to use. However, it is important to be aware that this header might be missing or might be miss-configured at the client end. (Consider how many Windows PCs are set up with the default locale being US-English even though they are not located in the US?) However, other than trying to determine the location of a visitor by their IP address, the Accept-Language header is probably the best there is.
There are two ways to use the Accept-Language header, either (i.) do the work yourself or (ii.) let ASP.NET try to work it out for you.
1. Interpreting Accept-Language for yourself
Request.UserLanguages returns an array of strings (or possibly just null). Each of these represents a preferred language. You can work through this array and pick the language which more closely matches to what you have developed for or simply take the first and use that as a hint for which culture to use.
I'm not going to include any code samples for this, because there is a much simpler way - let ASP.NET try to work it out for you.
2. Let ASP.NET try to work it out
The simpler way is to let ASP.NET try to work out for itself what culture to use. To do this simply add:
<globalization culture="auto" uiCulture="auto"/>
to the web.config file. It goes inside the <system.web>
section
(which in turn is inside the <configuration>
section).
Just remember that this is a starting point, and that it is probably best to allow the user the option to override it and select their own.
Time Zones
What time is it? It's a simple question, but depending on where you are in the world you will give a different answer. As I'm writing this it is 4:38PM, but someone in Paris would say no its 5:38PM and someone in San Francisco would say its 8:38AM.
So normally when we ask what time is it we mean what is the local time here?
Particularly when developing applications for the web it is important to know where "here" is, because a visitor might very easily be in a different time zome from where you web server is located. So your users's time zone may be different from your server's time zone (just like the server and user's culture may be different).
There are some things to ask yourself when considering the time-zone:
- Does it matter?
For example lets say that a user records that a meeting took place at 10am in London. If looking at that information from Singapore (7 hours ahead), then should a reader in Singapore read that the meeting took place at 10am or at 5pm? (London 10am BST = 9am UTC = 5pm Singapore [UTC+8])
- What time (and date) are you going to store at the server?
In the example above it might be appropriate to store "10am", but for others (say when planning a video-conference) it would be more appropriate to store times in UTC and then convert to each user's local time zone when displaying it.
- What is the client's time-zone and what is the server's
time-zone?
If you date stamp events at the server then consider whether it is appropriate to store the date stamp as per the client's timezone, the server's timezone or UTC. Which is the most appropriate for your application?
UTC : Coordinated Universal Time - A standard for time
Coordinated Universal Time (abbreviated UTC) is a global standard for time. It is based on GMT, which represents the time at latitude 0 (Greenwich, UK) without regard for any local daylight saving. Local times around the world are represented as an offset to UTC.
C# Routines for handling UTC time
C# makes it very
easy to work with UTC, because DateTime
provides the handy functions
ToUniversalTime
and ToLocalTime
:
DateTime utcTime = now.ToUniversalTime();
DateTime meetingDate = meetingDateUTC.ToLocalTime();
One obvious thing to be aware
of is that these functions use the time zone of the local computer.
So if you are writing a desktop application then these two functions
are all you need to know. If however you are writing web based
application then you may also need to use the client's time zone
instead of the server's time zone. So if you want to provide a
timezone then you need to use a different set of functions and the
TimeZoneInfo
class.
To convert a time to UTC from a given
time zone use TimeZoneInfo.ConvertTimeToUtc
, eg:
DateTime utcTime = TimeZoneInfo.ConvertTimeToUtc(userEnteredTime,userTimeZone);
and to convert from UTC to a given time zone use
TimeZone.ConvertTimeFromUtc
, eg:
DateTime localTime = TimeZoneInfo.ConvertTimeFromUtc(utcTime,userTimeZone);
but where does the time zone information ("userTimeZone
" in the
above examples) come from? There are two ways to define the time
zone to use, either
TimeZoneInfo.FindSystemTimeZoneById(string id)
or TimeZoneInfo.CreateCustomTimeZone(string id, TimeSpan
baseUtcOffset, string displayName, string standardDisplayName)
.
Actually there are a few other ways, but those two are the ones that
I've found most useful.
TimeZoneInfo.FindSystemTimeZoneById(string id)
The function TimeZoneInfo.FindSystemTimeZoneById(string id)
returns a TimeZoneInfo
object from the registry on the local
computer. It will throw an exception if it cannot find a matching
id.
Unfortunatly there doesn't seem to be a list of pre-defined time
zone id's. You can query the computer for a list using
TimeZoneInfo.GetSystemTimeZones
which returns a list of available
time zones. However if you want to know what time zones are
available then this isn't much help.
The following lists all the time zones available on my computer, remember that each of the IDs is a string:
ID | Display name | Standard name |
---|---|---|
Dateline Standard Time | (UTC-12:00) International Date Line West | Dateline Standard Time |
UTC-11 | (UTC-11:00) Co-ordinated Universal Time-11 | UTC-11 |
Hawaiian Standard Time | (UTC-10:00) Hawaii | Hawaiian Standard Time |
Alaskan Standard Time | (UTC-09:00) Alaska | Alaskan Standard Time |
Pacific Standard Time (Mexico) | (UTC-08:00) Baja California | Pacific Standard Time (Mexico) |
Pacific Standard Time | (UTC-08:00) Pacific Time (US & Canada) | Pacific Standard Time |
US Mountain Standard Time | (UTC-07:00) Arizona | US Mountain Standard Time |
Mountain Standard Time (Mexico) | (UTC-07:00) Chihuahua, La Paz, Mazatlan | Mountain Standard Time (Mexico) |
Mountain Standard Time | (UTC-07:00) Mountain Time (US & Canada) | Mountain Standard Time |
Central America Standard Time | (UTC-06:00) Central America | Central America Standard Time |
Central Standard Time | (UTC-06:00) Central Time (US & Canada) | Central Standard Time |
Central Standard Time (Mexico) | (UTC-06:00) Guadalajara, Mexico City, Monterrey | Central Standard Time (Mexico) |
Canada Central Standard Time | (UTC-06:00) Saskatchewan | Canada Central Standard Time |
SA Pacific Standard Time | (UTC-05:00) Bogota, Lima, Quito | SA Pacific Standard Time |
Eastern Standard Time | (UTC-05:00) Eastern Time (US & Canada) | Eastern Standard Time |
US Eastern Standard Time | (UTC-05:00) Indiana (East) | US Eastern Standard Time |
Venezuela Standard Time | (UTC-04:30) Caracas | Venezuela Standard Time |
Paraguay Standard Time | (UTC-04:00) Asuncion | Paraguay Standard Time |
Atlantic Standard Time | (UTC-04:00) Atlantic Time (Canada) | Atlantic Standard Time |
Central Brazilian Standard Time | (UTC-04:00) Cuiaba | Central Brazilian Standard Time |
SA Western Standard Time | (UTC-04:00) Georgetown, La Paz, Manaus, San Juan | SA Western Standard Time |
Pacific SA Standard Time | (UTC-04:00) Santiago | Pacific SA Standard Time |
Newfoundland Standard Time | (UTC-03:30) Newfoundland | Newfoundland Standard Time |
E. South America Standard Time | (UTC-03:00) Brasilia | E. South America Standard Time |
Argentina Standard Time | (UTC-03:00) Buenos Aires | Argentina Standard Time |
SA Eastern Standard Time | (UTC-03:00) Cayenne, Fortaleza | SA Eastern Standard Time |
Greenland Standard Time | (UTC-03:00) Greenland | GreenlandStandard Time |
Montevideo Standard Time | (UTC-03:00) Montevideo | Montevideo Standard Time |
Bahia Standard Time | (UTC-03:00) Salvador | Bahia Standard Time |
UTC-02 | (UTC-02:00) Co-ordinated Universal Time-02 | UTC-02 |
Mid-Atlantic Standard Time | (UTC-02:00) Mid-Atlantic | Mid-Atlantic Standard Time |
Azores Standard Time | (UTC-01:00) Azores | Azores Standard Time |
Cape Verde Standard Time | (UTC-01:00) Cape Verde Is. | Cape Verde Standard Time |
Morocco Standard Time | (UTC) Casablanca | Morocco Standard Time |
UTC | (UTC) Co-ordinated Universal Time | Co-ordinated Universal Time |
GMT Standard Time | (UTC) Dublin, Edinburgh, Lisbon, London | GMT Standard Time |
Greenwich Standard Time | (UTC) Monrovia, Reykjavik | Greenwich Standard Time |
W. Europe Standard Time | (UTC+01:00) Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna | W. Europe Standard Time |
Central Europe Standard Time | (UTC+01:00) Belgrade, Bratislava, Budapest, Ljubljana, Prague | Central Europe Standard Time |
Romance Standard Time | (UTC+01:00) Brussels, Copenhagen, Madrid, Paris | Romance Standard Time |
Central European Standard Time | (UTC+01:00) Sarajevo, Skopje, Warsaw, Zagreb | Central European Standard Time |
Libya Standard Time | (UTC+01:00) Tripoli | Libya Standard Time |
W. Central Africa Standard Time | (UTC+01:00) West Central Africa | W. Central Africa Standard Time |
Namibia Standard Time | (UTC+01:00) Windhoek | Namibia Standard Time |
GTB Standard Time | (UTC+02:00) Athens, Bucharest | GTB Standard Time |
Middle East Standard Time | (UTC+02:00) Beirut | Middle East Standard Time |
Egypt Standard Time | (UTC+02:00) Cairo | Egypt Standard Time |
Syria Standard Time | (UTC+02:00) Damascus | Syria StandardTime |
E. Europe Standard Time | (UTC+02:00) E. Europe | E. EuropeStandard Time |
South Africa Standard Time | (UTC+02:00) Harare, Pretoria | South Africa Standard Time |
FLE Standard Time | (UTC+02:00) Helsinki, Kyiv, Riga, Sofia, Tallinn, Vilnius | FLE Standard Time |
Turkey Standard Time | (UTC+02:00) Istanbul | Turkey Standard Time |
Israel Standard Time | (UTC+02:00) Jerusalem | Jerusalem Standard Time |
Jordan Standard Time | (UTC+03:00) Amman | Jordan Standard Time |
Arabic Standard Time | (UTC+03:00) Baghdad | Arabic Standard Time |
Kaliningrad Standard Time | (UTC+03:00) Kaliningrad, Minsk | Kaliningrad Standard Time |
Arab Standard Time | (UTC+03:00) Kuwait, Riyadh | Arab Standard Time |
E. Africa Standard Time | (UTC+03:00) Nairobi | E. Africa Standard Time |
Iran Standard Time | (UTC+03:30) Tehran | Iran Standard Time |
Arabian Standard Time | (UTC+04:00) Abu Dhabi, Muscat | Arabian Standard Time |
Azerbaijan Standard Time | (UTC+04:00) Baku | Azerbaijan Standard Time |
Russian Standard Time | (UTC+04:00) Moscow, St. Petersburg, Volgograd | Russian Standard Time |
Mauritius Standard Time | (UTC+04:00) Port Louis | Mauritius Standard Time |
Georgian Standard Time | (UTC+04:00) Tbilisi | Georgian Standard Time |
Caucasus Standard Time | (UTC+04:00) Yerevan | Caucasus Standard Time |
Afghanistan Standard Time | (UTC+04:30) Kabul | AfghanistanStandard Time |
Pakistan Standard Time | (UTC+05:00) Islamabad, Karachi | Pakistan Standard Time |
West Asia Standard Time | (UTC+05:00) Tashkent | West Asia Standard Time |
India Standard Time | (UTC+05:30) Chennai, Kolkata, Mumbai, New Delhi | India Standard Time |
Sri Lanka Standard Time | (UTC+05:30) Sri Jayawardenepura | Sri Lanka Standard Time |
Nepal Standard Time | (UTC+05:45) Kathmandu | Nepal Standard Time |
Central Asia Standard Time | (UTC+06:00) Astana | Central Asia Standard Time |
Bangladesh Standard Time | (UTC+06:00) Dhaka | Bangladesh Standard Time |
Ekaterinburg Standard Time | (UTC+06:00) Ekaterinburg | Ekaterinburg Standard Time |
Myanmar Standard Time | (UTC+06:30) Yangon (Rangoon) | Myanmar Standard Time |
SE Asia Standard Time | (UTC+07:00) Bangkok, Hanoi, Jakarta | SE Asia Standard Time |
N. Central Asia Standard Time | (UTC+07:00) Novosibirsk | N. Central Asia Standard Time |
China Standard Time | (UTC+08:00) Beijing, Chongqing, Hong Kong, Urumqi | China Standard Time |
North Asia Standard Time | (UTC+08:00) Krasnoyarsk | North Asia Standard Time |
Singapore Standard Time | (UTC+08:00) Kuala Lumpur, Singapore | Malay Peninsula Standard Time |
W. Australia Standard Time | (UTC+08:00) Perth | W. Australia Standard Time |
Taipei Standard Time | (UTC+08:00) Taipei | Taipei StandardTime |
Ulaanbaatar Standard Time | (UTC+08:00) Ulaanbaatar | Ulaanbaatar Standard Time |
North Asia East Standard Time | (UTC+09:00) Irkutsk | NorthAsia East Standard Time |
Tokyo Standard Time | (UTC+09:00) Osaka, Sapporo, Tokyo | Tokyo Standard Time |
Korea Standard Time | (UTC+09:00) Seoul | Korea Standard Time |
Cen. Australia Standard Time | (UTC+09:30) Adelaide | Cen. Australia Standard Time |
AUS Central Standard Time | (UTC+09:30) Darwin | AUS Central Standard Time |
E. Australia Standard Time | (UTC+10:00) Brisbane | E. Australia Standard Time |
AUS Eastern Standard Time | (UTC+10:00) Canberra, Melbourne, Sydney | AUS Eastern Standard Time |
West Pacific Standard Time | (UTC+10:00) Guam, Port Moresby | West Pacific Standard Time |
Tasmania Standard Time | (UTC+10:00) Hobart | Tasmania Standard Time |
Yakutsk Standard Time | (UTC+10:00) Yakutsk | Yakutsk Standard Time |
Central Pacific Standard Time | (UTC+11:00) Solomon Is., New Caledonia | Central Pacific Standard Time |
Vladivostok Standard Time | (UTC+11:00) Vladivostok | Vladivostok Standard Time |
New Zealand Standard Time | (UTC+12:00) Auckland, Wellington | New Zealand Standard Time |
UTC+12 | (UTC+12:00) Co-ordinated Universal Time+12 | UTC+12 |
Fiji Standard Time | (UTC+12:00) Fiji | Fiji Standard Time |
Magadan Standard Time | (UTC+12:00) Magadan | Magadan Standard Time |
Kamchatka Standard Time | (UTC+12:00) Petropavlovsk-Kamchatsky - Old | Kamchatka Standard Time |
Tonga Standard Time | (UTC+13:00) Nuku'alofa | Tonga Standard Time |
Samoa Standard Time | (UTC+13:00) Samoa | Samoa Standard Time |
For example, to show the current time in Singapore:
DateTime utcTimeNow =
DateTime.Now.ToUniversalTime();
TimeZoneInfo singaporeZone =
TimeZoneInfo.FindSystemTimeZoneById(
"Singapore Standard Time");
Console.WriteLine(
"Time in Singapore: " +
TimeZoneInfo.ConvertTimeFromUtc(
utcTimeNow,singaporeTime).ToString());
TimeZoneInfo.CreateCustomTimeZone(string id, TimeSpan baseUtcOffset, string displayName, string standardDisplayName)
If you do not know the time zone id, or have a need to create
your own timezone then you can do so using
TimeZoneInfo.CreateCustomTimeZone
. This takes four arguments:
string id
- This is the id to associate with the time zone. (This doesn't create a new system time zone.)
TimeSpan baseUtcOffset
- The time difference between this time zone and UTC. This must evaluate to a whole number of minutes.
string displayName
- The display name of the new time zone.
string standardDisplayName
- The name of the new time zone's standard time.
For example, to show the current time in Singapore which I know to be UTC+8:
DateTime utcTimeNow =
DateTime.Now.ToUniversalTime();
TimeZoneInfo singaporeZone =
TimeZoneInfo.CreateCustomTimeZone(
"UTC+8",TimeSpan.FromHours(8),
"Singapore
time",
"Singapore time");
Console.WriteLine(
"Time in Singapore: " +
TimeZoneInfo.ConvertTimeFromUtc(
utcTimeNow,singaporeTime).ToString());
Daylight saving (eg British Summer Time)
If you use a named time zone (i.e. one loaded using TimeZoneInfo.FindSystemTimeZoneById) then any daylight saving should be automatically handled for you. This isn't the case if you create your own custom time zone. If you do need to create your own custom time zone and daylight saving is likely to be needed then use one of the following functions:
TimeZoneInfo.CreateCustomTimeZone(string id, TimeSpan baseUtcOffset, string displayName, string standardDisplayName, string daylightDisplayName, TimeZoneInfo.AdjustmentRule[] adjustmentRules);
or
TimeZoneInfo.CreateCustomTimeZone(string id, TimeSpan baseUtcOffset, string displayName, string standardDisplayName, string daylightDisplayName, TimeZoneInfo.AdjustmentRule[] adjustmentRules, bool disableDaylightSavingTime);
I have yet to need to use either of these so for guidance on their use please refer to the msdn TimeZoneInfo.CreateCustomTimeZone method documentation.
Further Reading
- http://www.csharp-examples.net/culture-names/
- C# example showing how to list all the culture names in Windows.
- http://support.microsoft.com/kb/306162
- Microsoft article on how to set the current culture programtically in an ASP.NET Application.
- http://www.dragon-tech.org/en/projects/selflocate/setculture/
- Setting the culture for a Windows Forms application.
- http://msdn.microsoft.com/en-us/library/fw69ke6f%28v=vs.100%29.aspx
- Walkthrough: Using Resources for Localization with ASP.NET.
- http://www.csharpdeveloping.net/Snippet/how_to_get_number_format_information_for_culture
- How to get the number format for a culture in C#.
About the author: Brian Cryer is a dedicated software developer and webmaster. For his day job he develops websites and desktop applications as well as providing IT services. He moonlights as a technical author and consultant.