UTC timezone in the OK() function in .NET WebAPI C# - 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.

Related

How to strip timezone from DateTime in .NET Core

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.

How to format url datetime parameter with timezone

I've searched everywhere and can't find the answer. I would like to understand what's going with the way I format the datetime (with timezone) url parameter.
Here is the situation:
The caller program is having DateTime value with UTC timezone.
The receiver Json WebAPI (C#) is running on my local pc which is having Central timezone.
The PoCreationDate is a DateTime type (C#). I do not write code to parse the PoCreationDate value. C# converted it to DateTime object for me auto-magically (thru Serialization?).
Here are the test cases:
Case 1:
This one works
http://******/api/ItemSource/GetItemSourceOption?OrganizationCode=OKC&PoCreationDate=2018-10-08T01:02:03.0000000-05:00
Case 2:
This one does not work and the browser is displaying
<Error>
<Message>The request is invalid.</Message>
</Error>
http://******/api/ItemSource/GetItemSourceOption?OrganizationCode=OKC&PoCreationDate=2018-10-08T05:00:00.0000000+00:00
Notice the different? one of them have a -05:00 the other have +00:00. My timezone is Central (which is -05:00 right now?)
Case 3:
My current work around is to format it this way
http://******/api/ItemSource/GetItemSourceOption?OrganizationCode=OKC&PoCreationDate=2018-10-08T05:00:00Z
=====================
So I am just trying to understand what's going on here and these my thoughts...
I believe that using the Z format is the best solution since the DateTime value (from the source) is always in UTC format.
About the -05:00 and +00:00, are these supposed to be set per the receiver's timezone (the destination Server local timezone)? So for this case, my PC is the receiver (WebAPI) and it's set to Central Time Zone, therefore this value must be -05:00 to represent the current value for Central Time Zone?
Please help me understand this. Thanks.
The + character in the offset is being interpreted as a space, as per URL encoding rules. You will need to encode it, such that it is replaced with %2B.
If you are building this URL from JavaScript, use the encodeURIComponent function.
If you are building it in C#, use the System.Net.WebUtility.UrlEncode method.
Note that doing so will also replace the : characters with %3A, which is optional in a querystring parameter, but still recommended.
In general, parameters passed in the querystring need to be encoded, unless you can guarantee that they contain no special characters.
Also, you may want to ask yourself if this field really needs to be a full date+time+offset. In many cases, one might expect a field like PoCreationDate to be just a date, as in "2018-10-08". Of course, that depends on your application logic and business requirements.

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.

JSON: DateTimes deserialized format inconsistent [duplicate]

I've seen so many different standards for the JSON date format:
"\"\\/Date(1335205592410)\\/\"" .NET JavaScriptSerializer
"\"\\/Date(1335205592410-0500)\\/\"" .NET DataContractJsonSerializer
"2012-04-23T18:25:43.511Z" JavaScript built-in JSON object
"2012-04-21T18:25:43-05:00" ISO 8601
Which one is the right one? Or best? Is there any sort of standard on this?
JSON itself does not specify how dates should be represented, but JavaScript does.
You should use the format emitted by Date's toJSON method:
2012-04-23T18:25:43.511Z
Here's why:
It's human readable but also succinct
It sorts correctly
It includes fractional seconds, which can help re-establish chronology
It conforms to ISO 8601
ISO 8601 has been well-established internationally for more than a decade
ISO 8601 is endorsed by W3C, RFC3339, and XKCD
That being said, every date library ever written can understand "milliseconds since 1970". So for easy portability, ThiefMaster is right.
JSON does not know anything about dates. What .NET does is a non-standard hack/extension.
I would use a format that can be easily converted to a Date object in JavaScript, i.e. one that can be passed to new Date(...). The easiest and probably most portable format is the timestamp containing milliseconds since 1970.
There is no right format; The JSON specification does not specify a format for exchanging dates which is why there are so many different ways to do it.
The best format is arguably a date represented in ISO 8601 format (see Wikipedia); it is a well known and widely used format and can be handled across many different languages, making it very well suited for interoperability. If you have control over the generated json, for example, you provide data to other systems in json format, choosing 8601 as the date interchange format is a good choice.
If you do not have control over the generated json, for example, you are the consumer of json from several different existing systems, the best way of handling this is to have a date parsing utility function to handle the different formats expected.
When in doubt simply go to the javascript web console of a modern browser by pressing F12 (Ctrl+Shift+K in Firefox) and write the following:
new Date().toISOString()
Will output:
"2019-07-04T13:33:03.969Z"
Ta-da!!
From RFC 7493 (The I-JSON Message Format ):
I-JSON stands for either Internet JSON or Interoperable JSON, depending on who you ask.
Protocols often contain data items that are designed to contain
timestamps or time durations. It is RECOMMENDED that all such data
items be expressed as string values in ISO 8601 format, as specified
in RFC 3339, with the additional restrictions that uppercase rather
than lowercase letters be used, that the timezone be included not
defaulted, and that optional trailing seconds be included even when
their value is "00". It is also RECOMMENDED that all data items
containing time durations conform to the "duration" production in
Appendix A of RFC 3339, with the same additional restrictions.
Just for reference I've seen this format used:
Date.UTC(2017,2,22)
It works with JSONP which is supported by the $.getJSON() function. Not sure I would go so far as to recommend this approach... just throwing it out there as a possibility because people are doing it this way.
FWIW: Never use seconds since epoch in a communication protocol, nor milliseconds since epoch, because these are fraught with danger thanks to the randomized implementation of leap seconds (you have no idea whether sender and receiver both properly implement UTC leap seconds).
Kind of a pet hate, but many people believe that UTC is just the new name for GMT -- wrong! If your system does not implement leap seconds then you are using GMT (often called UTC despite being incorrect). If you do fully implement leap seconds you really are using UTC. Future leap seconds cannot be known; they get published by the IERS as necessary and require constant updates. If you are running a system that attempts to implement leap seconds but contains and out-of-date reference table (more common than you might think) then you have neither GMT, nor UTC, you have a wonky system pretending to be UTC.
These date counters are only compatible when expressed in a broken down format (y, m, d, etc). They are NEVER compatible in an epoch format. Keep that in mind.
"2014-01-01T23:28:56.782Z"
The date is represented in a standard and sortable format that represents a UTC time (indicated by the Z). ISO 8601 also supports time zones by replacing the Z with + or – value for the timezone offset:
"2014-02-01T09:28:56.321-10:00"
There are other variations of the timezone encoding in the ISO 8601 spec, but the –10:00 format is the only TZ format that current JSON parsers support. In general it’s best to use the UTC based format (Z) unless you have a specific need for figuring out the time zone in which the date was produced (possible only in server side generation).
NB:
var date = new Date();
console.log(date); // Wed Jan 01 2014 13:28:56 GMT-
1000 (Hawaiian Standard Time)
var json = JSON.stringify(date);
console.log(json); // "2014-01-01T23:28:56.782Z"
To tell you that's the preferred way even though JavaScript doesn't have a standard format for it
// JSON encoded date
var json = "\"2014-01-01T23:28:56.782Z\"";
var dateStr = JSON.parse(json);
console.log(dateStr); // 2014-01-01T23:28:56.782Z
JSON itself has no date format, it does not care how anyone stores dates. However, since this question is tagged with javascript, I assume you want to know how to store javascript dates in JSON. You can just pass in a date to the JSON.stringify method, and it will use Date.prototype.toJSON by default, which in turns uses Date.prototype.toISOString (MDN on Date.toJSON):
const json = JSON.stringify(new Date());
const parsed = JSON.parse(json); //2015-10-26T07:46:36.611Z
const date = new Date(parsed); // Back to date object
I also found it useful to use the reviver parameter of JSON.parse (MDN on JSON.parse) to automatically convert ISO strings back to javascript dates whenever I read JSON strings.
const isoDatePattern = new RegExp(/\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/);
const obj = {
a: 'foo',
b: new Date(1500000000000) // Fri Jul 14 2017, etc...
}
const json = JSON.stringify(obj);
// Convert back, use reviver function:
const parsed = JSON.parse(json, (key, value) => {
if (typeof value === 'string' && value.match(isoDatePattern)){
return new Date(value); // isostring, so cast to js date
}
return value; // leave any other value as-is
});
console.log(parsed.b); // // Fri Jul 14 2017, etc...
The prefered way is using 2018-04-23T18:25:43.511Z...
The picture below shows why this is the prefered way:
So as you see Date has a native Method toJSON, which return in this format and can be easily converted to Date again...
In Sharepoint 2013, getting data in JSON there is no format to convert date into date only format, because in that date should be in ISO format
yourDate.substring(0,10)
This may be helpful for you
I believe that the best format for universal interoperability is not the ISO-8601 string, but rather the format used by EJSON:
{ "myDateField": { "$date" : <ms-since-epoch> } }
As described here: https://docs.meteor.com/api/ejson.html
Benefits
Parsing performance: If you store dates as ISO-8601 strings, this is great if you are expecting a date value under that particular field, but if you have a system which must determine value types without context, you're parsing every string for a date format.
No Need for Date Validation: You need not worry about validation and verification of the date. Even if a string matches ISO-8601 format, it may not be a real date; this can never happen with an EJSON date.
Unambiguous Type Declaration: as far as generic data systems go, if you wanted to store an ISO string as a string in one case, and a real system date in another, generic systems adopting the ISO-8601 string format will not allow this, mechanically (without escape tricks or similar awful solutions).
Conclusion
I understand that a human-readable format (ISO-8601 string) is helpful and more convenient for 80% of use cases, and indeed no-one should ever be told not to store their dates as ISO-8601 strings if that's what their applications understand, but for a universally accepted transport format which should guarantee certain values to for sure be dates, how can we allow for ambiguity and need for so much validation?
it is work for me with parse Server
{
"ContractID": "203-17-DC0101-00003-10011",
"Supplier":"Sample Co., Ltd",
"Value":12345.80,
"Curency":"USD",
"StartDate": {
"__type": "Date",
"iso": "2017-08-22T06:11:00.000Z"
}
}
There is only one correct answer to this and most systems get it wrong. Number of milliseconds since epoch, aka a 64 bit integer. Time Zone is a UI concern and has no business in the app layer or db layer. Why does your db care what time zone something is, when you know it's going to store it as a 64 bit integer then do the transformation calculations.
Strip out the extraneous bits and just treat dates as numbers up to the UI. You can use simple arithmetic operators to do queries and logic.
The following code has worked for me. This code will print date in DD-MM-YYYY format.
DateValue=DateValue.substring(6,8)+"-"+DateValue.substring(4,6)+"-"+DateValue.substring(0,4);
else, you can also use:
DateValue=DateValue.substring(0,4)+"-"+DateValue.substring(4,6)+"-"+DateValue.substring(6,8);
I think that really depends on the use case. In many cases it might be more beneficial to use a proper object model (instead of rendering the date to a string), like so:
{
"person" :
{
"name" : {
"first": "Tom",
"middle": "M",
...
}
"dob" : {
"year": 2012,
"month": 4,
"day": 23,
"hour": 18,
"minute": 25,
"second": 43,
"timeZone": "America/New_York"
}
}
}
Admittedly this is more verbose than RFC 3339 but:
it's human readable as well
it implements a proper object model (as in OOP, as far as JSON permits it)
it supports time zones (not just the UTC offset at the given date and time)
it can support smaller units like milliseconds, nanoseconds, ... or simply fractional seconds
it doesn't require a separate parsing step (to parse the date-time string), the JSON parser will do everything for you
easy creation with any date-time framework or implementation in any language
can easily be extended to support other calendar scales (Hebrew, Chinese, Islamic ...) and eras (AD, BC, ...)
it's year 10000 safe ;-) (RFC 3339 isn't)
supports all-day dates and floating times (Javascript's Date.toJSON() doesn't)
I don't think that correct sorting (as noted by funroll for RFC 3339) is a feature that's really needed when serializing a date to JSON. Also that's only true for date-times having the same time zone offset.

Setting format of DateTime - how do I keep the value in DateTime format?

I have a DateTime being created in the format dd/MM/yyyy HH:mm:ss. I am writing code that interacts with a third-party SOAP library that requires a DateTime variable, in the format yyyy-MM-dd HH:mm:ss.
How do I change the way the information is stored in the DateTime variable, for the purpose of the call to the third-party SOAP library, i.e. no system-wide changes to dates?
I have investigated CultureInfo, which is mildly confusing and possibly too permanent a solution; the only time I need the DateTime changing is for an instance of this single call.
As an explanation, the library has a function GetOrders(DateTime startDate, DateTime endDate, TradingRoleCodeType roleType, OrderStatusCodeType statusType). When attempting to perform the function with DateTimes as created, it generates an error "Sorry, the end date was missing, invalid, or before the start date. must be in YYYY-MM-DD or YYYY-MM-DD HH:MI:SS format, and after the start date.". Given the format that is passed in as dd/MM/yyyy HH:mm:ss, I'd think this may be the problem.
I have a DateTime being created in the format dd/MM/yyyy HH:ii:ss
No, you do not. You have a DateTime. It has no format. It is a number - which is well documented, you know, in the documentation. The string form is never used in a stored DateTime, only when generating the string for presentation.
How do I change the way the information is stored in the DateTime
variable, for the purpose of the call to the third-party SOAP library,
i.e. no system-wide changes to dates?
You do not. I would suggest you talk to your SOAP library - and it is not SOAP btw., IIRC the format you give as example is not valid in SOAP. Yes, bad news. Someone wants Pseudo-Soap.
http://www.w3schools.com/schema/schema_dtypes_date.asp
describes all valid date, time and datetime formats and yours is NOT there.
You can change the default format on a thread level back and forth, so one solution is to set it before calls into the soap library. Another one is to have someone fix the SOAP layer to accept standard formats.
You can create a dummy date :
public class SomeClass
{
[XmlIgnore]
public DateTime SomeDate { get; set; }
[XmlElement("SomeDate")]
public string SomeDateString
{
get { return this.SomeDate.ToString("yyyy-MM-dd HH:mm:ss"); }
set { this.SomeDate = DateTime.Parse(value); }
}
}
Source : Force XmlSerializer to serialize DateTime as 'YYYY-MM-DD hh:mm:ss' --kbrimington
As it turns out, the problem - as some have pointed out - is not to do with the variable being a DateTime, nor its "format" which is not a "format", but is certainly the representation of the information in a method to be understood.
The basic issue with the information was a DateTime comparison between standard time and UTC time. The third-party library examined the DateTime as a UTC DateTime, which when at the right time of year to be caught with a difference in times can cause a problem comparing a DateTime; despite being presented as after the reference time to the user, the time is actually before the reference time when being calculated, meaning the comparison fails.
The main takeaway for this question is to interrogate the information being passed to functions, if you don't have access to third-party library code nor access to documentation with sufficient detail, and errors are occurring when interacting with said third-party code.
Particularly, test various use cases to determine what variable values cause a failure and which cause successful execution of code; identify a pattern, and then test specific use cases that confirm the pattern. From there, determine the actual error that is occurring and code to fix the issue.
In the case of DateTimes, where the code understands DateTimeKinds such as C#, remember to test the different DateTimeKinds to establish whether they can be a part of the problem; its not happened to me often, but it has happened (as evidenced by this question).
Finally, error codes don't help much, and can lead to poor questions and poor advice; trial and error appears to be the best in cases similar to this.
You don't need to change how it's stored, as already mentioned above.
You need to format is as a string according to ISO8601, which is what your SOAP service expects datetime parameter to be.
Check How to parse and generate DateTime objects in ISO 8601 format
and
Given a DateTime object, how do I get an ISO 8601 date in string format?

Categories

Resources