0

I have:

  • A Country (for instance Namibia)
  • A DateTime stored in UTC (Let's say 23 October 1955 12:01 PM)

I want to write a function to translate the UTC datetime to local Namibian datetime with historic accuracy, taking into consideration daylight savings time.

I can not use timezones as some countries actually move timezones (Namibia for instance falls under WAT (UTC+1) during winter and WAST (UTC+2) during summer.

Any CSharp functions that can achieve this? Bonus points if this can be achieved by only passing the country's two-letter country code (for instance "NA").

The ideal function signature should be either:

public static DateTime UtcToLocal(this DateTime UtcDateTime, string CountryCode)

or

public static string UtcToLocal(this DateTime UtcDateTime, string CountryCode)

UPDATE

As pointed out in the comments section below, some countries are bound to multiple TimeZones (US for instance). So, the method signatures should rather look as follows:

public static DateTime UtcToLocal(this DateTime UtcDateTime, string TZ_Environment_ZoneName)
Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
CShark
  • 2,183
  • 1
  • 24
  • 42
  • http://stackoverflow.com/questions/179940/convert-utc-gmt-time-to-local-time – Ali Vojdanian Feb 10 '15 at 10:24
  • 7
    No, a place doesn't change time zone (well, depending on which time zone data you use). A time zone changes UTC offset. So for example, I'm in the UK time zone, aka "Europe/London" in IANA/TZDB terminology. That's GMT during the winter and BST in the summer, but it's still one time zone. More worrying with your method signature (aside from the parameter capitalization) is the idea that a country only observes a single time zone. Look at the US for example... – Jon Skeet Feb 10 '15 at 10:25
  • Jon Skeet thanks for the valuable feedback. The countries this specific system targets luckily does not have multiple time zones but .I will keep that in mind. – CShark Feb 10 '15 at 10:28
  • @JonSkeet - there are places in the United States that have historically switched time zones. [Parts of Indiana](http://en.wikipedia.org/wiki/Time_in_Indiana) for example. – dbc Feb 10 '15 at 10:30
  • @JonSkeet Unless I do not understand the article correctly, or if in fact this article needs correction, Namibia is one such case of a country actually changing timezones: http://en.wikipedia.org/wiki/Namibia – CShark Feb 10 '15 at 10:33
  • 4
    @dbc: Each of those has a separate time zone ID within the IANA database. The aim is that a time zone represents complete data for a place/area, as far back as is reasonable to track. See http://en.wikipedia.org/wiki/List_of_tz_database_time_zones and search for America/Indiana. – Jon Skeet Feb 10 '15 at 10:34
  • 1
    @CraftBeerHipsterDude: The article basically is using terminology incorrectly, in my view. I would say that it is a single time zone which observes WAT in the winter and WAST in the summer. Even TimeZoneInfo can handle that, although the ID will refer to "standard time" probably, because their naming scheme is awful. In IANA, it would be the "Africa/Windhoek" time zone. But again, take a step back - what would you expect your method to do with "US"? – Jon Skeet Feb 10 '15 at 10:36
  • @JonSkeet It's all quite confusing, to be honest. I am open to suggestions as to what standardised parameter I should rather use in stead of the two-letter country code. That might solve a more generic requirement for the wider development community. For my own immediate needs, though, it does not pose a problem as no conversions will be required for the US in the foreseeable future. – CShark Feb 10 '15 at 10:43
  • A more generic solution that resolves the problem for the US scenario would be epic. – CShark Feb 10 '15 at 10:44
  • @JonSkeet I found this http://en.wikipedia.org/wiki/List_of_tz_database_time_zones which I think is in line with you comments. I will update the question. – CShark Feb 10 '15 at 10:48
  • @JonSkeet I've just played around with this, and I think you might be wrong. Namibia uses WAT like a number of other African nations. However, of these, its the only one to use WAST for DST. Consequently, using 'W. Central Africa Standard Time' as a TimeZoneInfo ID doesn't perform the correct DST transition for Namibia in September. Using 'Namibia Standard Time' does the correct DST transition, but the UTC offset is wrong. – pixelbadger Feb 10 '15 at 11:10
  • 1
    @pixelbadger: "Namibia Standard Time" sounds like it should be the right TimeZoneInfo name - what *exactly* do you mean by "the UTC offset is wrong"? When? What is it, and what would you expect it to be? And which of my many statements in this question do you think is wrong? (It's hard to try to address a correction when it's not specific.) – Jon Skeet Feb 10 '15 at 11:15
  • 2
    @CraftBeerHipsterDude: With your update, what do you expect `TZ_Environment_ZoneName` to be? Where will you get that from? If that's an IANA time zone ID, then the answer is pretty simple using my Noda Time library... – Jon Skeet Feb 10 '15 at 11:16
  • @JonSkeet 'I would say that it is a single time zone which observes WAT in the winder, and WAST in the summer.' Given the fact that it shares WAT with other nations, but is unique in using WAST, it just seems clearer to me to consider it a different timezone during DST. RE the offset being wrong: WAT is UTC+1; WAST is UTC+2. Using 'Namibia Standard Time I'm getting UTC+0 and UTC+1 for non-DST and DST times. – pixelbadger Feb 10 '15 at 11:18
  • 1
    @pixelbadger: That may seem clearer to you, but it would be a nightmare in reality. It's much simpler to have a single time zone ID, and be able to ask for that time zone what the offset is at a given point in time. How are you asking for the offset? It works fine for me - see http://csharppad.com/gist/38de30c42c081ab617d1 – Jon Skeet Feb 10 '15 at 11:25
  • @JonSkeet You're completely right: my uncertainty over the two TimeZoneInfo IDs was leading me astray there. On reflection, I think the 'you might be wrong' was directed as your suggestion that TimeZoneInfo was handling the DST transitions correctly. I was using 2010 as the year in my test, giving the UTC offsets I mentioned. I assume some timezone transition happened then, but I can't find any info on it... – pixelbadger Feb 10 '15 at 11:34
  • 2
    @pixelbadger: Interesting - yes, it looks like the BCL TimeZoneInfo was broken then. It's correct in TZDB, as shown by Noda Time: http://csharppad.com/gist/7f84e453e72d5c98c13b – Jon Skeet Feb 10 '15 at 11:39
  • @JonSkeet Iwill give your library a go, although I am unfamiliar with it. I will post the solution that I have gone with for now, although I still have to test it for historical accuracy wrt DST. – CShark Feb 10 '15 at 11:40
  • 1
    @CraftBeerHipsterDude: We still don't know what your "time zone name" will be - where you're getting that from. If you can get the proper TimeZoneInfo ID, you can use `FindSystemTimeZoneById`. If you can get an IANA ID instead, Noda Time would be a better bet. Basically we haven't got enough context to help you at the moment. – Jon Skeet Feb 10 '15 at 11:46
  • @JonSkeet I am using the StandardName attribute of the TimeZone objects returned by TimeZoneInfo.GetSystemTimeZones(). Not sure which naming convention / formal standard has been used here - I will try to look it up on MSDN. – CShark Feb 10 '15 at 12:13
  • @JonSkeet basically I just want the most accurate and simplest way to convert UTC to a local time for a specific country, state or geographic area. – CShark Feb 10 '15 at 12:22
  • 3
    You should use the `Id` property instead of `StandardName`... but the Windows time zone data isn't as good (IMO) as the IANA/TZDB data· – Jon Skeet Feb 10 '15 at 12:55
  • @JonSkeet See updated answer. Excellent work! – CShark May 19 '16 at 21:35

1 Answers1

0

As discussed, I used the TimeZoneInfo class to perform the conversion.

public static class DateExtenders
        {
            public static DateTime UtcToLocal(this DateTime UtcDateTime, string TimezoneName)
            {
                return
                    TimeZoneInfo.ConvertTimeFromUtc(UtcDateTime, TimeZoneInfo.GetSystemTimeZones().Where(tz => TimezoneName.Equals(tz.StandardName)).Single());
            }        
        }

The value of the TimeZoneName can be any of the following values:

  • Dateline Standard Time
  • UTC-11
  • Hawaiian Standard Time
  • Alaskan Standard Time
  • Pacific Standard Time (Mexico)
  • Pacific Standard Time
  • US Mountain Standard Time
  • Mountain Standard Time (Mexico)
  • Mountain Standard Time
  • Central America Standard Time
  • Central Standard Time
  • Central Standard Time (Mexico)
  • Canada Central Standard Time
  • SA Pacific Standard Time
  • Eastern Standard Time
  • US Eastern Standard Time
  • Venezuela Standard Time
  • Paraguay Standard Time
  • Atlantic Standard Time
  • Central Brazilian Standard Time
  • SA Western Standard Time
  • Pacific SA Standard Time
  • Newfoundland Standard Time
  • E. South America Standard Time
  • Argentina Standard Time
  • SA Eastern Standard Time
  • Greenland Standard Time
  • Montevideo Standard Time
  • Bahia Standard Time
  • UTC-02
  • Mid-Atlantic Standard Time
  • Azores Standard Time
  • Cabo Verde Standard Time
  • Morocco Standard Time
  • Coordinated Universal Time
  • GMT Standard Time
  • Greenwich Standard Time
  • W. Europe Standard Time
  • Central Europe Standard Time
  • Romance Standard Time
  • Central European Standard Time
  • W. Central Africa Standard Time
  • Namibia Standard Time
  • Jordan Standard Time
  • GTB Standard Time
  • Middle East Standard Time
  • Egypt Standard Time
  • Syria Standard Time
  • E. Europe Standard Time
  • South Africa Standard Time
  • FLE Standard Time
  • Turkey Standard Time
  • Jerusalem Standard Time
  • Russia TZ 1 Standard Time
  • Libya Standard Time
  • Arabic Standard Time
  • Arab Standard Time
  • Belarus Standard Time
  • Russia TZ 2 Standard Time
  • E. Africa Standard Time
  • Iran Standard Time
  • Arabian Standard Time
  • Azerbaijan Standard Time
  • Russia TZ 3 Standard Time
  • Mauritius Standard Time
  • Georgian Standard Time
  • Caucasus Standard Time
  • Afghanistan Standard Time
  • West Asia Standard Time
  • Russia TZ 4 Standard Time
  • Pakistan Standard Time
  • India Standard Time
  • Sri Lanka Standard Time
  • Nepal Standard Time
  • Central Asia Standard Time
  • Bangladesh Standard Time
  • Russia TZ 5 Standard Time
  • Myanmar Standard Time
  • SE Asia Standard Time
  • Russia TZ 6 Standard Time
  • China Standard Time
  • Russia TZ 7 Standard Time
  • Malay Peninsula Standard Time
  • W. Australia Standard Time
  • Taipei Standard Time
  • Ulaanbaatar Standard Time
  • Tokyo Standard Time
  • Korea Standard Time
  • Russia TZ 8 Standard Time
  • Cen. Australia Standard Time
  • AUS Central Standard Time
  • E. Australia Standard Time
  • AUS Eastern Standard Time
  • West Pacific Standard Time
  • Tasmania Standard Time
  • Magadan Standard Time
  • Russia TZ 9 Standard Time
  • Russia TZ 10 Standard Time
  • Central Pacific Standard Time
  • Russia TZ 11 Standard Time
  • New Zealand Standard Time
  • UTC+12
  • Fiji Standard Time
  • Kamchatka Standard Time
  • Tonga Standard Time
  • Samoa Standard Time
  • Line Islands Standard Time

Unfortunately I am unsure which formal naming standard / naming conventions was used for the above listed values

UPDATE

I have, since I posted this answer, adopted the use of Jon Skeet's Nodatime library, which is an excellent library for working with datetime concepts. I highly recommend it over struggling with BCL date, time and timespan classes!

Community
  • 1
  • 1
CShark
  • 2,183
  • 1
  • 24
  • 42
  • 1
    The list is dependant on the windows OS. Older versions might not have Samoa Standard Time for example. – Carra Feb 10 '15 at 12:26
  • 1
    You should be using `TimeZoneInfo.FindSystemTimeZoneById` instead of filtering by name via LINQ. IDs are consistent, but `StandardName`, `DaylightName` and `DisplayName` are [localized by the OS language](http://codeofmatt.com/2014/12/26/localized-time-zone-names-in-net/). – Matt Johnson-Pint Feb 11 '15 at 20:14
  • 1
    With regard to your comment about naming conventions - with Microsoft time zones, there are no uniform conventions. You would need to use [IANA/TZDB time zones](http://en.wikipedia.org/wiki/Tz_database) if you want uniformity. You can do that with [Noda Time](http://nodatime.org/). Also, you should have a read of [the timezone tag wiki](http://stackoverflow.com/tags/timezone/info). – Matt Johnson-Pint Feb 11 '15 at 20:16
  • Thanks for the above comments. I definitely want uniformity so I will be taking a look at NodaTime. I will post the updated answer with my new implementation as soon as I am done with it. – CShark Feb 12 '15 at 07:10