How to convert a datetime to specific timezone in c#? - c#

I need help converting a DateTime to a specific time zone. What I have below is not working correctly.
gmTime = 03/02/2013 1:00:00 AM
TimeZoneInfo timeZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
var time = timeZoneInfo.ConvertTime(gmTime, timeZone);
When I debug the value of time, which should be 03/01/2013 8:00:00 PM when the zone is applied, it comes back as 03/02/2013 1:00:00 AM.
If I do time.ToLocalTime() then I get the correct value. However, I need to convert time to different time zones.

DateTime objects have a "Kind" variable which helps TimeZoneInfo know how to treat it. In the MSDN documentation for TimeZone.ConvertTime it has the following:
DateTimeKind.Local, Converts the local time to the time in destinationTimeZone.
DateTimeKind.Utc, Converts Coordinated Universal Time (UTC) to the time in destinationTimeZone.
DateTimeKind.Unspecified, Assumed to be Local.
For example:
Console.WriteLine("Local time zone is '{0}'.", TimeZoneInfo.Local.Id);
var gmTime = new DateTime(2013, 03, 02, 01, 00, 00, DateTimeKind.Utc);
var localTime = new DateTime(2013, 03, 02, 01, 00, 00, DateTimeKind.Local);
var unspecifiedTime = new DateTime(2013, 03, 02, 01, 00, 00);
var timeZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
var gmTimeConverted = TimeZoneInfo.ConvertTime(gmTime, timeZone); // 03/02/2013 8:00:00AM
var localTimeConverted = TimeZoneInfo.ConvertTime(localTime, timeZone); // 03/02/2013
var unspecifiedTimeConverted = TimeZoneInfo.ConvertTime(unspecifiedTime, timeZone);
Console.WriteLine("Converting GMT to EST: {0}", gmTimeConverted);
Console.WriteLine("Converting Local to EST: {0}", localTimeConverted);
Console.WriteLine("Converting Unspecified to EST: {0}", unspecifiedTimeConverted);
Results in:
Local time zone is 'Pacific Standard Time'.
Converting GMT to EST: 3/1/2013 8:00:00 PM
Converting Local to EST: 3/2/2013 4:00:00 AM
Converting Unspecified to EST: 3/2/2013 4:00:00 AM
Or if your local timezone is 'Eastern Standard Time' you get these results
Local time zone is 'Eastern Standard Time'.
Converting GMT to EST: 3/1/2013 8:00:00 PM
Converting Local to EST: 3/2/2013 1:00:00 AM
Converting Unspecified to EST: 3/2/2013 1:00:00 AM
If you'd like TimeZoneInfo to treat 'Unspecified' like Utc, you should function like TimeZoneInfo.ConvertTimeFromUtc. Again from MSDN documentation
DateTimeKind.Local, Throws an ArgumentException.
DateTimeKind.Unspecified or DateTimeKind.Utc, Converts from Coordinated Universal Time (UTC).

Try something like the following Chace
TimeZoneInfo estTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
DateTime estDateTime = TimeZoneInfo.ConvertTimeFromUtc(timeUtc, estTimeZone);

The following code will let you go from any arbitrary time zone to any other. We make use of DateTimeOffset which will allow you to pass the UTC Offset in. You may consider whether just using DateTimeOffset instead of DateTime will suit your needs. But if you want to use DateTime instead, here is some code that will do the conversion for you:
public DateTime ChangeTimeZone(DateTime dateTimeInput, TimeZoneInfo sourceTimeZone, TimeZoneInfo destTimeZone)
{
var zonedTime = new DateTimeOffset(DateTime.SpecifyKind(dateTimeInput, DateTimeKind.Unspecified),
sourceTimeZone.GetUtcOffset(dateTimeInput));
var utcTime = zonedTime.UtcDateTime;
return TimeZoneInfo.ConvertTime(utcTime, destTimeZone);
}
You may notice that we explicitly call SpecifyKind and set it to Unspecified. The reason for this is because if the Kind is specified on the dateTimeInput then the UtcOffset must match that Kind -- so if it is DateTimeKind.Utc, then that number must be 0. If it is Local, then it must be whatever the local time offset is or you will get an exception. Of course, if you already know the Kind then you could skip this function and just go straight to TimeZoneInfo.ConvertTime.

Related

C# DateTime - converting a DateTimeOffset to another TimeZone

When converting a DateTimeOffset to another TimeZone, the OffSet is incorrect.
I've read many articles and experimented for too many hours, but can't see what I'm missing here:
// It's June in the UK and we're in British Summer Time, which is 1 hour ahead of UTC (GMT)
var UKoffsetUtc = new TimeSpan(1, 0, 0);
// It's 4pm - declare local time as a DateTimeOffset
var UKdateTimeOffset = new DateTimeOffset(2020, 6, 17, 16, 0, 0, UKoffsetUtc);
// Convert to UTC as a date
var utc = DateTime.SpecifyKind(UKdateTimeOffset.UtcDateTime, DateTimeKind.Utc);
// Get Aus TimeZoneInfo
var AUSTimeZone = TimeZoneInfo.FindSystemTimeZoneById("AUS Eastern Standard Time");
// Check the Aus offset from UTC
var AUSOffset = AUSTimeZone.GetUtcOffset(utc);
Console.WriteLine(AUSOffset); // Output is 10 as expected
// Declare Aus Time as DateTimeOffset
var AUSDateTimeOffset = TimeZoneInfo.ConvertTimeFromUtc(utc, AUSTimeZone);
// The Aus Offset from UTC is not correct
Console.WriteLine(AUSDateTimeOffset.ToString("dd MM yyyy HH:mm zzz"));
The output is 18 06 2020 01:00 +01:00
Aus are 10 hours ahead of UTC (9 hours ahead of GMT) so the date and time are correct, but not the offset.
How can I get the correct offset in AUSDateTimeOffset?
You can create new offset and use it -
// Create new offset for UTC
var AUSOffset = new DateTimeOffset(utc, TimeSpan.Zero);
// Declare Aus Time as DateTimeOffset
var AUSDateTimeOffset = UKdateTimeOffset.ToOffset(AUSTimeZone.GetUtcOffset(AUSOffset));
Console.WriteLine(AUSDateTimeOffset.ToString("dd MM yyyy HH:mm zzz"));
Or:
Use ConvertTimeBySystemTimeZoneId as suggested by Jimi in the comment!
var finalDate = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(UKdateTimeOffset, "AUS Eastern Standard Time");
Console.WriteLine(finalDate.ToString("dd MM yyyy HH:mm zzz"));
The error is in this part:
var AUSDateTimeOffset = TimeZoneInfo.ConvertTimeFromUtc(utc, AUSTimeZone);
In that code, utc is a DateTime, and thus the resulting AUSDateTimeOffset is actually a DateTime. Its Kind will be DateTimeKind.Unspecified.
The conversion will have been done correctly, and thus you see the correct date and time in the result. However, the offset is wrong because it is not part of a DateTime. The documentation about the zzz specifier says:
With DateTime values, the "zzz" custom format specifier represents the signed offset of the local operating system's time zone from UTC, measured in hours and minutes. It doesn't reflect the value of an instance's DateTime.Kind property. For this reason, the "zzz" format specifier is not recommended for use with DateTime values.
Thus, the +01:00 is coming from your local time zone, not from the target time zone.
There are a few ways you could fix this:
You could make AUSDateTimeOffset a DateTimeOffset with the correct offset:
DateTime AUSDateTime = TimeZoneInfo.ConvertTimeFromUtc(utc, AUSTimeZone);
TimeSpan AUSOffset = AUSTimeZone.GetUtcOffset(utc);
DateTimeOffset AUSDateTimeOffset = new DateTimeOffset(AUSDateTime, AUSOffset);
You could use a UTC-based DateTimeOffset instead of a UTC-based DateTime:
DateTimeOffset utc = UKdateTimeOffset.ToUniversalTime();
DateTimeOffset AUSDateTimeOffset = TimeZoneInfo.ConvertTime(utc, AUSTimeZone);
You could just convert the orignal DateTimeOffset, as there's no need to convert to UTC first:
DateTimeOffset AUSDateTimeOffset = TimeZoneInfo.ConvertTime(UKdateTimeOffset, AUSTimeZone);
As Jimi pointed out in comments, you can even convert without constructing a TimeZoneInfo object at all:
DateTimeOffset AUSDateTimeOffset = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(UKdateTimeOffset, "AUS Eastern Standard Time");
Any of the above will give the same, correct response.
It's easy to get around:
var fromTime = DateTimeOffset.Parse("2020-06-17T16:00:00+01:00");
var timeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("AUS Eastern Standard Time");//TZConvert.GetTimeZoneInfo("Australia/Sydney");//for Mac
var toTime = fromTime.ToOffset(timeZoneInfo.GetUtcOffset(fromTime.UtcDateTime));
Console.Write(toTime.ToString("yyyy-MM-ddTHH:mm:sszzz")); //2020-06-18T01:00:00+10:00

Apply TimeZone to a specific date?

For example, server time is 11 pm.
User timezone, specified within the app, is US Mountain Standard Time.
So I need to get 4 pm, user time.
Tried with
var UserTimeZoneInfo = "US Mountain Standard Time";
var userTime =TimeZoneInfo.ConvertTimeToUtc(now, _UserTimeZoneInfo);
and this
var userTime = new DateTimeOffset(now, this._UserTimeZoneInfo.BaseUtcOffset);
but in both cases, I get 8am instead of 4pm. TimeZone difference gets added to server time , instead of subtracted. I see there are other DateTime functions, but not sure which one to use ?
You need to use ConvertTimeFromUtc method if you want change to specified timezone time from UTC.
var timeZone = TimeZoneInfo.FindSystemTimeZoneById("US Mountain Standard Time");
DateTime arizonaTime = TimeZoneInfo.ConvertTimeFromUtc(new DateTime(2017, 11, 9, 23, 0, 0,DateTimeKind.Utc), timeZone);
DotNetFiddle
You can use ConvertTime which Converts a time to the time in a particular time zone.
DateTime currentDt = DateTime.Now;
var timeZone = TimeZoneInfo.FindSystemTimeZoneById("US Mountain Standard Time");
var userTime = TimeZoneInfo.ConvertTime(currentDt, timeZone);

C# DateTime Convert from string to DateTime in differents TimeZones

I'm struggling with a problem. i have a string date looks like this, "2015-05-02 01:00:00", extracted from a database.
I know that it's british time, but my local time is belgian time.
I'm trying to store the date in UTC and in (CEST or CET depend of the season), converting it from the British time i've extract.
I tried to set Kind property to British time, but the result seems to be in local or utc time. So, i can do half of the job, but not the rest (e.g. I still need the CEST/CET time).
I tried to use this :
string dateString = (string) line["stringDate"];
DateTime ukTime = DateTime.Parse(dateString, new CultureInfo("en-GB", false));
DateTime belgianTime = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(ukTime, "Romance Standard Time");
The result is the same for both ukTime and belgianTime: 2015-05-02 01:00:00 with kind = unspecified.
It should be 2015-05-02 02:00:00 for belgianTime
If you just add the source time zone to the conversion method it gives the desired answer, even without specifying the IFormatProvider.
string dateString = (string) line["stringDate"];
DateTime ukTime = DateTime.Parse(dateString);
DateTime belgianTime = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(ukTime,
"GMT Standard Time",
"Romance Standard Time");
This gives time Kind == Unspecified. However if you use:
var belgianTime = TimeZoneInfo.ConvertTime(ukTime,
TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time"),
TimeZoneInfo.Local);
for the conversion, you get Kind == Local
Use the following line of code.
var time = DateTime.Parse(DateTime.Now.ToString());
var clientZone = TimeZoneInfo.FindSystemTimeZoneById("India Standard Time");
var utcTime = TimeZoneInfo.ConvertTimeToUtc(time, clientZone);
You have to use the ConvertTime method. ConvertTime
a quick sample -
string s = "2015-05-02 01:00:00";
var dt = new DateTime(2015, 05, 02, 1, 0, 0);
var t = TimeZoneInfo.ConvertTime(dt, TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time"),
TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time"));

How can I create a new instance of DateTime in specific time zone?

Given a specific TimeZoneInfo instance how can I create a new DateTime instance in the specified time zone? For example if I have:
var tz = TimeZoneInfo.FindSystemTimeZoneById("US Eastern Standard Time");
var date = new DateTime(2017, 1, 1, 0, 0, 0, DateTimeKind.Unspecified);
Console.WriteLine(TimeZoneInfo.ConvertTime(date, tz));
I am always getting 12/31/2016 7:00:00 PM regardless of what DateTimeKind I define (Utc, Local or Unspecified).
How can I declare a new DateTime that will be January 1st of 2017 at 0:00:00 in US Eastern Standard Time?
You can use TimeZoneInfo to retrieve your zone
You can find timezones here
var zn = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
to express that you are using a local eastern standard time use DateTimeOffset struct instead of DateTime
DateTimeOffset dateTimeOffset = new DateTimeOffset(new DateTime(2017, 1, 1, 0, 0, 0, DateTimeKind.Unspecified), zn.BaseUtcOffset);
Why DateTimeOffset
DateTimeOffset is a representation of instantaneous time (also known as absolute time).
you can use the timezoneID as you are using it to specify what timezone you want to create your datetime object.
TimeZoneInfo tzone= TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard
Time");
DateTime dt = DateTime.Now;
later you just convert the datetime to your required timezone.
var datetime2 = TimeZoneInfo.ConvertTimeFromUtc(dt , tzone);
this is the link where you can find all timezones ID. TimeZoneIDs
Thank you, hope this can help you.

c# DataTime: Assume EST convert to GTM

I have a server running in New York that saves a DateTime into the database in local time.
I then have a client application running in GMT timezone that needs to save down a DateTime in the same local New York time
Can I do using:
TimeZoneInfo.ConvertTime(DateTime.Now, TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"))
Or I need to consider daylight savings?
Now in my UI I need to display 2 columns. 1) the DateTime from the database and the DateTime in the database converted to GMT
How can I do this?
The TimeZoneInfo class should give you what you need.
var date = (DateTime)reader[0]; // Retrieve data from database however you normally get it
var est = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");
var utcTime = TimeZoneInfo.ConvertTimeToUtc(date, est);
var localTime = utcTime.ToLocalTime();
Edit: You modified your question to indicate you have looked at TimeZoneInfo, so this doesn't add much anymore. However to resolve the ambiguous time issue mentioned by Jon, take a look at the IsAmbiguousTime() and GetAmbiguousTimeOffsets() methods to be able to detect values that can't be definitively converted.
Here's a sample to show that it should work as expected. That is, it will do the DST conversion.
DateTime dt1 = new DateTime(2016, 06, 01, 08, 00, 00, DateTimeKind.Unspecified); // Daylight saving time
DateTime dt2 = new DateTime(2016, 12, 01, 08, 00, 00, DateTimeKind.Unspecified); // Standard time
var dt1Converted = TimeZoneInfo.ConvertTimeToUtc(dt1,
TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"));
var dt2Converted = TimeZoneInfo.ConvertTimeToUtc(dt2,
TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time"));
var diff1 = (dt1Converted - dt1).TotalHours;
var diff2 = (dt2Converted - dt2).TotalHours;
Console.WriteLine($"dt1: {dt1}, converted: {dt1Converted}, diff: {diff1}");
Console.WriteLine($"dt2: {dt2}, converted: {dt2Converted}, diff: {diff2}");
Output:
dt1: 2016-06-01 08:00:00, converted: 2016-06-01 12:00:00, diff: 4
dt2: 2016-12-01 08:00:00, converted: 2016-12-01 13:00:00, diff: 5
Is there any chance you can change this to use DateTimeOffset ? It was designed to resolve all of these problems

Categories

Resources