Parse a UTC date string to date in C# - c#

Simple question, I have this string:
string dateString = "7/12/2014 4:42:00 PM";
This is a date string and it's in the UTC timezone.
I need to convert it to a date, so I'm doing the following:
DateTimeOffset dateOffset;
DateTimeOffset.TryParse(dateString, out dateOffset);
DateTime date = dateOffset.UtcDateTime;
The problem:
When I'm parsing the string to date, the code is considering that the dateString is in the Local Timezone of the PC (+3 GMT), and not in the UTC timezone.
So I am getting the following the dateOffset = {7/12/2014 4:42:00 PM +03:00} and thus date = {7/12/2014 1:42:00 PM}
how can I tell him that the date string provided is in the UTC format and not in the local timezone format?
Thanks

how can I tell him that the date string provided is in the UTC format and not in the local timezone format?
Specify a DateTimeStyles value of AssumeUniversal in the call. That tells the parsing code what to do. For example:
// null here means the thread's current culture - adjust it accordingly.
if (DateTimeOffset.TryParse(dateString, null, DateTimeStyles.AssumeUniversal,
out dateOffset))
{
// Valid
}
You should always use the result of TryParse to tell whether or not it's successfully parsed.
If you know the format and the specific culture, I'd personally use DateTimeOffset.TryParseExact. (Well, to be honest I'd use my Noda Time project to start with, but that's a different matter.)

There is another overload of DateTimeOffset.TryParse
DateTimeOffset.TryParse Method (String, IFormatProvider, DateTimeStyles, DateTimeOffset)
which allows you specify DateTimeStyles. One of the DateTimeStyles is AssumeUniversal, which is what you're looking for:
If no time zone is specified in the parsed string, the string is
assumed to denote a UTC. This value cannot be used with AssumeLocal or
RoundtripKind.

Don't know how .Net API provides, but I guess you could probably use ISO8601 format to indicate a UTC timezone before parsing, i.e, first translate 7/12/2014 4:42:00 PM into something 2014-07-02T16:42:00Z, then use try parse using DateTimeOffset

Related

DateTime.ParseExact Failing to convert to correct date

I am using FullCalendar. Now there is a code where I get a Date/Time from FullCalendar API. This is called startDate and has a below format:
String. An ISO8601 string representation of the start date. It will
have a timezone offset similar to the calendar’s timeZone e.g.
2018-09-01T12:30:00-05:00. If selecting all-day cells, it won’t have a
time nor timezone part e.g. 2018-09-01.
Let us for this question, assume that startStr is 2020-11-15T23:00:00-08:00
I have an ASP.NET MVC backend, where I send this string using Javascript.
The server receives the correct string as above i.e. 2020-11-15T23:00:00-08:00
Now, there is a code where I parse this date to the DateTime object
DateTime sdt = DateTime.ParseExact(sstartStr, "yyyy'-'MM'-'dd'T'HH':'mm':'sszzz", CultureInfo.InvariantCulture)
But here, this date/time is parsed as 11/16/2020 12:30:00 PM.
(You can try parsing the said date using the above code, the output will be wrong as above.)
Am I missing something ?

Format date using DateTime.ToString() based on TimeZone

I read the following question Creating a DateTime in a specific Time Zone in c# and was able to create a DateTime with TimeZone information. But I need to convert the DateTime to string value based on TimeZone.
E.g. I've set the TimeZone as India Standard Time and created a DateTime, when I tried to convert to string using ToString() instead of 13/12/2019 4:00:00 PM, I am getting 12/13/2019 4:00:00 PM. Since I've set the TimeZone as India Standard Time, I would like to display the date in India Format (dd/mm/yyyy) rather than mm/dd/yyyy.
So, how do I format the date based on TimeZone in C#?
Edit: I completely understand that Format and Timezone are different things. But I need to format the DateTime to match user's geography which I can identify using his timezone provided as input.
If you only want a string representation of the DateTime that matches a specific culture you can use the DateTime.ToString(IFormatProvider) overload to specify the target culture you want to use. The date will be formatted accordingly. If you want to format your date and time you want to do this based on the culture of the user and not based on the timezone. People in Kongo and Germany share the same timezone but are formatting their date and time differently.
var myDate = DateTime.Now();
var myDateString = myDate.ToString(new CultureInfo("fr-FR"));
would print the date and time in a french format for example.
You can also format your DateTime with a custom format:
var myDate = DateTime.Now;
var myDateString = myDate.ToString("dd/MM/yyyy hh:mm");
References:
- DateTime.ToString(IFormatProvider)
- DateTime.ToString(string)
- CultureInfo
- Date and time formatting

DateTime ParseExact not working when changing time

I'm having trouble figuring out why my date is parsed correctly until I change the time of the date passed into the parse method.
var parsedDate = DateTime.ParseExact("2016-02-05T07:00:00+00:00", "yyyy-MM-ddThh:mm:ss+00:00", CultureInfo.InvariantCulture);
dateValueToTryParse = parsedDate.ToString("dd/MM/yyyy");
The required result is outputted and I do get 05/02/2016. However, if I change the string passed in to:
2016-02-19T23:59:00+00:00
The output of dateValueToTryParse remains the same and it is not parsed correctly. Am I doing anything particularly wrong with my parsing? I'm confused as the format seems to be exactly the same?
You need to change your incoming format to yyyy-MM-ddTHH:mm:ss+00:00.
The difference is HH. Capital H means 24 hour clock or "military time".
Otherwise, it is trying to parse hour 23 which doesn't exist.
See here for more detailed information on other formats: https://msdn.microsoft.com/en-us/library/8kb3ddd4(v=vs.110).aspx
Changing hh to HH specifier can solve your problem but since your string has an UTC offset value, I would prefer to parse it to DateTimeOffset instead of DateTime for consistency.
var dto = DateTimeOffset.ParseExact("2016-02-05T23:00:00+00:00",
"yyyy-MM-ddTHH:mm:sszzz",
CultureInfo.InvariantCulture);
Now, you have a DateTimeOffset as {05.02.2016 23:00:00 +00:00} and you can use it's .DateTime property to get the DateTime value represented by it.
var dateValueToTryParse = dto.DateTime.ToString("dd/MM/yyyy", CultureInfo.InvariantCulture);
This will generate 05/02/2016 as a result.

Parse date time c# with correct timezone and kind

I have a datetime in database which I read using SqlDataReader and then cast it to (DateTime). After the cast its Kind property is DateTimeKind.Unspecified.
Then I have another string which I read from some other source. Its format is like this 2016-01-20T22:20:29.055Z. I do DateTime.Parse("2016-01-20T22:20:29.055Z") and its Kind property is DateTimeKind.Local.
How do I properly parse the both date times for comparison? Do I need to use DateTimeOffsets? How should I parse them?
Thanks
Because SQLReader cannot reasonably infer a DateTimeKind, it leaves it as unspecified. You'll want to use DateTime.SpecifyKind to change the DateTimeKind on your output from the SQLReader to the appropriate value. This works ok if you are only dealing with UTC and one consistent local time zone; otherwise, you really should be using DateTimeOffset in both your code and the SQL Database.
The string "2016-01-20T22:20:29.055Z" is ISO 8601 compliant and is a UTC date; however, DateTime.Parse with only 1 argument can end up performing a conversion to local time. Per the documentation:
Generally, the Parse method returns a DateTime object whose Kind
property is DateTimeKind.Unspecified. However, the Parse method may
also perform time zone conversion and set the value of the Kind
property differently, depending on the values of the s and styles
parameters:
If s contains time zone information, the date and time is converted
to the time in the local time zone and the Kind is DateTimeKind.Local.
If s contains time zone information, and styles includes the
AdjustToUniversalflag, the date and time is converted to Coordinated
Universal Time (UTC) and the Kind is DateTimeKind.Utc.
If s contains the Z or GMT time zone designator, and styles includes
the RoundtripKind flag, the date and time are interpreted as UTC and
the Kind is DateTimeKind.Utc.
Also see UTC gotchas in .NET and SQL Server in Derek Fowler's blog for additional coverage on the topic.
In your second example, 2016-01-20T22:20:29.055Z has timezone information provided with it; the 'Z' at the end indicates that the timestamp is intended for Coordinated Universal Time (UTC). However, DateTime.Parse() will default its conversion using DateTimeKind.Local unless a specific timezone is specified. You can use DateTime.ParseExact to be more specific.
As to why the datetime values in your database are coming out as Unspecified, that's likely because they contain no timezone indication at all. Check to see if your database values specify timezone information, either by using 'Z' at the end or specifying an exact timezone, such as 2016-01-20T22:20:29.055-07:00 (UTC-7).
You can use something like this:
string format = "ddd dd MMM h:mm tt yyyy";
DateTime dateTime = DateTime.ParseExact(dateString, format,
CultureInfo.InvariantCulture);
In format variable, you can put the format you want, and pass it to ParseExact function.
Hope it helps.
You are missing the datetime context (offset) in your database. You should persist it either in a datetimeoffset column or in a datetime column but persisting utc datetimes.
And always better compare two utc datetimes.
I coded a quick C# console app that I pasted in below. This converts a UTC date and time to a string (format similar to the ISO 8601 format described in another post with some extra digits of precision), writes it to a file, reads it from the file (as a string) and then converts it back to a UTC date and time.
It then compares the two UTC Date Time objects, which are both of UTC kind, and they match.
class Program
{
// "2016-01-20T22:20:29.055Z" is ISO 8601 compliant and is a UTC date
const string dtf = "yyyy-MM-ddTHH:mm:ss.fffffffZ";
static void Main(string[] args)
{
string file = #"c:\temp\file.txt";
DateTime dt = DateTime.UtcNow;
using (var sw = new System.IO.StreamWriter(file))
{
sw.WriteLine(dt.ToString(dtf, System.Globalization.CultureInfo.InvariantCulture));
}
DateTime dtin;
using (var sr = new System.IO.StreamReader(file))
{
dtin = DateTime.ParseExact(sr.ReadLine(), dtf, System.Globalization.CultureInfo.InvariantCulture);
}
Console.WriteLine(dt.ToString(dtf) + "\r\n" + dtin.ToString(dtf) + "\r\nEquality:" + (dt == dtin));
Console.ReadLine();
}
}

getting hour part and time-zone part from datetime

I had a string in config file, defining date time with time zone.
I am not able to get this value, while reading values from config file.
In config file:
Setting name="abcdefgh" value="2012-08-10T22:00:00-08:00"
In C#, I am reading this as follows:
DateTime StartDate;
StartDate = DateTime.ParseExact(RoleEnvironment.GetConfigurationSettingValue("abcdefgh"), "yyyy-MM-dd HH:mm:ss", null);
Configuration.Instance.abcdefgh= StartDate;
In start date, i am getting 11 Aug, 2012 11:30:00, with no time zone.
I want to read it as it is. also tell, if my format of writing datetime in config file is correct
MSDN link to DateTimeOffset.
Use DateTimeOffset whenever you are referring to an exact point in
time. For example, use it to calculate "now", transaction times, file
change times, logging event times, etc. If the time zone is not
known, use it with UTC. These uses are much more common than the
scenarios where DateTime is preferred, so this should be considered
the default.
var date = DateTimeOffset.Parse("2012-08-10T22:00:00-08:00");
date.Offset // -08:00:00, offset from Coordinated Universal Time (UTC)
date.DateTime // 10/08/2012 22:00:00,
DateTime doesn't keep information about timezone. To parse the string and keep information about timezone - you should use DateTimeOffset structure.
Use the DateTimeOffset structure (and DateTimeOffset.ParseExact) if you want to store timezone information.
Your ParseExact format also doesn't quite match the setting value: it should have a zz at the end for the timezone information. You can also use DateTimeOffset.Parse since your setting string is in a standard format.
It's a standard format, so the ParseExact isn't needed, try:
StartDate = DateTime.Parse(RoleEnvironment.GetConfigurationSettingValue("abcdefgh"));
I substituted the hard-coded value you provided and got the correct result for my timezone (GMT-4) as
8/11/2012 2:00 AM
Note: as others mentioned, the timezone is not retained, so you will get the correct localized time corresponding to whatever timezone information was in the string, but you won't be able to find out what timezone that was. The DateTime.Kind property will reflect that it's a local time.

Categories

Resources