How to strip timezone from DateTime in .NET Core - c#

I have a use case that I'm not sure how to solve in a nice way.
I'm currently developing a .Net Core WebApi that is receiving data from various current systems, from a cross the whole world. Which I then process and lastly I commit it to SAP through oData endpoint.
The problem I'm having is on of parameters I'm receiving in the body payload, is a DateTime. Previous I have not have any issues. But not long ago I started getting data from a other system which deliverers it in a slightly differently way.
Previously this was the format I got: 2020-09-16T16:30:00 not problem with it. But the new system looks like this: 2020-09-16T16:00:00 -05:00 Could also end in +08:00.
The problem I'm facing is that SAP needs to get in local time. But in the my code it converts this: 2020-09-16T16:00:00 -05:00 to 2020-09-16T23:00:00 when I see the incoming payload in the controller.
I have searched quite a bit to find a solution. But 99% only suggest using UTC time, which is not a option for me.
Another option is to use DateTimeOffset, which I have tried but can't the time conversion to use localTime.
My question is. Are it not possible to custom convert to strip the timezone before it hits the controller?

Generarally when you're working with datetime data that includes offsets for time zone the DateTimeOffset type is a good place to start. The sample string 2020-09-16T16:00:00 -05:00 can be passed to DateTimeOffset.Parse() to get a correct DTO value with timezone information attached. From there you can get the local time, UTC time or a DateTime value with the timezone stripped.
string source = "2020-09-16T16:00:00 -05:00";
string fmt = #"yyyy-MM-dd\THH:mm:ss zzz"
// Same as input
Console.WriteLine(DateTimeOffset.Parse(source).ToString(fmt));
// Adjusted to your local timezone
Console.WriteLine(DateTimeOffset.Parse(source).ToLocalTime().ToString(fmt));
// DateTime portion of the source, timezone offset ignored
Console.WriteLine(DateTimeOffset.Parse(source).DateTime.ToString());
Getting the UTC time is simple too via the UtcDateTime property.
It sounds like what you want is the last one - just the date and time from the inputt string with the timezone offset stripped. If you just want the corresponding local time then DateTime.Parse should give that to you directly.
The JsonSerializer class doesn't support this format for DateTimeOffset so you might have some trouble getting it converted before hitting your controller. In that case you'd need to accept a string and do the conversion by hand in your code. You also might need to investigate the TryParseExact method.

Use DateTime.Parse() , for example
string timeInString1 = "2020-09-16T16:00:00 -05:00";
DateTime moment1 = DateTime.Parse(timeInString1);
string timeInString2 = "2020-09-16T16:00:00 +08:00";
DateTime moment2 = DateTime.Parse(timeInString2);
string timeInString3 = "2020-09-16T16:30:00";
DateTime moment3 = DateTime.Parse(timeInString3);
but momen1, momen2, or moment3 is non-timezone awareness value.

Related

Is there functionality to convert from UTC time to local time using country name? [duplicate]

We are developing a C# application for a web-service client. This will run on Windows XP PC's.
One of the fields returned by the web service is a DateTime field. The server returns a field in GMT format i.e. with a "Z" at the end.
However, we found that .NET seems to do some kind of implicit conversion and the time was always 12 hours out.
The following code sample resolves this to some extent in that the 12 hour difference has gone but it makes no allowance for NZ daylight saving.
CultureInfo ci = new CultureInfo("en-NZ");
string date = "Web service date".ToString("R", ci);
DateTime convertedDate = DateTime.Parse(date);
As per this date site:
UTC/GMT Offset
Standard time zone: UTC/GMT +12 hours
Daylight saving time: +1 hour
Current time zone offset: UTC/GMT +13 hours
How do we adjust for the extra hour? Can this be done programmatically or is this some kind of setting on the PC's?
For strings such as 2012-09-19 01:27:30.000, DateTime.Parse cannot tell what time zone the date and time are from.
DateTime has a Kind property, which can have one of three time zone options:
Unspecified
Local
Utc
NOTE If you are wishing to represent a date/time other than UTC or your local time zone, then you should use DateTimeOffset.
So for the code in your question:
DateTime convertedDate = DateTime.Parse(dateStr);
var kind = convertedDate.Kind; // will equal DateTimeKind.Unspecified
You say you know what kind it is, so tell it.
DateTime convertedDate = DateTime.SpecifyKind(
DateTime.Parse(dateStr),
DateTimeKind.Utc);
var kind = convertedDate.Kind; // will equal DateTimeKind.Utc
Now, once the system knows its in UTC time, you can just call ToLocalTime:
DateTime dt = convertedDate.ToLocalTime();
This will give you the result you require.
I'd look into using the System.TimeZoneInfo class if you are in .NET 3.5. See http://msdn.microsoft.com/en-us/library/system.timezoneinfo.aspx. This should take into account the daylight savings changes correctly.
// Coordinated Universal Time string from
// DateTime.Now.ToUniversalTime().ToString("u");
string date = "2009-02-25 16:13:00Z";
// Local .NET timeZone.
DateTime localDateTime = DateTime.Parse(date);
DateTime utcDateTime = localDateTime.ToUniversalTime();
// ID from:
// "HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Time Zone"
// See http://msdn.microsoft.com/en-us/library/system.timezoneinfo.id.aspx
string nzTimeZoneKey = "New Zealand Standard Time";
TimeZoneInfo nzTimeZone = TimeZoneInfo.FindSystemTimeZoneById(nzTimeZoneKey);
DateTime nzDateTime = TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, nzTimeZone);
TimeZone.CurrentTimeZone.ToLocalTime(date);
DateTime objects have the Kind of Unspecified by default, which for the purposes of ToLocalTime is assumed to be UTC.
To get the local time of an Unspecified DateTime object, you therefore just need to do this:
convertedDate.ToLocalTime();
The step of changing the Kind of the DateTime from Unspecified to UTC is unnecessary. Unspecified is assumed to be UTC for the purposes of ToLocalTime: http://msdn.microsoft.com/en-us/library/system.datetime.tolocaltime.aspx
I know this is an older question, but I ran into a similar situation, and I wanted to share what I had found for future searchers, possibly including myself :).
DateTime.Parse() can be tricky -- see here for example.
If the DateTime is coming from a Web service or some other source with a known format, you might want to consider something like
DateTime.ParseExact(dateString,
"MM/dd/yyyy HH:mm:ss",
CultureInfo.InvariantCulture,
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal)
or, even better,
DateTime.TryParseExact(...)
The AssumeUniversal flag tells the parser that the date/time is already UTC; the combination of AssumeUniversal and AdjustToUniversal tells it not to convert the result to "local" time, which it will try to do by default. (I personally try to deal exclusively with UTC in the business / application / service layer(s) anyway. But bypassing the conversion to local time also speeds things up -- by 50% or more in my tests, see below.)
Here's what we were doing before:
DateTime.Parse(dateString, new CultureInfo("en-US"))
We had profiled the app and found that the DateTime.Parse represented a significant percentage of CPU usage. (Incidentally, the CultureInfo constructor was not a significant contributor to CPU usage.)
So I set up a console app to parse a date/time string 10000 times in a variety of ways. Bottom line:
Parse() 10 sec
ParseExact() (converting to local) 20-45 ms
ParseExact() (not converting to local) 10-15 ms
... and yes, the results for Parse() are in seconds, whereas the others are in milliseconds.
I'd just like to add a general note of caution.
If all you are doing is getting the current time from the computer's internal clock to put a date/time on the display or a report, then all is well. But if you are saving the date/time information for later reference or are computing date/times, beware!
Let's say you determine that a cruise ship arrived in Honolulu on 20 Dec 2007 at 15:00 UTC. And you want to know what local time that was.
1. There are probably at least three 'locals' involved. Local may mean Honolulu, or it may mean where your computer is located, or it may mean the location where your customer is located.
2. If you use the built-in functions to do the conversion, it will probably be wrong. This is because daylight savings time is (probably) currently in effect on your computer, but was NOT in effect in December. But Windows does not know this... all it has is one flag to determine if daylight savings time is currently in effect. And if it is currently in effect, then it will happily add an hour even to a date in December.
3. Daylight savings time is implemented differently (or not at all) in various political subdivisions. Don't think that just because your country changes on a specific date, that other countries will too.
#TimeZoneInfo.ConvertTimeFromUtc(timeUtc, TimeZoneInfo.Local)
Don't forget if you already have a DateTime object and are not sure if it's UTC or Local, it's easy enough to use the methods on the object directly:
DateTime convertedDate = DateTime.Parse(date);
DateTime localDate = convertedDate.ToLocalTime();
How do we adjust for the extra hour?
Unless specified .net will use the local pc settings. I'd have a read of: http://msdn.microsoft.com/en-us/library/system.globalization.daylighttime.aspx
By the looks the code might look something like:
DaylightTime daylight = TimeZone.CurrentTimeZone.GetDaylightChanges( year );
And as mentioned above double check what timezone setting your server is on. There are articles on the net for how to safely affect the changes in IIS.
In answer to Dana's suggestion:
The code sample now looks like:
string date = "Web service date"..ToString("R", ci);
DateTime convertedDate = DateTime.Parse(date);
DateTime dt = TimeZone.CurrentTimeZone.ToLocalTime(convertedDate);
The original date was 20/08/08; the kind was UTC.
Both "convertedDate" and "dt" are the same:
21/08/08 10:00:26; the kind was local
I had the problem with it being in a data set being pushed across the wire (webservice to client) that it would automatically change because the DataColumn's DateType field was set to local. Make sure you check what the DateType is if your pushing DataSets across.
If you don't want it to change, set it to Unspecified
I came across this question as I was having a problem with the UTC dates you get back through the twitter API (created_at field on a status); I need to convert them to DateTime. None of the answers/ code samples in the answers on this page were sufficient to stop me getting a "String was not recognized as a valid DateTime" error (but it's the closest I have got to finding the correct answer on SO)
Posting this link here in case this helps someone else - the answer I needed was found on this blog post: http://www.wduffy.co.uk/blog/parsing-dates-when-aspnets-datetimeparse-doesnt-work/ - basically use DateTime.ParseExact with a format string instead of DateTime.Parse
This code block uses universal time to convert current DateTime object then converts it back to local DateTime. Works perfect for me I hope it helps!
CreatedDate.ToUniversalTime().ToLocalTime();

C# DateTimeInvalidLocalFormat - How to set timezone to UTC

I'm working in a EasyPost integration making a class library to make the use of their API simpler and I'm getting this error:
Managed Debugging Assistant 'DateTimeInvalidLocalFormat' has detected a problem in 'C:\Projects\TestClient.vshost.exe'.
Additional information: A UTC DateTime is being converted to text in a format that is only correct for local times. This can happen when calling DateTime.ToString using the 'z' format specifier, which will include a local time zone offset in the output. In that case, either use the 'Z' format specifier, which designates a UTC time, or use the 'o' format string, which is the recommended way to persist a DateTime in text. This can also occur when passing a DateTime to be serialized by XmlConvert or DataSet. If using XmlConvert.ToString, pass in XmlDateTimeSerializationMode.RoundtripKind to serialize correctly. If using DataSet, set the DateTimeMode on the DataColumn object to DataSetDateTime.Utc.
I get this error when I call the Create method in the EasyPost Shipment object. Code below:
Shipment shipment = new Shipment() {
to_address = toAddress,
from_address = fromAddress,
parcel = parcel
};
shipment.Create();
This create function probably makes a call to their REST API and is trying to convert a json response into one of their models.
To solve the error I'm trying to set the UTC as the default of my library so whenever I use DateTime.ToString() I use the DateTime.ToString("o"). I don't know if this would actually solve the problem, but I don't know how to force it (use UTC as the library default). I have tried the piece of code below, but it doesn't work
CultureInfo newCulture = CultureInfo.InvariantCulture;
Thread.CurrentThread.CurrentCulture = newCulture;
Can you help me?
I'm one of the developers on the EasyPost client libraries.
As far as I can find in some basic research, there's no (easy) way to set a default time zone for a C# application. Most of the blog posts and other SO answers I found suggest using utility functions to convert a UTC datetime object to a local datetime object when trying to display it to a string.
EasyPost's API returns all datetimes in UTC time + timezone information (ex. 2022-10-24T12:37:24-06:00), which is accounted for when the JSON is deserialized into a DateTime object in the C# client library.

UTC timezone in the OK() function in .NET WebAPI C#

I have a .NET WebAPI which returns some dates as JSON.
I'm using the Ok() function which takes the C# DateTime list and convert them into a JSON array.
My requirement is to specify the timezone in any case (even +00:00)
Now, the format I'm using is:
jsonSerializerSettings.DateFormatString = "o";
which uses the ISO standard and a "Z" to specify UTC.
Unfortunately my web application doesn't understand such convention (I mean, the final "Z") and it requires a timezone offset to be present in any case.
In other words, I'd like to use a "+00:00" instead of the "Z".
How can I tell WebAPI to use such convention?
Previously I had:
jsonSerializerSettings.DateFormatString = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.fffzzz";
which doesn't had the timezone information.
This is not as easy as one would like - mainly, because the DateTime type is confusing at its best, and wrong at its worst.
I would recommend handling only UTC dates on the server (i.e. assuming UTC on any incoming date, saving everything as UTC and returning UTC everywhere) and letting your clients decide if they need to do something about that (e.g. convert to a local time for correct display). Then, it could be as easy as setting
jsonSerializerSettings.DateFormatString = "yyyy-MM-ddTHH:mm:ss.fff+00:00";
i.e. hard-coding the +00:00 there, since you know (by assumption) that it's going to be UTC.
Use System.DateTimeOffset instead of Use System.DateTime in your return statement (Ok). This will automatically append the +00:00 the the serialized string (+00:00 is assuming its a UTC point in time).
for Web API 2 and higher, I am not sure about previous versions
This is also the default date/time format for other Web API extensions like oData.

Parse date with time zone, skip timezone

I try to parse date from string which contains time zone information. Input string is 2014-12-17T08:05:39+00:00.
I use DateTime.Parse() method which return me 2014-12-17 09:05:39 (one hour was added). I live in UTC+1:00 (Warsaw), so .NET adopt this date to my local time.
My question is how to use the parse method while skipping time zone, for example for 2014-12-17T08:05:39+00:00 I want to get 2014-12-17 08:05:39.
I would recommend parsing it as a DateTimeOffset instead of as a DateTime. You can then get the DateTime out of that, but it separates the "parsing the data you've been given" step from the "only using the bits I want from that" step.
It's possible that there are ways to make DateTime.Parse behave the way you want using DateTimeStyles - and I'm surprised it's converting to a "local" kind automatically anyway - but using DateTimeOffset will make it clearer.
(Of course I'd really recommend using Noda Time instead, parsing to an OffsetDateTime and then getting the LocalDateTime out of that, but that's a different matter...)
If you remove the part specifying time zone in input string then it parses directly without adjusting to local time. The date.Kind is then Unspecified.
var input = "2014-12-17T08:05:39";
var date = DateTime.Parse(fixedInput);
Although this works you might want to have a look on NodaTime as well.
You should try using DateTimeOffset instead of the DateTime
DateTimeOffset result = DateTimeOffset.Parse("2014-12-17T08:05:39+00:00", CultureInfo.InvariantCulture);
it gives you : 12/17/2014 8:05:39 AM +00:00

Convert javascript date time to C#/VB.NET date time

I want to get client timezone so i'm using the code below
function filltime()
{
document.getElementById("hdnTime").value = new Date();
}
conversion
Dim time As Date = DateTime.ParseExact(hdnTime.Value,
"ddd MMM d HH:mm:ss UTCzzzzz yyyy",InvariantCulture)
I'm not getting exact value. Its showing server time only.
But hdnTime.Value contains the correct value("Mon Feb 18 14:46:49 UTC+0530 2013"). I think the problem is with conversion.
What is the problem? How can I solve?
Dates and times are a pain in 1 language, let alone when passing a value between 2.
I'd recommend serializing the JavaScript Date() object into JSON before posting it back to the server. Then de-serializing it into a C# DateTime object using a library such as JSON.NET. There's comprehensive documentation (Serializing Dates in JSON) with regards to what settings can be applied when serializing and de-serializing.
JavaScript
function filltime()
{
document.getElementById("hdnTime").value = JSON.stringify(new Date());
}
JSON isn't native to every browser, so you mean need to manually load it in, for more information you can refer to: Browser-native JSON support (window.JSON)
C# using JSON.NET
DateTime dateTime = JsonConvert.DeserializeObject<DateTime>(hdnTime.Value);
You are confusing the DateTime object with its displaying
it is normal that you see the server time because you are seeing the datetime rappresentation with your current timezone.
What you don't get is how DateTime works...
If you pass a datetime with timezone info then it will be converted to your timezone with the right offset.
If you want to pass a datetime and get it as it is than you have to remove the timezone part.
In you situation, anyway, if you need only to know the client timezone just pass it!
var d = new Date()
var n = d.getTimezoneOffset();
The getTimezoneOffset() method returns the time difference between UTC time and local time, in minutes.
For example, If your time zone is GMT+2, -120 will be returned.
For general discussion:
in my experience the best way to deal with datetime converted as string and passed between different systems, is to use the ISODATE format:
DateTime.Now.ToString("s"); //"2013-02-18T11:17:24"

Categories

Resources