Parse DateTime with time zone of form PST/CEST/UTC/etc

103,347

Solution 1

AFAIK the time zone abbreviations are not recognized. However if you replace the abbreviation with the time zone offset, it will be OK. E.g.:

DateTime dt1 = DateTime.ParseExact("24-okt-08 21:09:06 CEST".Replace("CEST", "+2"), "dd-MMM-yy HH:mm:ss z", culture);
DateTime dt2 = DateTime.ParseExact("24-okt-08 21:09:06 CEST".Replace("CEST", "+02"), "dd-MMM-yy HH:mm:ss zz", culture);
DateTime dt3 = DateTime.ParseExact("24-okt-08 21:09:06 CEST".Replace("CEST", "+02:00"), "dd-MMM-yy HH:mm:ss zzz", culture);

Solution 2

The quick answer is, you can't do it.


Here is why,

There is a definitive database of world timezones, you can get it from the IANA here.

The problem is, the 3 or 4 letter abbreviations have a many-to-one association with the IANA timezones. For instance "AMT" means different things, depending on your culture, what part of the world you are in and the context of your application.

AMT "Armenia Time" Asia          UTC + 4 hours 
AMT "Amazon Time"  South America UTC - 4 hours 

If you really want to tackle this, I suggest using Noda Time to represent your Instances. You'll have to write some code to convert the abbreviations to a standard IANA timezone.

We can't do this for you, it depends on the context of your application.


Another good example is "CST".

CST "China Standard Time"   Asia            UTC + 8 hours 
CST "Central Standard Time" Central America UTC - 6 hours 
CST "Cuba Standard Time"    Caribbean       UTC - 5 hours 
CST "Central Standard Time" North America   UTC - 6 hours 

Solution 3

Dictionary of abbreviations if you decide to go the search&replace route (I did).

Dictionary<string, string> _timeZones = new Dictionary<string, string>() {
            {"ACDT", "+1030"},
            {"ACST", "+0930"},
            {"ADT", "-0300"},
            {"AEDT", "+1100"},
            {"AEST", "+1000"},
            {"AHDT", "-0900"},
            {"AHST", "-1000"},
            {"AST", "-0400"},
            {"AT", "-0200"},
            {"AWDT", "+0900"},
            {"AWST", "+0800"},
            {"BAT", "+0300"},
            {"BDST", "+0200"},
            {"BET", "-1100"},
            {"BST", "-0300"},
            {"BT", "+0300"},
            {"BZT2", "-0300"},
            {"CADT", "+1030"},
            {"CAST", "+0930"},
            {"CAT", "-1000"},
            {"CCT", "+0800"},
            {"CDT", "-0500"},
            {"CED", "+0200"},
            {"CET", "+0100"},
            {"CEST", "+0200"},
            {"CST", "-0600"},
            {"EAST", "+1000"},
            {"EDT", "-0400"},
            {"EED", "+0300"},
            {"EET", "+0200"},
            {"EEST", "+0300"},
            {"EST", "-0500"},
            {"FST", "+0200"},
            {"FWT", "+0100"},
            {"GMT", "GMT"},
            {"GST", "+1000"},
            {"HDT", "-0900"},
            {"HST", "-1000"},
            {"IDLE", "+1200"},
            {"IDLW", "-1200"},
            {"IST", "+0530"},
            {"IT", "+0330"},
            {"JST", "+0900"},
            {"JT", "+0700"},
            {"MDT", "-0600"},
            {"MED", "+0200"},
            {"MET", "+0100"},
            {"MEST", "+0200"},
            {"MEWT", "+0100"},
            {"MST", "-0700"},
            {"MT", "+0800"},
            {"NDT", "-0230"},
            {"NFT", "-0330"},
            {"NT", "-1100"},
            {"NST", "+0630"},
            {"NZ", "+1100"},
            {"NZST", "+1200"},
            {"NZDT", "+1300"},
            {"NZT", "+1200"},
            {"PDT", "-0700"},
            {"PST", "-0800"},
            {"ROK", "+0900"},
            {"SAD", "+1000"},
            {"SAST", "+0900"},
            {"SAT", "+0900"},
            {"SDT", "+1000"},
            {"SST", "+0200"},
            {"SWT", "+0100"},
            {"USZ3", "+0400"},
            {"USZ4", "+0500"},
            {"USZ5", "+0600"},
            {"USZ6", "+0700"},
            {"UT", "-0000"},
            {"UTC", "-0000"},
            {"UZ10", "+1100"},
            {"WAT", "-0100"},
            {"WET", "-0000"},
            {"WST", "+0800"},
            {"YDT", "-0800"},
            {"YST", "-0900"},
            {"ZP4", "+0400"},
            {"ZP5", "+0500"},
            {"ZP6", "+0600"}
        };

Solution 4

I have two answers because I'm not exactly sure what you are asking.

1) I see you are using CultureInfo, so if you just want to format the date and time to be culture specific, I would separate the date/time and timezone, apply culture method on the date/time and append the timezone. If "CEST" is different for different cultures, you will have to change it by listing all the options (maybe in a case statement).

2) If you want date/time to be converted to another timezone, you can't use CultureInfo,

I suggest reading: http://msdn.microsoft.com/en-us/library/ms973825.aspx

You can also use the .net framework 3.5 class TimeZoneInfo (different from TimeZone) to make your life easier.

http://msdn.microsoft.com/en-us/library/system.timezoneinfo.aspx

Solution 5

This is how:

  1. Get the string (precondition: format: ddd, dd MMM yyyy HH:mm:ss zzz)
  2. Get the last whitespace
  3. Remove zzz from string, but save value of zzz
  4. Lookup offset for zzz
  5. Add offset to string
string dateString = reader.ReadContentAsString();
int timeZonePos = dateString.LastIndexOf(' ') + 1;
string tz = dateString.Substring(timeZonePos);
dateString = dateString.Substring(0, dateString.Length - tz.Length );
dateString += s_timeZoneOffsets[tz];

// https://msdn.microsoft.com/en-us/library/w2sa9yss(v=vs.110).aspx
//string es = reader.ReadElementString("pubDate");
this.m_value = System.DateTime.ParseExact(dateString, "ddd, dd MMM yyyy HH:mm zzz", System.Globalization.CultureInfo.InvariantCulture);

with

private static System.Collections.Generic.Dictionary<string, string> s_timeZoneOffsets =
    new System.Collections.Generic.Dictionary<string, string>() {
    {"ACDT", "+10:30"},
    {"ACST", "+09:30"},
    {"ADT", "-03:00"},
    {"AEDT", "+11:00"},
    {"AEST", "+10:00"},
    {"AHDT", "-09:00"},
    {"AHST", "-10:00"},
    {"AST", "-04:00"},
    {"AT", "-02:00"},
    {"AWDT", "+09:00"},
    {"AWST", "+08:00"},
    {"BAT", "+03:00"},
    {"BDST", "+02:00"},
    {"BET", "-11:00"},
    {"BST", "-03:00"},
    {"BT", "+03:00"},
    {"BZT2", "-03:00"},
    {"CADT", "+10:30"},
    {"CAST", "+09:30"},
    {"CAT", "-10:00"},
    {"CCT", "+08:00"},
    {"CDT", "-05:00"},
    {"CED", "+02:00"},
    {"CET", "+01:00"},
    {"CEST", "+02:00"},
    {"CST", "-06:00"},
    {"EAST", "+10:00"},
    {"EDT", "-04:00"},
    {"EED", "+03:00"},
    {"EET", "+02:00"},
    {"EEST", "+03:00"},
    {"EST", "-05:00"},
    {"FST", "+02:00"},
    {"FWT", "+01:00"},
    {"GMT", "+00:00"},
    {"GST", "+10:00"},
    {"HDT", "-09:00"},
    {"HST", "-10:00"},
    {"IDLE", "+12:00"},
    {"IDLW", "-12:00"},
    {"IST", "+05:30"},
    {"IT", "+03:30"},
    {"JST", "+09:00"},
    {"JT", "+07:00"},
    {"MDT", "-06:00"},
    {"MED", "+02:00"},
    {"MET", "+01:00"},
    {"MEST", "+02:00"},
    {"MEWT", "+01:00"},
    {"MST", "-07:00"},
    {"MT", "+08:00"},
    {"NDT", "-02:30"},
    {"NFT", "-03:30"},
    {"NT", "-11:00"},
    {"NST", "+06:30"},
    {"NZ", "+11:00"},
    {"NZST", "+12:00"},
    {"NZDT", "+13:00"},
    {"NZT", "+12:00"},
    {"PDT", "-07:00"},
    {"PST", "-08:00"},
    {"ROK", "+09:00"},
    {"SAD", "+10:00"},
    {"SAST", "+09:00"},
    {"SAT", "+09:00"},
    {"SDT", "+10:00"},
    {"SST", "+02:00"},
    {"SWT", "+01:00"},
    {"USZ3", "+04:00"},
    {"USZ4", "+05:00"},
    {"USZ5", "+06:00"},
    {"USZ6", "+07:00"},
    {"UT", "-00:00"},
    {"UTC", "-00:00"},
    {"UZ10", "+11:00"},
    {"WAT", "-01:00"},
    {"WET", "-00:00"},
    {"WST", "+08:00"},
    {"YDT", "-08:00"},
    {"YST", "-09:00"},
    {"ZP4", "+04:00"},
    {"ZP5", "+05:00"},
    {"ZP6", "+06:00"}
};
Share:
103,347
thelsdj
Author by

thelsdj

C# business logic programmer by day, electronic music and science fiction fan by night

Updated on July 08, 2022

Comments

  • thelsdj
    thelsdj almost 2 years

    I'm trying to parse an international datetime string similar to:

    24-okt-08 21:09:06 CEST
    

    So far I've got something like:

    CultureInfo culture = CultureInfo.CreateSpecificCulture("nl-BE");
    DateTime dt = DateTime.ParseExact("24-okt-08 21:09:06 CEST",
        "dd-MMM-yy HH:mm:ss ...", culture);
    

    The problem is what should I use for the '...' in the format string? Looking at the Custom Date and Time Format String MSDN page doesn't seem to list a format string for parsing timezones in PST/CEST/GMT/UTC form.

  • Vitaliy Ulantikov
    Vitaliy Ulantikov about 11 years
    Will this handle Daylight Time?
  • Matt Johnson-Pint
    Matt Johnson-Pint over 8 years
    Sorry, but this approach is unreliable. Any hardcoded list of abbreviation to offset is opinionated with regard to ambiguities, and is just a snapshot in time.
  • Jussi Palo
    Jussi Palo over 8 years
    Of course it is. It is equally (un)reliable as using these non-standardized time zones in the first place. My answer is just backing up the accepted answer. Remember to down-vote that as well.
  • Vincent Vancalbergh
    Vincent Vancalbergh over 8 years
    Some people (I'd go even further and say most) actually only receive data pertinent to a single culture. This approach, while inperfect, will suffice.
  • gzak
    gzak over 8 years
    No, it will not, since the offset is being specified manually here.
  • gzak
    gzak over 8 years
    Technically this is still doable, since you can pass a CultureInfo object to the parser to disambiguate your context.
  • Jodrell
    Jodrell about 8 years
    @gzak, yes, if you wanted the abbreviations localised to a passed culture you could work out the mappings.
  • Panagiotis Kanavos
    Panagiotis Kanavos about 7 years
    This is unreliable, even for a single culture. Russia changed DST rules many times in the past 4 years. Mapping the abbreviation to an IANA or Windows tz name and looking up the current rules is far more reliable
  • Matt Johnson-Pint
    Matt Johnson-Pint over 6 years
    No you couldn't. Culture info will tell you things about the user's language and cultural preferences. It will tell you nothing about a user's time zone. My culture might be en-US even if I'm visiting Japan.
  • Jodrell
    Jodrell over 6 years
    @MattJohnson but if your culture is en-US we could infer that CST meant "Central Standard Time" North America UTC -6 to you regardless of your timezone, even if it were UTC-5. Of course, what is appropriate for one application may be inappropriate for another. In abstract, you can't tell, as my answer states. With enough context, part of which would be he culture, we could tell.
  • Matt Johnson-Pint
    Matt Johnson-Pint over 6 years
    "en-US" is intended to mean "English as spoken in the United States". In other words, US is referring to dialect, not location. Why would it be correct to infer Central Standard Time from CST just because I speak English in the way that Americans do? Sure, Americans say "CST", but we might also say that referring to China - especially if we happen to be in China. :)
  • Jodrell
    Jodrell over 6 years
    @MattJohnson, as we are agreeing, additional context is necessary.
  • JohnB
    JohnB about 6 years
    Thank you. Yes there were lots of bad answers.
  • Ryan Bemrose
    Ryan Bemrose almost 6 years
    This is still a bad answer for reasons discussed elsewhere on this page. You are hardcoding assumptions about what abbreviations like "AMT" or "CST" mean. The problem is this question has no good answer; the codes are ambiguous, and no lookup table can be definitive. These assumptions may have sufficed to solve OP's problem, but they were not stated in the question.
  • thelem
    thelem almost 6 years
    It will, provided you have a Replace call for all the timezones you might receive and the source date uses the correct timezone (e.g. doesn't use EST when they mean EDT)
  • MIKE
    MIKE over 5 years
    so wait.. does it handle daylight time or not?
  • jpmc26
    jpmc26 over 5 years
    Do not put "Necromancing" declarations in your posts. These are clutter; SO has no policy about activity on old questions. If anything, it is somewhat encouraged since new answers arise as technology changes.
  • jpmc26
    jpmc26 over 5 years
    @MattJohnson Because as an United States English speaker in Japan using your device configured to your normal culture, you would probably not type CST in an application to mean something other than U.S. Central. Admittedly, it's not definitive, but it's okay as a heuristic.
  • Stefan Steiger
    Stefan Steiger over 5 years
    @MIKE: Considering CEST (central european summer time) and CET (central european [winter] time) are not the same, then yes. However, a call to replace is risky, as you don't know if CEST/CET occurs in the date string for culture X.
  • boatcoder
    boatcoder over 2 years
    If given a choice between right some of the time and right none of the time, I'll take "some" of the time for the project I'm currently working on. Right now I'd have to punt without using a crutch like this which might get it wrong.....
  • Stefan Steiger
    Stefan Steiger over 2 years
    @jpmc26: I put those declaration in my posts when I answer an old question. The idea is, that people see that low-vote-count compared to other answers is due to that the answer is new, and not that the answer is bad. Though, it is true that one could already see this when looking at the answer-date - so consequently, that declaration is always redundant.
  • Stefan Steiger
    Stefan Steiger over 2 years
    @Ryan Bemrose: Actually, I'm assuming they are windows-timezones, so the abbrevations are unambiguous. It's true however, that IANA time-zones would be ambiguous, thus there would be no solution. Assuming the input values are from windows-machines, which would be true in 95% of cases of desktop machines, this works best. If you'd be running the code on a Linux-machine however, you'd first have to map the posix-timezones generated from C# to windows-timezones for lookup-purposes. I have the code for this somewhere, but if it's unambiguous, is a good question.
  • Stefan Steiger
    Stefan Steiger over 2 years
    Anybody, you might be interested in github.com/ststeiger/ews-managed-api/blob/master/…