leora
leora

Reputation: 196539

What is the correct way to convert this to a date time in C#?

I have an asp.net-mvc site that is reading a string field from a sharepoint site and i get a string

var stringDate = "3/11/2016 12:05:00 AM"

I was told the time is in Eastern Standard Time. I try to convert to a date using:

 var date = DateTime.Parse(stringDate);

and I think display it using this format:

<%= Model.Date.ToString("MMM dd HH:mm")

When I run this on a machine in the US, I get

Mar 14 00:05 (which is what i want to display)

but when i run the same code on a machine in London, I get:

Mar 14 05:05 (which is NOT what i want to display)

What is the right way to show the date in Eastern Standard Time regardless of where the server is hosted?

Upvotes: 0

Views: 943

Answers (5)

Alexander Bell
Alexander Bell

Reputation: 7918

The answer depends on how the time string was generated on the remote server. For example, if the string represents the local time on that remote server, then you can try to ParseExact() and ToUniversalTime() to get GMT (Greenwich Mean Time, aka UTC), then subtract 5 hours to get EST (this operation should be performed on the remote server):

DateTime _ny = 
DateTime.ParseExact("3/11/2016 12:05:00 AM", 
"mm/dd/yyyy HH:mm:ss UTC", 
CultureInfo.InvariantCulture).ToUniversalTime().AddHours(-5);

Note: Time in NY City is EST (UTC-05:00, or GMT-05:00).

The solution could be further extended by using TimeZoneInfo class to calculate the offset (re: https://msdn.microsoft.com/en-us/library/system.timezoneinfo(v=vs.110).aspx). Pertinent to your question, US Eastern Standard Time ID is 720 (UTC-05:00) (re: https://msdn.microsoft.com/en-us/library/gg154758.aspx).

Also, be aware that if you read the data from remote server, then you have to adjust the solution pertinent to that server time zone. Once I was facing similar problem, caused by my real-time web app residing at remote Azure cloud server, so I used the similar solution (re: Listing 10, http://www.codeproject.com/Articles/884183/enRoute-Real-time-NY-City-Bus-Tracking-Web-App)

/// <summary>
/// Get the accurate NY Time value
/// </summary>
/// <returns>DateTime</returns>
protected DateTime GetTimeNYC()
{
    try { return DateTime.Now.ToUniversalTime().AddHours(_offsetHour); }
    catch { throw; }
}

Hope this may help.

Upvotes: 0

Enigmativity
Enigmativity

Reputation: 117064

You should use DateTimeOffset for this as it has been built to deal with timezones properly.

Then you can do this:

var stringDate = "3/11/2016 12:05:00 AM";

var value =
    DateTimeOffset
        .ParseExact(
            stringDate + "-05:00",
            "M/dd/yyyy hh:mm:ss ttzzz",
            System.Globalization.CultureInfo.GetCultureInfo("en-us"));

This will always parse your input in EST ("-05:00") time.

When I write the value to the console you get this:

2016/03/11 00:05:00 -05:00

It just knows about the time zone. There's no confusion here.

Upvotes: -1

Tahbaza
Tahbaza

Reputation: 9548

The question was changed after my first answer was provided so here's a different answer to the changed question.

The way to keep datetime straight globally is to always capture and persist datetime values in UTC and then translate to the context time zone for use/display.

In this case adding 5 hours to the provided, parsed value gives us UTC if Daylight Savings Time is ignored. Any variations in offset due to Daylight Savings Time must be taken account and the offset adjusted accordingly when determining UTC.

DateTime dtInUTC = DateTime.ParseExact("3/11/2016 12:05:00 AM", "M/d/yyyy hh:mm:ss tt",
    CultureInfo.InvariantCulture).AddHours(5); // the source string is expressed in ET
Console.WriteLine(ToLocalTime(dtInUTC, "Eastern Standard Time")); // for ET
Console.WriteLine(ToLocalTime(dtInUTC, "GMT Standard Time")); // for GMT

This is what I use to convert timezone for context:

private static DateTime ToLocalTime(DateTime utcDateTime, string tzId) {
   TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById(tzId);
   return TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, tz);
}

Normally I'd keep the user time zone with a given user's profile, not hardcode it, but you get the idea.

Upvotes: 3

Tahbaza
Tahbaza

Reputation: 9548

Since you know it's in Eastern Time it's important to retain that truth in the parsed value. I'd append the -5 offset and parse the provided string. Once you parse it as ET explicitly the following

DateTime t = DateTime.ParseExact("3/11/2016 12:05:00 AM -05:00", 
    "M/d/yyyy hh:mm:ss tt zzz", CultureInfo.InvariantCulture);
Console.WriteLine(t.ToUniversalTime());

...results in this:

3/11/2016 5:05:00 AM

I suspect the "flexible" behavior you describe in your question is the result of the following value apparently being the default in the Parse method: AssumeLocal

Here is an excerpt of the relevant DateTime.ParseExact doc, here.

AssumeLocal: Specifies that if s lacks any time zone information, it is assumed to represent a local time. Unless the DateTimeStyles.AdjustToUniversal flag is present, the Kind property of the returned DateTime value is set to DateTimeKind.Local.

AssumeUniversal: Specifies that if s lacks any time zone information, it is assumed to represent UTC. Unless the DateTimeStyles.AdjustToUniversal flag is present, the method converts the returned DateTime value from UTC to local time and sets its Kind property to DateTimeKind.Local.

Daylight Savings Time is a problem, but not if you capture the current offset and append it appropriately in the parsing instead of just hardcoding -05:00.

Upvotes: 1

Jonathan
Jonathan

Reputation: 1027

Try it:

DateTime _dt = DateTime.ParseExact(dateString, "your format",CultureInfo.InvariantCulture);

I hope it help.

Upvotes: -1

Related Questions