Parsing Twitter Created At Date as UTC - c#

I realize there are many threads about parsing twitter dates, but I am having a peculiar issue, and haven't been able to find any threads specific to this.
I am retrieving this post: https://twitter.com/bodegamcallen/status/1033757489567805440
which has a created date of 8/26/2018 at 9:46 AM Central Time.
The created date in the api is this: "Sun Aug 26 16:46:06 +0000 2018"
Which makes sense as 16:46pm (2:46pm) UTC is 9:46 AM Central (-500).
However, I'm parsing this using this code:
statusModel.DatePosted = DateTime.ParseExact(
this.created_at, "ddd MMM dd HH:mm:ss zzzz yyyy",
CultureInfo.InvariantCulture.DateTimeFormat, DateTimeStyles.AssumeUniversal);
and instead of getting the desired UTC time shown above, I'm getting this: 8/26/2018 4:46:06 PM
If I change the DateTimeStyle to None or AssumeLocal, I get this: 8/26/2018 11:46:06 AM
Neither of which is correct!
I've tried different formats from other threads like:
"ddd MMM dd HH:mm:ss K yyyy"
"ddd MMM dd HH:mm:ss Z yyyy"
"ddd MMM dd HH:mm:ss zzz yyyy"
"ddd MMM dd HH:mm:ss +ffff yyyy"
I also tried using DateTimeOffset.Parse and changing the culture to mine (en-us)
they all give me the same results.
What am I doing wrong? How do I get the datetime to be the same UTC time as the date value I'm getting from the API?

Aha! It turns out that my twitter account settings were configured to be in Pacific Time, rather than Central Time, and that would account for the two hour difference.
I changed my time zone settings for my account as described here: https://help.twitter.com/en/managing-your-account/how-to-change-time-zone-settings
And after changing to Central Time, the API data is coming in correct!
hope this helps someone else. Time zones, amirite?

A few things:
zzzz is not a valid specifier. Always check these docs if you're uncertain.
K is the only time zone specifier that is appropriate for DateTime parsing. The others (z, zz, and zzz) are for DateTimeOffset parsing.
When there is any offset or time zone information in the input string (even if it's +0000 or Z), DateTime.Parse and DateTime.ParseExact will assume by default that you want the output kind to be DateTimeKind.Local and that you want the value adjusted to local whatever it is in the input string. Examine the output .Kind if you're not certain if it's working correctly. If you want UTC instead, you should pass DateTimeStyles.AdjustToUniversal.
You don't need to pass DateTimeStyles.AssumeUniversal, because there is time zone information present in the input string.
It's not invalid, but you don't need to pass CultureInfo.InvariantCulture.DateTimeFormat. It's sufficient, and more common, to pass CultureInfo.InvariantCulture.
Putting this all together, your code should be:
statusModel.DatePosted = DateTime.ParseExact(
this.created_at, "ddd MMM dd HH:mm:ss K yyyy",
CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);
And of course, you'd save some hassle and confusion if you changed your DatePosted to be a DateTimeOffset type instead. It's superior for this sort of scenario, and then you don't have to worry about DateTimeKind or DateTimeStyles.

Related

C# DateTime.Parse efficiently time with hour/min/sec/milis/micro/nano seconds

From third party I'm getting this string that I'd like to convert to DateTime:
"13 NOV 2018 16:08:52:000:000:000"
I've tried those options but FormatException thrown:
System.DateTime.ParseExact("12 NOV 2018 16:08:52:000:000:000",
"dd MMM yyyy HH:mm:ss:fff:ffffff:fffffffff",
CultureInfo.InvariantCulture)
And the same exception when I've used this:
System.DateTime.ParseExact("12 NOV 2018 16:08:52:000:000:000",
"dd MMM yyyy HH:mm:ss:fff", CultureInfo.InvariantCulture)
Is there a clean way to parse it as is or, I need to use a dirty way such string.Split(new []{':'})?
Note:
For my business needs, I don't need the part of micro/nano seconds.
since this parsing operation occurs many times in a second, the efficiency is a key factor.
Update
I chose the #Tim's suggestion to do string manipulation:
string date = "12 NOV 2018 16:08:52:000:000:000";
date = date.Remove(date.Remove(date.LastIndexOf(':')).LastIndexOf(':'));
DateTime result = System.DateTime.ParseExact(date, "dd MMM yyyy HH:mm:ss:fff", System.Globalization.CultureInfo.InvariantCulture);
The reasons:
I can't promise the structure of the date string, since it comes from third party. So it will be very dangerous to use the format pattern dd MMM yyyy HH:mm:ss:fff:fff:fff
As #Jeroen Mostert wrote the usage of string splitting is not a key factor when you use DateTime.ParseExact()
Also, if you really think efficiency is so important, don't assume any single call to DateTime.ParseExact will be "fast", or that any string splitting you do will be a bottleneck.
Well, isn't it simply this?
System.DateTime.ParseExact("12 NOV 2018 16:08:52:000:000:000",
"dd MMM yyyy HH:mm:ss:fff:fff:fff",
System.Globalization.CultureInfo.InvariantCulture)
This works if all groups of f have the same values, so for example all 0 or 123.
Tbh, i don't understand why you think that fff:ffffff:fffffffff matches 000:000:000
For my business needs, I don't need the part of micro/nano seconds.
You could make your second format working by cutting off the micro/nano part:
string date = "12 NOV 2018 16:08:52:000:000:000";
date = date.Remove(date.Remove(date.LastIndexOf(':')).LastIndexOf(':'));
DateTime result = System.DateTime.ParseExact(date, "dd MMM yyyy HH:mm:ss:fff", System.Globalization.CultureInfo.InvariantCulture);
Of course this assumes that there are always at least two colons. It's obvious that you need a try-catch to log invalid values and to continue with the next one.
Not an exact answer
System.DateTime.ParseExact("25 NOV 2018 16:08:52:000:000:000",
"dd MMM yyyy HH:mm:ss:fff:fff:fff", CultureInfo.InvariantCulture);
Things to consider: count of input string (000) should match with format(fff),
000 = fff good
00 = fff not good
000 = ff not good
You may need to manipulate input date string before trying to parse.
See this for more information regarding use of format specifier (fff)
https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings
.NET Fiddle:
https://dotnetfiddle.net/5UxCkd
I think that having same format for :fff is a key factor here
System.DateTime.ParseExact("12 NOV 2018 16:08:52:000:000:000","dd MMM yyyy H:mm:ss:fff:fff:fff", CultureInfo.InvariantCulture) seems to work
https://dotnetfiddle.net/ZAtchu example code

convert datetime string to Utc

how to convert datetime string to utc time format in GMT.
var x = "02/01/2017 10:00";
var z = DateTime.ParseExact(x, "ddd, dd MMM yyyy HH:mm:ss 'GMT'", CultureInfo.InvariantCulture);
Actually the thing you have tried is wrong, what you can do is, get the DateTime value equivalent to the given date and then convert them to the UTC time, try something like the following:
string inputDateStr = "02/01/2017 10:00";
DateTime inputDate;
if (DateTime.TryParseExact(inputDateStr, "MM/dd/yyyy HH:mm", CultureInfo.InvariantCulture, DateTimeStyles.None, out inputDate))
{
Console.WriteLine("Date time Now : {0} ", inputDate);
Console.WriteLine("Date time UTC : {0} ", inputDate.ToUniversalTime().ToString("ddd, dd MMM yyyy HH:mm:ss 'GMT'"));
}
Working Example
I am not sure what you wanted to do. But, Universal Time, Zulu time, and UTC are effectively modern names for Greenwich Mean Time (GMT). So both the times will be same. You can use the DateTime.ToUniversalTime() or DateTime.UtcNow method to get the UTC time.
It's not completely clear what you are asking... UTC isn't a format, it's a timezone, equivalent to GMT (well, actually that isn't strictly true, but for the purposes of this question it should be ok.
What point in time is your string representing? Is it UTC? Or is it the local time in Moscow? You need to have the answer to that, because they are completely different times.
If the string represents a UTC time, then you can do something like this:
// first parse it to a DateTime object. Notice that the format string corresponds with the string you have - in your code, they were completely different.
var dateTimeWithUnspecifiedKind = DateTime.ParseExact(x, "dd/MM/yyyy HH:mm", CultureInfo.InvariantCulture);
So how you have a datetime object. It has a "Kind" property of Unspecified. So it isn't storing any information to specify that it's supposed to be UTC, rather than Moscow or New York time.
// so we do this...
var dateTimeAsUtc = DateTime.SpecifyKind(dateTimeWithUnspecifiedKind, DateTimeKind.Utc);
That means, "keep the numbers the same, but make a note that the datetime is to be interpreted as a UTC datetime".
Then, if you want to convert it back into a string, you can do something like:
var s = dateTimeAsUtc.ToString("O");
Which will give you a nice representation:
2017-01-02T10:00:00.0000000Z
You are lucky you are interested in UTC. The datetime class can only do UTC, "local" (whatever that is), or "Unspecified". It's not super useful for this sort of thing. DateTimeOffset is a bit better - it's basically a DateTime but it also stores the difference between UTC and the offset that's in force at the time.
That may be all you need. If you ever need real clarity around this stuff though, take a look at Noda time - an alternative set of date and time classes for .NET.

How to parse default git date format in C#

How do you parse the default git format to a DateTime in C#?
As per What is the format for --date parameter of git commit
The default date format from git looks like Mon Jul 3 17:18:43 2006 +0200.
Right now I don't have control over the output, this strings comes from another tool that printed the date and I need to parse it.
I wouldn't parse this to DateTime, I would parse it to DateTimeOffset since it has a UTC offset value inside of it.
Why? Because if you parse it to DateTime, you will get a DateTime as Local and it might generate different results for different machines since they can have timezone offsets of that time.
For example, I'm in Istanbul and we use Eastern European Time which use UTC+02:00. If I run the example of your code with ParseExact method, I will get the 07/03/2006 18:18:43 as a Local time.
Why? Because in 3 July 2006, my timezone was in a daylight saving time which is UTC+03:00. That's why it generates 1 hour forwarded result. That's the part makes it ambiguous when you parse it to DateTime.
string s = "Mon Jul 3 17:18:43 2006 +0200";
DateTimeOffset dto;
if (DateTimeOffset.TryParseExact(s, "ddd MMM d HH:mm:ss yyyy K",
CultureInfo.InvariantCulture,
DateTimeStyles.None, out dto))
{
Console.WriteLine(dto);
}
Now, you have a DateTimeOffset as 07/03/2006 17:18:43 +02:00. You can still get the DateTime part with it's .DateTime property but it's Kind will be Unspecified in that case.
But of course, I suggest to use Noda Time instead which can solve most of the DateTime weirdness.
So far the best format string I found is ddd MMM d HH:mm:ss yyyy K.
DateTime date;
DateTime.TryParseExact(
gitDateString,
"ddd MMM d HH:mm:ss yyyy K",
System.Globalization.CultureInfo.InvariantCulture,
System.Globalization.DateTimeStyles.None,
out date
);

How can I format a date in RFC format?

I need to format a date in RFC format for an RSS feed. I have tried taking my date and adding the following:
.ToString("ddd, dd mm yyyy HH:mm:ss zzz")
However it seems this is not valid. Any help would be great! The end result I need is, for example, Mon, 01 Jan 2013 GMT
Your question is a bit confusing because your example lacks any time (but has a time-zone).
Nevertheless, try using MMM for month:
.ToString("ddd, dd MMM yyyy HH:mm:ss zzz")
If you don't want time, simply omit that section from the string:
.ToString("ddd, dd MMM yyyy")
But since you mentioned you're generating a string for an RSS feed, you could just use the "R" format specifier to generate a RFC1123-format date / time string:
.ToString("R")

Twitter time to local time c#

How do i convert the time of tweets made by the user to localtime? The created_at gives me the time of the tweet created and is based on the user's country, how to i change it to my localtime using c#. The format of the time is "Fri Jul 27 15:14:11 +0000 2012". What do they mean by utc_offset and how can it be used to change the timezone?
I am not really familiar with the timezone stuff, thank you for your help :)
You'll want to use the DateTimeOffset structure. This allows you to capture a date and a time as well as offset from UTC as well.
The format that you want to use for Twitter times is:
string twitterDate = "Fri Jul 27 15:14:11 +0000 2012";
DateTimeOffset dt = DateTimeOffset.ParseExact(twitterDate,
"ddd MMM dd HH:mm:ss zzz yyyy", CultureInfo.InvariantCulture);
Note that while not documented, zzzz does work as a custom date time format and succeeds in parsing the offset correctly. This means you should be careful in relying on it in the future (unless the documentation changes to reflect this functionality).
Once you have the DateTimeOffset, you know the offset from UTC. If you want to get it in your local time, you can call the ToLocalTime method on the DateTimeOffset that was parsed and it will return an instance that has an offset based on your local settings.
This should be it:
DateTime localDateTime = DateTime.ParseExact(dateString, "ddd MMM dd HH:mm:ss zzz yyyy", new CultureInfo("en-US"));
Unless you give a DateTimeKind in the constructor of a DateTime, the DateTime will be in the timezone the administrator of the workstation/server has selected for Windows.

Categories

Resources