Change server time to local time that is sent by Facebook - c#

I am using Facebook C# SDK to get some data from my Facebook page.
When I get objects of data, at that time I get one field:
created_time : 2014-05-23T11:55:00+0000
As it is not same as my current time how do I convert it to my current time or to standard UTC time?

For me the code:
DateTime.Parse("2014-05-23T11:55:00+0000").ToString()
returns
2014-05-23 12:55:00
Because 'DateTime.Parse()` understands the timezone in this string, and by default produces a local time. My timezone being Irish Summer Time, one hour ahead of UTC, that means 2014-05-23T12:55:00 for me, for you it'll be a different time depending on your timezone.
For the converse, to get the time parsed in UTC (more useful for behind-the-scenes web stuff or storage, rather than user interface), use DateTime.Parse("2014-05-23T11:55:00+0000").ToUniversalTime()
If you need to deal with timezones other than local to the machine the code is running on, or UTC, then you will need to use DateTimeOffset, with the exception that DateTimeParse will handle other timezones in the string, but from that point on only has the concepts of "local time", "universal time" and "unknown timezone".

I would use DateTimeOffset.ParseExact, specifying the format string an the invariant culture:
DateTimeOffset value = DateTimeOffset.ParseExact(text, "yyyy-MM-dd'T'HH:mm:ssK",
CultureInfo.InvariantCulture);
I strongly recommend this over using DateTime.Parse for the following reasons:
This always uses the invariant culture. It's explicitly stating that you don't want to use the local culture, which might have a different default calendar system etc
This specifies the format exactly. If the data becomes "10/06/2014 11:55:00" you will get an exception, which is better than silently guessing whether this is dd/MM/yyyy or MM/dd/yyyy
It accurately represents the data in the string: a date/time and an offset. You can then do whatever you want with that data, but separating the two steps is clearer
The first two of these can be fixed by using DateTime.ParseExact and specifying the culture as well, of course.
You can then convert that to your local time zone, or to any other time zone you want, including your system local time zone. For example:
DateTimeOffset localTime = value.ToLocalTime(); // Applies the local time zone
or if you want a DateTime:
DateTimeOffset localTime = value.ToLocalTime().DateTime;
It's just one extra line of code, but it makes it clearer (IMO) what you're trying to do. It's also easier to compare DateTimeOffset values without worrying about what "kind" they are, etc.
In fact, I wouldn't personally use DateTimeOffset or DateTime - I'd use OffsetDateTime from my Noda Time project, but that's a different matter.

Related

What is the best way to convert this date format "2019-11-07T13:30:00+05:30" to utc date?

I need a way to convert this date:
2019-11-07T13:30:00+05:30
to utc.
While also taking into account that it has +05:30
https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings
string dateEnd = "2019-11-07T13:30:00+05:30";
DateTime converted = Convert.ToDateTime(dateEnd);
It converts it to this date:
29-Aug-19 9:00:00 AM
dateEnd="2019-11-07T13:30:00+05:30";
matchObject.DateEnd = Convert.ToDateTime(dateEnd).ToUniversalTime();
Okay, as a warning ahead: Dealing with timezones can be madening. I try to avoid it whever I can. Luckily in .NET, we can for most cases.
Internally DateTime stores the amount of Ticks since the start of the Unix Epoch (1/1/1970). Any string and any other property you see? Those are just a interpretation of that one value.
The ToString() and Parse() functions are really good at their job. If not given another culture, they will retreive the current Culture set for windows (or their Thread). For DateTimes it will also get your local timezones to factor into the display (as nessesary).
Now the debugger is just a programm too. And it will of course display the average DateTime it is viewd from your Windows current Timezone. Or rather the timezones used by the user this programm runs in - wich can be a temporary/compilation only user with all kinds of oddities.
With the Input string the timezone of Origin is clearly noted. I can not remember having seen that Syntax, but it is propably like providing a specific port for a WebRequest. No guessing or implying of values involved. And it is accepted by Parse, so whatever :)
If you get a DateFrom a UTC related function, it will set the Kind property to UTC. Wich should fix the whole "Display in Local Timezone" thing.

C# Parse String into DateTime with Specific TimeZone

I've been struggling with this for a bit so I'll punt to SO.
I have an app where I need to parse strings into datetimes. The strings look like this:
"201503131557"
(they will always be this format "yyyyMMddHHmm") and always be in Central Standard Time (or Central Daylight Time depending on the date)even though they don't specify it.
When I parse them I understand that it parses them into local time. I'm running on Azure PaaS and don't want to change it to run in CST just to support this operation.
How do i write code that works both locally and in Azure PaaS that will correctly parse these dates into DateTimes setting their timezone to CST?
Here is a quick unit test I wrote to prove Matt Johnson's answer.
[TestMethod]
public void DateTests()
{
var unSpecDt = DateTime.ParseExact("201503131557", "yyyyMMddHHmm", CultureInfo.InvariantCulture);
var tz = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
var utcDt = TimeZoneInfo.ConvertTimeToUtc(unSpecDt, tz);
var offset = tz.GetUtcOffset(unSpecDt);
var dto =new DateTimeOffset(unSpecDt, offset);
var cstDt = dto.DateTime;
Assert.IsTrue(cstDt.Hour - utcDt.Hour == offset.Hours);
}
To parse the string, since you have only the date and time, and you know the specific format the strings will be in, do this:
DateTime dt = DateTime.ParseExact("201503131557", "yyyyMMddHHmm", CultureInfo.InvariantCulture);
The resulting value will have its Kind property set to DateTimeKind.Unspecified (not local time, as you thought). That is to be expected, as you provided no information regarding how this timestamp is related to UTC or local time.
You said the value represents time in Central Standard Time. You'll need a TimeZoneInfo object that understands that time zone.
TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
Note that this identifier represents the Central Time observed in the USA, including both CST or CDT depending on which is in effect for the given value (despite the word "Standard" in its name). Also note that it valid on Windows operating systems only. If you wanted to use .NET Core on some other OS, then you'd need to pass the IANA identifier "America/Chicago" instead (or use my TimeZoneConverter library to use either identifier on any platform).
The next step is to figure out what you want to do with this value. You might do a few different things with it:
If you want to convert it to the equivalent UTC value, represented as a DateTime, then you can do this:
DateTime utc = TimeZoneInfo.ConvertTimeToUtc(dt, tz);
If you want a DateTimeOffset representation which holds the input you gave and the offset from UTC as it related to US Central Time, then you can do this:
TimeSpan offset = tz.GetUtcOffset(dt);
DateTimeOffset dto = new DateTimeOffset(dt, offset);
Keep in mind that it's possible for the input time is invalid or ambiguous if it falls near a DST transition. The GetUtcOffset method will return the standard offset in such cases. If you want different behavior, you have more code to write (out of scope for this post).
There are other things you might do, all of which are provided by the TimeZoneInfo class.
Note that "Azure PaaS" might refer to a few different things, and while there is a setting called WEBSITE_TIME_ZONE in Azure App Service - I don't recommend you lean on it. Consider it a last resort to be used only when you can't control the code. In most cases, it is better off writing your code to never depend on the time zone setting of the system it runs on. That means never calling DateTime.Now, or TimeZoneInfo.Local, DateTime.ToLocalTime, or even DateTime.ToUniversalTime (since it converts from the local time zone), etc. Instead, rely upon methods that work explicitly with either UTC or a specific time zone or offset. Then you will never need to care about where your app is hosted.
Lastly, understand that neither the DateTime or DateTimeOffset types have any capability of understanding that a value is tied to a specific time zone. For that, you'd need to either write your own class, or look to the Noda Time library whose ZonedDateTime class provides such functionality.
You can use:
DateTime.ParseExact(...)
public static DateTime ParseExact (string s, string format, IFormatProvider provider);
This datetime do not have any metadata about timezone. You can convert to UTC and then you will be sure that you are able to convert to all timezones.
Use the DateTime.TryParseExact(...) method with DateTimeStyles.RoundtripKind to avoid conversion.
DateTime dt;
DateTime.TryParseExact("201503131557", "yyyyMMddHHmm", null, System.Globalization.DateTimeStyles.RoundtripKind, out dt);
If you need to convert you will need to go to UTC then use the conversion methods of TimeZoneInfo with TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time").

UTC date.ToLocalTime() still produces date in UTC time

I'm working with an ASP.Net backend. I'm saving all my dates from the client side to the database in UTC time.
I have a function in the backend that exports some records and I would like to convert the dates extracted, from UTC time to the user's local time before displaying them.
I have tried tons of solutions proposed here on StackOverflow, but none of them seem to convert the date to local time, even though this works when displaying some of these dates on the client.I suspect the server already thinks the date is in local time, but I'm not sure how else to solve it.
Below are the different solutions I have tried:
//1.
var alertTime = record.TimeRecorded.GetValueOrDefault().ToLocalTime().ToString("hh:mm tt");
// 2.
var alertTime = record.TimeRecorded;
if (alertTime.HasValue)
{
var timeInUtc = TimeZoneInfo.ConvertTimeToUtc(alertTime.Value);
string alertTimeToLocalTime = timeInUtc.ToLocalTime().ToString("hh:mm tt");
}
//alertTimeToLocalTime is still in UTC time here
// 3.
if (alertTime.HasValue)
{
var localTime = TimeZoneInfo.ConvertTimeFromUtc(timeInUtc, TimeZoneInfo.Local);
string alertTimeToLocalTime = localTime.ToString("hh:mm tt");
}
None of these have managed to convert the alertTime to local time.
Am I missing something?
EDIT
//4. Another approach I had already tried which didn't work as well
var alertTime = DateTime.SpecifyKind(record.TimeRecorded.GetValueOrDefault(), DateTimeKind.Utc);
alertTimeToLocalTime = alertTime.ToLocalTime().ToString("hh:mm tt");
You said:
... from UTC time to the user's local time ...
Nothing in ASP.Net will tell you the user's local time zone. Calling ToLocalTime will convert from UTC to the server's time zone (unless the .Kind is already DateTimeKind.Local).
In many cases, the best practice of setting the server's time zone to UTC will mean that you will see no change with ToLocalTime or ToUniversalTime, other than the kind. And since the server's time zone is irrelevant in most cases, this is not the correct approach.
Instead, you either need to know the user's time zone through some other mechanism (such as them selecting it in your application) so you can use the TimeZoneInfo.ConvertTime (or Noda Time) to convert server-side, or you need to send UTC time down to the client and do the utc-to-local in JavaScript (since the browser is running in the user's time zone).
In general, any use of "local time" in a server application (such as ASP.NET) should be avoided. This includes ToLocalTime, ToUniversalTime, DateTimeKind.Local, TimeZoneInfo.Local, DateTime.Now, and a few other miscellaneous things.
It's because your DateTime's Kind is either Local or Unspecified. See the documentation for ToLocalTime():
Starting with the .NET Framework version 2.0, the value returned by the ToLocalTime method is determined by the Kind property of the current DateTime object. The following table describes the possible results.
Utc - This instance of DateTime is converted to local time.
Local - No conversion is performed.
Unspecified - This instance of DateTime is assumed to be a UTC time, and the conversion is performed as if Kind were Utc.
You can use the SpecifyKind method to set the Kind prior to doing the conversion.

Parse DateTime without Timezone information into specific Timezone

This is a follow on from a question answered yesterday..
Convert 12hr Time String to DateTime object
Those times in the xml feed are EST (who does that?) but our timezone is BST.
so 10:30PM is 02:30AM UTC or 03:30AM BST
However, TryParseExact yields 10:30PM in local time (as to be expected given that there is not timezone information)
So the question; how can I parse that time as 02:30AM UTC rather than 10:30PM BST?
However, TryParseExact yields 10:30PM in local time
No, it doesn't. Not unless you tell it to. By default, and unless there's any indication of the offset in the pattern, the parse methods will return DateTime values with a Kind of Unspecified - which is entirely appropriate as no information has been specified. If you just convert it to a string, it will assume it's actually a local time, but that's not what the value itself says. You need to understand the three kinds of DateTime - it's a broken model IMO, but that's what we've got in the BCL.
You can pass that to the appropriate TimeZoneInfo to apply a specific time zone and get an appropriate DateTimeOffset, although it's then up to you to remember the actual time zone involved. (An offset isn't the same as a time zone.)
Alternatively, you could use my Noda Time project, which differentiates between the different logical types rather more clearly. You'd parse as a LocalTime, then decide which LocalDate to join that with in order to produce LocalDateTime, which you could then convert to a ZonedDateTime using the "America/Los_Angeles" time zone (or the Windows equivalent; the choice is yours). In performing that conversion, you'd specify what you'd want to happen if the given local time was invalid or ambiguous due to daylight saving transitions.

Datetime nightmare, any thorough module or control in C# to help ease the pain?

once again I have to create a date module, and once again i live the horror of perfecting it, is it me or are date and time the filthiest animals in programming profession, its the beast lurking behind the door that I wish I never have to deal with :(
does anyone know of a great source I can learn from that deals with dates in the following aspects:
user enters datetime and time zone
system translates to universal time and saves in data source
system retrieves universal time converted to local time chosen by developer (not by server or client location which may not be the right zone to display)
system should consider daylight time saving differences
cannot rely on "DateTime" parsing as it parses bohemiangly with respect to local server time
must give ability to developer to deal in both shapes: datetime and string objects
i looked at blogengine.net to see how they deal with but its too nieve, they save the time difference in hours in the settings datasource, it is absoluteley inaccurate... any sources to help?
i already went far in creating the necessary methods that use CultureInfo, TimeZoneInfo, DateTimeOffset ... yet when i put it to the test, it failed! appreciate the help
EDIT:
After squeezing some more, i narrowed it down to this:
public string PrettyDate(DateTime s, string format)
{
// this one parses to local then returns according to timezone as a string
s = TimeZoneInfo.ConvertTimeBySystemTimeZoneId(s, "AUS Eastern Standard Time");
CultureInfo Culture = CultureInfo.CreateSpecificCulture("en-au");
return s.ToString(format , Culture);
}
problem is, I know the passed date is UTC time because im using
DateTimeOffset.Parse(s, _dtfi).UtcDateTime;
// where dtfi has "yyyy-MM-ddTHH:mmzzz" as its FullDateTimePattern
when i call the function on my datetime, like this:
AuDate.Instance.PrettyDate(el.EventDate,"yyyy-MM-dd HH:mm zzz");
on my machine i get:
2009-11-26 15:01 +11:00
on server I get:
2009-11-26 15:01 -08:00
I find this very peculiar! why is the timezone incorrect? everything else is in place! have i missed something?
My comments for your pointers.
user enters datetime and time zone
# OK no issue
system translates to universal time and saves in data source
# OK no issue
system retrieves universal time converted to local time chosen by developer (not by server or client location which may not be the right zone to display)
# Is this s requirement? Why not just retrieve as universal time
system should consider daylight time saving differences
# Can be handled by DaylightTime Class, TimeZone Class etc
cannot rely on "DateTime" parsing as it parses bohemiangly with respect to local server time
# Then do not rely on DateTime Parsing
must give ability to developer to deal in both shapes: datetime and string objects
# DateTime Class as the basis should be good enough, use TimeZone / TimeZoneInfo / DaylightTime / DateTimeOffset etc to augment it
I feel your pain - which is why I'm part of the Noda Time project to bring a fully-featured date and time API to .NET. However, that's just getting off the ground. If you're still stuck in a year's time, hopefully Noda Time will be the answer :)
The normal .NET situation is better than it was now that we've got DateTimeOffset and TimeZoneInfo, but it's still somewhat lacking.
So long as you use TimeZoneInfo correctly twice, however, it should be fine. I'm not sure that DateTime parsing should be too bad - I think it should parse it as DateTimeKind.Unspecified unless you specify anything else in the data. You can then convert it to UTC using TimeZoneInfo.
Could you provide a short but complete program which shows the problems you're having?
Actually, I find the .NET date/time functionality to be quite nice. I'm puzzled by your troubles with it.
What exactly are you trying to do that DateTimeOffset and TimeZoneInfo can't do for you?
"User enters datetime and timezone" -- Check! Either DateTime or DateTimeOffset would work here.
"System translates to universal time and saves in data source" -- Check! Again, either DateTime or DateTimeOffset would work for you, although most database backends will need some special handling if you want to store timezone offsets. If you're already converting it to UTC, just store it as a datetime field in SQL Server or the equivalent in another RDBMS and don't worry about storing the fact that it's UTC.
"System retrieves universal time converted to local time chosen by the developer" -- Check! Just construct a TimeZoneInfo for your desired local time, and then call TimeZoneInfo.ConvertTime.
"System should consider daylight time saving differences" -- Check! That's what TimeZoneInfo.AdjustmentRule is for.
"Cannot rely on "DateTime" parsing as it parses bohemiangly with respect to local server time" -- ??? First off, "bohemiangly" isn't even a word. And you can customize how the datetime gets parsed with DateTime.ParseExact.
"Must give ability to developer to deal in both shapes: datetime and string objects" -- Why? What's wrong with just keeping one internal representation and then transforming only on input and output? I can't think of any operation on date/time values that would be made easier by doing it against a string.
In short, I think you're just griping about the complexities of handling date/time data in general.
Thanks to Jon Skeet who put me on the right track, i never knew this before but now I know, DateTime object does not hold time zone information in it AT ALL! so whenever i use it i am already losing the datetime offset information, the DateTimeOffset object however, retains the time zone bit, so all my objects should use that, i really thought datetimeoffset object to be a bit limiting, i wanted to post a question about what is different between datetime and datetimeoffset, i should have done that!
now Im using the following code to retrieve the right zone:
string s = "2009-11-26T04:01:00.0000000Z";
DateTimeOffset d = DateTimeOffset.Parse(s);
TimeZoneInfo LocalTimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("AUS Eastern Standard Time");
DateTimeOffset newdate = TimeZoneInfo.ConvertTime(d, LocalTimeZoneInfo);
return newdate.ToString("yyyy-MM-dd HH:mm zzz");
thank you all for your input

Categories