简体   繁体   中英

Converting DateTime in string with GMT to local time in C#

I have a date in a CSV file which is coming as a string to SSIS Script task.

I need to convert the date to the local time based on the GMT offset present in the string - I want to convert it to datetime and save it in the DB.

The datetime I am getting is

2018-06-21 08:55 GMT-0400

I need to store this as

2018-06-21 08:55

assuming my local time is EST.

For this I am using the following code:

 DateTime dt;        // datetime variable
 string str;                // string variable
 string format = "yyyy-MM-dd HH:mm:ss";
 str = Row.Dateused;

 if (Row.Dateused_IsNull == false)
 {
     // convert datetime format to standard one
     DateTime.TryParseExact(str, format, CultureInfo.InvariantCulture,DateTimeStyles.AssumeUniversal |DateTimeStyles.AdjustToUniversal,out dt);
     Row.Dateused = dt.ToString();
 }

But when I execute it, this is the output I am getting:

1/1/0001 12:00:00

Can someone tell me where I am going wrong?

Short Version

The correct pattern for ParseExact is "yyyy-MM-dd HH:mm 'GMT'zzzzz" . The best type to use is DateTimeOffset .

If DateTime is used, it should have the DateTimeStyles.AdjustToUniversal in order to get the UTC time.

In any case, pass the strongly typed value to the database instead of strings to avoid conversion errors.

Long Version

The correct type when dealing with timezones is DateTimeOffset , not DateTime . DateTime doesn't understand timezones so it assumes that times are either UTC or the local timezone of the machine that runs this code. It doesn't understand what local actually means.

Both DateTime and DateTimeOffset can parse this string using the correct pattern :

"yyyy-MM-dd HH:mm 'GMT'zzzzz"

For example :

var pattern="yyyy-MM-dd HH:mm 'GMT'zzzzz";
var dt=DateTimeOffset.ParseExact("2018-06-21 08:55 GMT-0400",pattern,CultureInfo.InvariantCulture);
Console.WriteLine("{0:O}",dt);

Will print :

2018-06-21T08:55:00.0000000-04:00

The DateTime property can return the date and time without the offset, with DateTimeKind.Unspecified. The following code :

 DateTime dtOnly=dt.DateTime;
 Console.WriteLine("{0:O}",dtOnly);

Will print :

2018-06-21T08:55:00.0000000

It's still better to use datetimeoffset in the database and avoid errors eg due to daylight time conversions. If the type has to be datetime (why?) it should be converted to UTC first with UtcDateTime . This will lose the offset information though.

Console.WriteLine("{0:O}",dt.UtcDateTime);

Will print :

2018-06-21T12:55:00.0000000Z

With DateTimeKind.Utc

What about DateTime?

DateTime.ParseExact will also work, but the result will depend on the local timezone. That's be cause ParseExact will see the offset and return either a DateTime adjusted to the local timezone, whatever that is, or to UTC. The only way it will return 08:55 will be if that's the timezone offset of the current machine.

On my machine the offset is +3:00. So

DateTime.ParseExact("2018-06-21 08:55 GMT-0400",pattern,CultureInfo.InvariantCulture,DateTimeStyles.AssumeLocal);

Will return 2018-06-21T15:55:00 with Kind = Local. Same for AssumeUniversal since well, the string isn't UTC, it has an offset.

DateTimeStyles.AdjustToUniversal will result in 2018-06-21T12:55:00 with Kind Utc as it should. That is the correct the corresponding UTC value which can be stored in the database without causing too much confusion,

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM