Henry Lisowski avatar image
Henry Lisowski asked

DateTime parsing wrong in C# Client SDK

So we've run into a really weird crash using Xamarin Android with the C# client sdk. We hit it before with some of our own code and handle the issue there, but now we're seeing the crash inside the Playfab SDK json parsing code. It stems from how DateTime string parsing is handled for different "CultureInfo" or languages.

Basically the SDK, when parsing the DateTime needs to pass in which Culture to use, and is currently passing in "CultureInfo.CurrentCulture" which means it looks up the current device to know how to interpret the string representing the DateTime. On Android this causes a system call to find the current language, get the Calendar associated with that language, find out how they format their dates so it knows how to parse it.

Current Issue: On languages that have different calendars, that calendar might not be installed thus causing a hard crash. This is the source of the crash we're seeing in some languages (specifically Arabic).

Design Issue: Even if we worked around the calendar issue, it still seems weird that the SDK is hardcoding the CurrentCulture usage. The crash we're seeing hits as soon as we do any login, because part of the return value contains "Last login time". From my experience with similar issues the usual practice is to write libraries to use the "Invariant" culture (especially when dealing with backend) and leaving all "convert to local culture/timezone" to the client/user facing code. If we DID get past the calendar crash, I'm not even sure it'd still work because (I'm assuming at this point) we'd hit a crash trying to interpret a DateTime from the server in what (I'm assuming) is UTC format as a DateTime string in whatever culture setting the user has locally on their device.

(As a reference point while searching for existing posts about this in this forum I found this 3 year old post about the C++ SDK doing the same thing, where even though the server stored times in UTC by the time the SDK client call finished parsing it, it's no longer stored as UTC and instead in the users local timezone settings. Although they weren't dealing with a crash like us, they seemed to have the similar expectation that the api calls should be returning the values as invariant:

Solution: What we did when we hit this with our own DateTime parsing is on the parse calls change from CultureInfo.CurrentCulture to CultureInfo.InvariantCulture. This causes it to use a standardized format independent of language/culture settings. At that point we can leave it to the UI to convert it to the users local culture. I've found the few lines in the Playfab Client SDK repo where this change would be needed, and even have a PR that I could request to put in, but I don't even know if Playfab allows external PRs, especially since I couldn't find the issues tab to even file the issue.

My main question is if this is something that would be considered for a fix, and if so if the repo is open to a PR to fix it, because if not we're going to need to fork the repo and start building it on our own which is its own pain.

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Henry Lisowski avatar image
Henry Lisowski answered

Yup, here's the location I'm talking about:

In most cases I imagine this call would be perfectly fine, but in our scenario on Android the stack trace we're getting is:

Non-fatal Exception: crc644925ff5c0134f0c2.InvalidOperationException:  Failed to login, error message was System.ArgumentOutOfRangeException: Not a valid calendar for the given culture.
       at DateTimeFormatInfo.set_Calendar (Calendar value) [0x00142] in <d64d422ba8ce408095330b4ac61a309f>:0(DateTimeFormatInfo.cs)
       at System.Globalization.DateTimeFormatInfo..ctor (CultureData cultureData, Calendar cal) [0x00022] in <d64d422ba8ce408095330b4ac61a309f>:0(.cs)
       at System.Globalization.CultureInfo.get_DateTimeFormat () [0x00042] in <d64d422ba8ce408095330b4ac61a309f>:0(CultureInfo.cs)
       at System.Globalization.DateTimeFormatInfo.GetInstance (IFormatProvider provider) [0x00042] in <d64d422ba8ce408095330b4ac61a309f>:0(DateTimeFormatInfo.cs)
       at System.DateTime.TryParseExact (String s, String[] formats, IFormatProvider provider, DateTimeStyles style, DateTime& result) [0x0001e] in <d64d422ba8ce408095330b4ac61a309f>:0(DateTime.cs)
       at PlayFab.Json.SimpleJsonInstance+PlayFabJsonSerializerStrategy.SimpleJsonInstance+DeserializeObject (Object value, Type type) [0x00064] in <cf8d5657351f464c8f8e345445533936>:0(SimpleJsonInstance+PlayFabJsonSerializerStrategy.cs)

I'm still digging into the specific error (something about having not included the correct Calendar type for a specific Culture setting) but before even hitting that it seems weird that a call to parse a field for "Last time logged in" is causing calls down the chain to retrieve calendar info for the given client culture. I feel like an api client should be as lightweight as possible, and any culture conversions be done on the frontend only when required. I believe that's what "InvariantCulture" option is made for, so it uses a standardized culture setting regardless of the users settings.

10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Rick Chen avatar image Rick Chen ♦ commented ·

Thanks for the information. I will discuss this issue with the corresponding team. For now, you could avoid using this function or apply your own solution. You may also open a pull request to the SDK GitHub repo if you want.

0 Likes 0 ·
Henry Lisowski avatar image Henry Lisowski Rick Chen ♦ commented ·

Thanks for the reply! Hopefully we can find a workaround in the interim since not using the "login" call is probably a deal breaker lol. I've posted a PR at the repo here:

1 Like 1 ·
Rick Chen avatar image Rick Chen ♦ Henry Lisowski commented ·

Thank you for your work.

0 Likes 0 ·
Rick Chen avatar image
Rick Chen answered

By C# Client SDK, do you mean the PlayFabAllSDK in C#? What do you mean by the SDK parsing the DateTime needs to pass in which Culture to use? Can you specify the location of this part of the code in the SDK?

If you want to parse the datetime in C# to a standard format string or custom format string, you could use the DateTime.ToString({format specifier}).

For example, the following code snippet could return the Universal sortable date/time pattern.

var result = await PlayFabClientAPI.LoginWithCustomIDAsync(new
PlayFab.ClientModels.LoginWithCustomIDRequest {
CustomId = "csharptest",
TitleId = PlayFabSettings.staticSettings.TitleId,
DateTime lastlogin = (DateTime) result.Result.LastLoginTime;
if (lastlogin != null)
Console.WriteLine("LastLoginTime: "+ lastlogin.ToString("u"));

datetime-format.png (21.1 KiB)
10 |1200

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.

Write an Answer

Hint: Notify or tag a user in this post by typing @username.

Up to 2 attachments (including images) can be used with a maximum of 512.0 KiB each and 1.0 MiB total.