How to Convert Date Time using Offset values - c#

I Need to convert a DateTime accordign to the given offset value.
I have values like:
-08:00
-07:00
+08:00
+07:00
+02:00
+05:30
How I can convert a date time according to these given offset values.
I tried:
string t = "Pacific Standard Time";
var tInfo = TimeZoneInfo.FindSystemTimeZoneById(t);
var data = TimeZoneInfo.ConvertTime(DateTime.Now, tInfo);
this is fine to but I need to convert based on offset value.
Plz suggest here how to convert it.
Thanks

The type that stores timezone offsets is DateTimeOffset. If you care about offsets use that type instead of DateTime. Otherwise you won't be able to compare dates with different offsets unless you also store the offset along with the datetime.
Properties like DateTimeOffset.Now and DateTimeOffset.UtcNow will return the current time in the machine's timezone or UTC respectively.
Creating a DateTimeOffset from a DateTime in a specific offset is as simple as calling the appropriate constructor, eg :
var pstTime=new DateTimeOffset(2019,1,14,1,0,0,new TimeSpan(-8,0,0));
You can convert a DateTimeOffset value to different offsets with ToOffset, eg :
var eastEuropeTime=pstTime.ToOffset(new TimeSpan(2,0,0));
This will return 11am.
ToUniversalTime will return the time in UTC, ie +00:00:
var utcTime=pstTime.ToUniversalTime();
Which returns 9 am.
Conversion from/to DateTime
You can also construct a DateTimeOffset from an existing DateTime value. The constructor check the input DateTime's Kind property and refuses to use invalid offsets if DateTime.Kind.
For Utc the only valid value is 00:00.
var now=DateTime.UtcNow;
var utcOffset=new DateTimeOffset(now, TimeSpan.Zero);
utcOffset.Dump();
For a local time, the only valid value is the machine's offset. To convert a local time to DateTimeOffset, you can retrieve its offset from TimeZoneInfo.Local :
var now=DateTime.Now;
var localOffset=new DateTimeOffset(now, TimeZoneInfo.Local.GetUtcOffset(now));
Arbitrary Offsets
In some cases we may want to use a DateTime as is with a specific offset. Many web sites (especially forums) for example allow users to specify their timezone and thus avoid problems with timezone detection on the browser.
In other cases, the offset may be stored separately or come from an IANA timezone name.
To use an arbitrary offset, the DateTime's Kind must have the Unspecified:
var date=new DateTime(2019,01,15,18.17.00, DateTimeKind.Unspecified);
var pst=new DateTimeOffset(date,new TimeSpan(-8,0,0));
This is useful eg when loading datetime values from a database. DateTime values loaded from a database are Unspecified.
Values that come from code or input controls may already be Local or UTC. In this case we need to use DateTime.SpecifyKind to create a new Unspecified DateTime value :
var date=DateTime.SpecifyKind(domeDate,DateTimeKind.Unspecified);
var pst=new DateTimeOffset(date,new TimeSpan(-8,0,0));

What you can use is DateTimeOffset.Parse
For example:
var offsetValue = "+08:00";
var now = DateTime.Now;
var nowString = now.ToString("dd/MM/yyyy HH:mm:ss");
var offsetDateTime = DateTimeOffset.Parse($"{nowString} {offsetValue}");
Please note the above is just an example, this is ignoring any sort of culture specific issues etc.

Related

DateTime format usage in C#

I have following date time format
TimeZoneDetails.TimeZoneInstance ="Australia/Perth"
DateTime Today = TimeZoneInfo.ConvertTimeFromUtc(DateTime.UtcNow,TimeZoneDetails.TimeZoneInstance);
Does today variable store the date based on timezone?
string date = "2020-03-19";
DateTime startdate = DateTime.Parse(date);
What is the timezone of startdate variable?
DateTime enddate = TimeZoneInfo.ConvertTimeToUtc(startdate, TimeZoneDetails.TimeZoneInstance);
Will enddate variable converted to UTC time?
A few things:
"Australia/Perth" is an IANA time zone identifier. It will work with .NET on Linux or Mac OSX, but on Windows you'd have to use "W. Australia Standard Time" instead. Alternatively, you could use my TimeZoneConverter library to work with either form of identifier on any platform.
In your code:
TimeZoneDetails.TimeZoneInstance ="Australia/Perth"
This isn't generally valid. Given the usage in the rest of your code, your TimeZoneInstance would have to be a TimeZoneInfo object. You can't assign a string in that way. You'd have to use a function like TimeZoneInfo.FindSystemTimeZoneById, or TZConvert.GetTimeZoneInfo from TimeZoneConverter, or a similar function in your own code. (Also you're missing a semicolon.)
In your code:
string date = "2020-03-19";
DateTime startdate = DateTime.Parse(date);
You asked what the time zone is in the startdate variable. That's a DateTime, which does not store time zone or offset information. It only has a .Kind property, which is of type DateTimeKind. In your example, it will be DateTimeKind.Unspecified. Also note the time will be set to 00:00:00.0000000.
You can read more about this in the documentation, here and here.
In your code:
DateTime enddate = TimeZoneInfo.ConvertTimeToUtc(startdate, TimeZoneDetails.TimeZoneInstance);
Yes, that will correctly convert the DateTime from the time zone given to UTC. Because startdate.Kind == DateTimeKind.Unspecified, the value is treated as belonging to the time zone specified. The resulting value will have enddate.Kind == DateTimeKind.Utc.
You can read more in the documentation, here.
In comments you asked:
which one is default for DateTimeKind?
That depends on which method you call to create the DateTime, and what values you pass in. In your case, because you call DateTime.Parse and pass a string that contains no time zone offset information, the resulting value has .Kind == DateTimeKind.Unspecified. You can read more about the behavior of DateTime.Parse in the remarks section here. Other methods and constructors behave similarly, but you should check the documentation for each, or validate the results yourself. You may find conversion errors if you, for example, think a DateTime has Unspecified kind, but it actually has Local kind due to how you obtain it.

TimeZoneInfo.ConvertTime method not converting the DateTime correctly

I have the following date string: 2015-11-10T23:52:18.5245011Z
And when I parse it using DateTime.Parse method it returns 11/11/2015 10:52:18 AM which is incorrect.
I also tried the follwing conversion:
TimeZoneInfo est = TimeZoneInfo.FindSystemTimeZoneById("AUS Eastern Standard Time");
DateTime targetTimeUtcconverted = TimeZoneInfo.ConvertTime(UtcDate, est);
and it still gives out: 11/11/2015 10:52:18 AM
Can't figure out what I am missing here.
Use:
DateTime.Parse(s, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind)
Or:
DateTime.Parse(s, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal)
Or (best option):
DateTimeOffset.Parse(s)
By default, DateTime.Parse will adjust to local time if there is any offset information present in the string. Since Z is the same as +00:00, it assumes the input is +00:00, then adjusts from UTC to the local time zone.
If there is no offset information present, it returns a DateTime with Unspecified kind.
Passing DateTimeStyles.RoundtripKind tells it to treat any value with an offset as local time (as before), but any value containing Z, UTC, GMT, etc. to have DateTimeKind.Utc.
Passing DateTimeStyles.AdjustToUniversal tells it that the output should always have DateTimeKind.Utc, and the value should be adjusted if necessary.
Parsing using DateTimeOffset.Parse bypasses all of that convoluted behavior and just returns a value with an offset matching what was provided. This is the best approach when an offset (or Z) is present in the input string. If you need a DateTime, you can use the UtcDateTime, LocalDateTime, or DateTime properties from the resulting DateTimeOffset.
The time zone conversion code you gave is correct, as long as the Kind is UTC. It would be more explicit to use ConvertTimeFromUtc, but that wouldn't really matter in this case. The best approach is to use the overload of ConvertTime that works with DateTimeOffset values. The resulting value will be a DateTimeOffset whose DateTime property matches the time in that time zone, and whose Offset property is the correct offset for that time in that time zone.

DateTimeOffset parse and custom time zone

We are parsing XML DateTime values into a DateTimeOffset value. According to the W3C XSD documentation for DateTime, the type may have a timezone info or not.
Our requirment says:
If time zone info is provided in XML, use this time zone
If no time zone info is provided, assume it's a local time in a predefined, configurable time zone (not the one from Server).
The Problem is that when a XML DateTime without a time zone is parsed into a DateTimeOffset, it uses the local (System) timezone by default. It seems not possible to override the default timezone and also not possible to identify wheter the timezone was parsed or added internally.
Is there any way I can specify the default timezone used by the DateTimeOffset parsing?
If not, how can one identify if the time zone was parsed or added automatically during parsing for DateTimeOffset?
It seems strange to me that there is no support to set the time zone for a .NET application the same way as one can set the current culture.
Therefore the only approach to this problem seems to first parse the value into DateTime and check the Kind property. If Kind is not Unspecified, parse the value again into a DateTimeOffset:
/*
sample values:
- 2015-06-03T10:47:01
- 2015-06-03T07:47:01Z
- 2015-06-03T10:47:01+03:00
*/
DateTimeOffset dto;
var timeZone = TimeZoneInfo.FindSystemTimeZoneById(ConfigurationManager.AppSettings["DefaultTimeZone"]);
var dt = DateTime.Parse(value);
if (dt.Kind == DateTimeKind.Unspecified)
{
dto = new DateTimeOffset(dt, timeZone.GetUtcOffset(dt));
}
else
{
dto = DateTimeOffset.Parse(value);
}
The simplest way would be to test the string ahead of time to see if it contains an offset. Regular expressions work well for this.
Here is a function that should work well for the case you described:
static DateTimeOffset ParseAsDateTimeOffset(string s, TimeSpan defaultOffset)
{
if (Regex.IsMatch(s, #"(Z|[+-]\d{2}:\d{2})$"))
return DateTimeOffset.Parse(s, CultureInfo.InvariantCulture);
var dt = DateTime.Parse(s, CultureInfo.InvariantCulture);
return new DateTimeOffset(dt, defaultOffset);
}
You might also consider a slight variation of that, which is to provide a default time zone, rather than a default offset. This is an important distinction, since the offset of a time zone can change depending on whether the specific date is in a daylight saving time period or not. See also "Time Zone != Offset" in the timezone tag wiki.
static DateTimeOffset ParseAsDateTimeOffset(string s, TimeZoneInfo defaultTimeZone)
{
if (Regex.IsMatch(s, #"(Z|[+-]\d{2}:\d{2})$"))
return DateTimeOffset.Parse(s, CultureInfo.InvariantCulture);
var dt = DateTime.Parse(s, CultureInfo.InvariantCulture);
return new DateTimeOffset(dt, defaultTimeZone.GetUtcOffset(dt));
}

Is there a way to instantiate a datetime object in a timezone other than local?

I've been racking my brain all afternoon trying to figure this one out. Essentially, the problem itself seems simple. I'm given a date/time that is representative of a date and time in another time zone (not local). I want to convert this value to a UTC value to store in the database. However, all of the methods I find online seem to point to you either starting with UTC or starting with a local time zone. You can convert TO other time zones from these, but you can't start with anything other than those. As a result, it appears that I'll have to do some kind of convoluted offset math to do what I want. Here is an example of the problem:
var dateString = "8/20/2014 6:00:00 AM";
DateTime date1 = DateTime.Parse(dateString,
System.Globalization.CultureInfo.InvariantCulture);
var currentTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
// Now the server is set to Central Standard Time, so any automated offset calculation that it runs will come from that point of view:
var utcDate = date1.ToUniversalTime; // This is wrong
// Similarly, if I try to reverse-calculate it, it doesn't work either
var convertedDate = TimeZoneInfo.ConvertTime(date1, currentTimeZone);
utcDate = convertedDate.ToUniversalTime; // This is also wrong
In essence, I want to somehow tell the system that the datetime object I'm currently working with is from that time zone other than local, so that I know the conversion will be correct. I know that I'll eventually need to figure Daylight Savings Time in there, but that is a problem for another day.
Would this method be of any use to you ?
The TimeZoneInfo.ConvertTime method converts a time from one time zone
to another.
Alternatively, you could use the ConvertTimeToUtc method to simply convert any date (specifying the source time zone) to UTC.
var dateString = "8/20/2014 6:00:00 AM";
DateTime date1 = DateTime.Parse(dateString,
System.Globalization.CultureInfo.InvariantCulture);
var currentTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
var utcDate = TimeZoneInfo.ConvertTimeToUtc(date1, currentTimeZone);
The System.DateTime struct only has two bits for storing the "kind" information. That is why you can only have "local" or "universal" or "unknown" (or "magicl local").
Take a look at the System.DateTimeOffset struct. It is like a DateTime, but it also keeps the time zone (offset from (plus or minus) UTC).

How to handle conversion of a DateTime independently of the timezone of the hosting server?

I have an application which potentially rans in different timezones in the world, to name a few it runs in Germany & UK.
Now I have a requirement wherein I have to interpret datetime objects as they are GMT dates, and then get the equivalent UTC datetime out of it. This should happen irrespective of timezones, for example if the application is running in Germany as well the DateTime should be interpreted as GMT and converted to UTC before saving on the server.I do deal will DST shifts as well.
For ex:
If I have a datetime object like this:
var date = new Datetime(2011,03,28,01,00,00), this should be converted to it's equivalent UTC.In this case it should be 28/03/2011 01:00:00 +01:00:00, however while my server reads the saved datetime it finds it as a 28/03/2011 01:00:00 +02:00:00. My UI was running in Germany at the moment and I suspect the dates were interpreted as local dates(CET).
Can you please advise me how to perform the accurate conversion?
It's usually considered a best practice to
Store datetimes as UTC
Render this in timezone-aware user friendly format as late as possible
Thus, I would suggest you to not rely on DateTime.Now, but instead consider using DateTime.UtcNow.
Provided you allow each user to determine (through a Preferences/Options panel) to select its own timezone, then you could render an UTC date in the appropriate user-friendly format using:
string timeZoneInfoId = "Romance Standard Time"; // Or any valid Windows timezone id ;-)
var tzi = TimeZoneInfo.FindSystemTimeZoneById(timeZoneInfoId);
//Build a DateTimeOffset which holds the correct offset considering the user's timezone
var dto = new DateTimeOffset(TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, timeZoneInfo), timeZoneInfo.GetUtcOffset(utcDateTime));
var formated = string.Format("{0} {1} ({2})", dto.ToString("d"), dto.ToString("T"), dto.ToString("zzz")); //Or whatever format that fits you
Note: You can find the list of all valid Windows timeZoneId here.
Provided you're willing to add a selecting list for the user to choose its rendering timezone, you could use TimeZoneInfo.GetSystemTimeZones() to retrieve a list of TimeZoneInfo, then use the Id property of each TimeZoneInfo as the option's value and call the ToString() method of each TimeZoneInfo to render the option's content.
Your selecting list would render in a similar way than native Windows one:
For the first part of your query , you can get the UTC time from the DateTime object.
DateTime dt = DateTime.Now;
dt.ToUniversalTime().ToString() will give you UTC time.
Now incase you want to represent the same as local time, you will need to get the offset from the client end via javascript. Something like
var now = new Date();
var offset = now.getTimezoneOffset();
Now you may use this offset to display the Time for the client by adding or subtracting the minutes you get from this method.
Hope this helps.
Take a look at the TimeZoneInfo class: http://msdn.microsoft.com/en-us/library/system.timezoneinfo.aspx
date += TimeZone.CurrentTimeZone.GetUtcOffset(date);

Categories