Caius Jard
Caius Jard

Reputation: 74605

c# parse string (without timezone) to DateTime, taking DST into account

I've read many SO articles, but I don't seem to be able to find a good answer to the problem. Posted suggestions include functions that convert dates to and from strings more then once, concatenating bits on the end and it all just seems... messy

So to the problem:

We have servers around the world. All servers run in their own local time and keep logs with time entries that are local to the server. Some servers are in DST observing areas, others arent

Suppose I have these strings from a log: 2013-01-01 12:34:56, 2013-07-01 12:34:56 And I know that this server is in New York so it's UTC-5 or UTC-4 when DST is in operation

And I have the same strings from a log on a server in Hong Kong, where DST does not apply and the time zone is +8

What I'm after is a block of code where I can tell it:

And the code will parse the string into a DateTimeOffset, where the offset is adjusted according to DST if the time being parsed is DST relevant

For example: NY server log says "2013-01-01 ..." DST does NOT apply to this date in JANUARY so the date parsed should be: 12:34:56 in new york time, a.k.a 17:34:56 in UTC (because it's -5, no DST)

NY server log says "2013-07-01 ..." DST DOES apply to this date in june so the date parsed should be: 12:34:56 in new york time, a.k.a 16:34:56 in UTC (because it's -4, with the DST)

HK server, both date times parse to 04:34:56 UTC

Thanks guys

Upvotes: 3

Views: 2948

Answers (2)

Spontifixus
Spontifixus

Reputation: 6660

To get the UTC-times of the time logged in the different log files you will need to know the names of the local time zones. Then you can use the DateTimeOffset-struct TimeZoneInfo-class to calculate the UTC-times:

public DateTime ParseAsUtc(string logDate, string timezoneName)
{
    var timeZone = TimeZoneInfo.FindSystemTimeZoneById(timezoneName);
    var localDate = DateTime.Parse(logDate);
    var offset = new DateTimeOffset(localDate, timeZone.GetUtcOffset(localDate));
    return offset.ToUniversalTime().DateTime;
}

ParseAsUtc("2013-01-01 12:34:56", "Eastern Standard Time"); //01.01.2013 17:34:56
ParseAsUtc("2013-07-01 12:34:56", "Eastern Standard Time"); //01.07.2013 16:34:56
ParseAsUtc("2013-01-01 12:34:56", "China Standard Time");   //01.01.2013 04:34:56
ParseAsUtc("2013-01-01 12:34:56", "China Standard Time");   //01.07.2013 04:34:56

Upvotes: 5

Jon Skeet
Jon Skeet

Reputation: 1500825

Firstly, I'd strongly recommend that you change the system to log in UTC everywhere. It'll make your life much simpler.

If you're really stuck with what you've got, you should use DateTime.TryParseExact with a DateTimeStyles of just 0 (the default). That will give you a value with a DateTimeKind of Unspecified, which is what you want. (It's not UTC, and it's not local to the machine doing the parsing.)

You can then use TimeZoneInfo.GetUtcOffset (with the right time zone for that log) to work out the offset, and create a DateTimeOffset from the two together.

As a completely biased aside, you could also change to use the Noda Time project I maintain, which will allow your code to be much simpler to understand :)

Upvotes: 6

Related Questions