TimeZoneInfo.ConvertTime method not converting the DateTime correctly - c#

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.

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.

Unable to convert DateTime string to DateTime in C# using DateTime.ParseExact()

So I want to convert a certain UTC DateTime string that is in the following format 2020-04-18T20:05:00.000-04:00.
I am trying to use the following function :
DateTime.ParseExact(segment.DepartureDate,"yyyy-MM-ddTHH:mm:ss.fffzzz", System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.AdjustToUniversal);
for converting the above Date string that i received from an API, to a C# DateTime type variable.
But the Actual Result is {19-04-2020 00:05:00}. Somehow the date gets rounded up or converted which is not what i am expecting.
Have also tried Date.Parse but that filters out the UTC Offset whose value i really need.
Can anyone suggest a legit way to achieve this conversion accurately.Thanks in Advance.
If you are working with different time zones (where the offset is not equal to your current locale's offset) and the offset is important, it is usually better to use DateTimeOffset instead of DateTime. DateTime only has a property identifying it as UTC or (system-)local, but DateTimeOffset stores the full offset value instead.

Get time zone with UTC conversion

I have the system date in BST . I want to convert it to UTC. So did the below:
string utcDate= TimeZoneInfo.ConvertTimeToUtc(dt).ToString("dd/MM/yyyy HH:mm:ss");
What I want is to get the zone along with the Date in UTC. Pls consider the daylight savings.
Example: 2019-07-08T23:59:00+01:00.
A few things:
The string format you gave the example of, 2019-07-08T23:59:00+01:00 is part of the ISO 8601 specification. To be precise, it is the "complete date and time of day representation" of the "ISO 8601 Extended Format". It also the format defined by RFC 3339.
In this format, the date and time portion represent the local time, as denoted by the time zone offset portion. In other words, the values are not in UTC, but already adjusted. In your example, 2019-07-08T23:59:00 is the local time and UTC+01:00 is in effect at that time. The corresponding UTC time would thus be an hour earlier, 2019-07-08T22:59:00Z.
You seem to be asking for the date in UTC but with an offset that includes daylight saving time. That is impossible, as UTC does not observe daylight saving time. The offset from UTC is always zero. You can read more about UTC here.
The offset of UTC itself is denoted with Z, but can also be represented with +00:00, which can be thought of as "zero offset from UTC". In other words, if you are referring to UTC time use the Z, and if you are referring to a local time that is aligned to UTC (such as GMT in London in the winter, or Iceland, etc.) use +00:00.
In your question, you say you want the system time in UTC with the offset. I will assume by "system time" you mean the current time of the clock on the system. That is provided by DateTime.UtcNow or DateTimeOffset.UtcNow. These return either a DateTime or DateTimeOffset structure - not a string. Since you wanted a string in a specific format, then you should first ask for the current time, and then format it as a string with ToString:
using System.Globalization;
...
string a = DateTime.UtcNow.ToString("yyyy-MM-dd'T'HH:mm:ssK", CultureInfo.InvariantCulture);
// output example: "2019-07-08T22:59:00Z"
string b = DateTimeOffset.UtcNow.ToString("yyyy-MM-dd'T'HH:mm:sszzz", CultureInfo.InvariantCulture);
// output example: "2019-07-08T22:59:00+00:00"
If what you actually wanted was the local time, such that the offset would be +00:00 in the winter and +01:00 in the summer (in the UK), then use Now instead of UtcNow. This gives the local time in the time zone of the computer where the code is running.
string c = DateTime.Now.ToString("yyyy-MM-dd'T'HH:mm:ssK", CultureInfo.InvariantCulture);
// output example: "2019-07-08T23:59:00+01:00"
string d = DateTimeOffset.Now.ToString("yyyy-MM-dd'T'HH:mm:sszzz", CultureInfo.InvariantCulture);
// output example: "2019-07-08T23:59:00+01:00"
If you actually wanted the time in the UK regardless of what the time zone of the local computer was on, then you'd have to first get the UTC time and then convert it to UK time before creating the string.
TimeZoneInfo tzi = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
string e = TimeZoneInfo.ConvertTime(DateTime.UtcNow, tzi).ToString("yyyy-MM-dd'T'HH:mm:ssK", CultureInfo.InvariantCulture);
// output example: "2019-07-08T23:59:00"
string f = TimeZoneInfo.ConvertTime(DateTimeOffset.UtcNow, tzi).ToString("yyyy-MM-dd'T'HH:mm:sszzz", CultureInfo.InvariantCulture);
// output example: "2019-07-08T23:59:00+01:00"
In example e, note that a DateTime can't store an arbitrary offset as the result of time zone conversion, and thus you get DateTimeKind.Unspecified assigned to the Kind property, which results in no offset being in the string representation. Thus most of the time you should use a DateTimeOffset (example f) instead.
Also, note the time zone ID of "GMT Standard Time" is the correct ID to use for the UK on Windows platforms. It correctly switches between GMT and BST when appropriate. If you are running .NET Core on non-Windows platforms (Linux, OSX, etc.), then you should use "Europe/London" instead. Or if you are wanting to write code that is platform-neutral then you can use my TimeZoneConverter library, which allows you to provide either form and run on any platform.
In your code example, you didn't call any of the "now" functions, but gave a dt variable. Assuming this is a DateTime, the result of calling TimeZoneInfo.ConvertTimeToUtc will depend on the Kind property of that variable. If it's DateTimeKind.Utc, then no conversion is performed. If it's DateTimeKind.Local or DateTimeKind.Unspecified, then the value is converted from the computer's local time zone to UTC.
Lastly, keep in mind that when talking to an international audience, time zone abbreviations can be ambiguous. I could deduce by "BST" that you meant British Summer Time, but only because you showed a +01:00 offset in your question. "BST" can also stand for "Bangladesh Standard Time" (+06:00), or "Bougainville Standard Time" (+11:00).
I guess you can do something like this:
var dt = DateTime.Now;
string utcDate = dt.ToUniversalTime().ToString("dd/MM/yyyy HH:mm:ss") +
dt.ToString(" zzz");
Output: (I'm in EET)
14/07/2019 20:02:17 +02:00
But be aware that this could be confusing to people. The standard way is that the timezone follows the local date, not the universal date.

How to Convert Date Time using Offset values

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.

Convert DateTime to Utc only if not already Utc

I'm using the DateTimeWithZone struct that Jon Skeet posted at Creating a DateTime in a specific Time Zone in c# fx 3.5
This didn't work exactly for my situation since it assumes that the DateTime passed in the constructor is the local time, and therefore converts it to Utc using the specified TimeZone.
In my case we will mostly be passing in DateTime objects already in Utc (since this is what we are storing) so we need to only perform the conversion if the source DateTime.Kind is not Utc.
Therefore I changed the constructor to:
public DateTimeWithZone(DateTime dateTime, TimeZoneInfo timeZone, DateTimeKind kind = DateTimeKind.Utc) {
dateTime = DateTime.SpecifyKind(dateTime, kind);
utcDateTime = TimeZoneInfo.ConvertTimeToUtc(dateTime, timeZone);
this.timeZone = timeZone;
}
Here we have an optional Kind parameter that defaults to Utc.
However, running this code and passing a Utc DateTime generates the following exception:
The conversion could not be completed because the supplied DateTime did not have the Kind property set correctly. For example, when the Kind property is DateTimeKind.Local, the source time zone must be TimeZoneInfo.Local.
According to the docs (http://msdn.microsoft.com/en-us/library/bb495915.aspx):
If the Kind property of the dateTime parameter equals DateTimeKind.Utc and the sourceTimeZone parameter equals TimeZoneInfo.Utc, this method returns dateTime without performing any conversion.
Since both the input time and the timezone both have a Kind property of Utc then I would not expect to get this exception.
Have I misunderstood?
Like the MSDN docs say if you pass in a DateTime with the kind set to anything besides DateTimeKind.Utc and specify a TimeZone other than Utc the conversion function will throw an exception. That Must be what is happening here. In your code you should check if the DateTime is already in Utc and skip the conversion if it is.
Also since the dateTime you are passing in will have a DateTime attached to it already you probably don't need to pass in a separate Kind parameter.
from the docs
Converts the time in a specified time
zone to Coordinated Universal Time
(UTC).
meaning that it converts from the time zone supplied to Utc
the function throws an argument exception if:
dateTime .Kind is DateTimeKind.Utc and
sourceTimeZone does not equal
TimeZoneInfo.Utc.
-or-
dateTime .Kind is DateTimeKind.Local
and sourceTimeZone does not equal
TimeZoneInfo.Local.
-or-
sourceTimeZone .IsInvalidDateTime(
dateTime ) returns true.

Categories