C# – How to test that your code can handle another culture’s date format

Let’s say you’re using DateTime.Parse() to convert a date string into a DateTime object.

public class DataProcessor
{
	public static DateTime GetDate(string date)
	{
		return DateTime.Parse(date);
	}
}

By default, DateTime.Parse() uses CultureInfo.CurrentCulture to figure out the date format. The current culture ultimately comes from your OS settings. So when you run this code on a computer that is using the en-US locale, the current culture will automatically default to en-US.

How would you test that DataProcessor.GetDate() is able to parse the date based on the current locale?

The Wrong Way

Simple, I’ll just change CultureInfo.CurrentCulture in my unit test. In this case I am changing it to the French locale “fr”.

[TestMethod]
public void TestGetDate_CanParseFrenchDate()
{
	//arrange
	DateTime expectedDate = DateTime.Parse("7/30/2020", new CultureInfo("en-US"));

	CultureInfo.CurrentCulture = new CultureInfo("fr");
	string convertFromValue = "30/07/2020"; //French format dd/mm/yyyy

	//act
	var actualDate = DataProcessor.GetDate(convertFromValue);

	//assert
	Assert.AreEqual(expectedDate, actualDate);
}
[TestMethod]
public void TestGetDate_CanParseDate()
{
	//arrange
	DateTime expectedDate = DateTime.Parse("7/30/2020", new CultureInfo("en-US"));
	string convertFromValue = "7/30/2020"; 

	//act
	var actualDate = DataProcessor.GetDate(convertFromValue);

	//assert
	Assert.AreEqual(expectedDate, actualDate);
}

Why is this wrong?

If I run each test by itself, it’s fine. They both pass. But if I run them both, one of them will fail with the error message:

System.FormatException: String was not recognized as a valid DateTime.

The reason this is failing is because the unit test is changing CurrentInfo.Culture to “fr” in the current thread. Both unit tests are running on the same thread, therefore this other test changed the culture for the other unit test, hence why it’s failing to parse the string.

Change CultureInfo.CurrentCulture from a different thread

Use Task.Run() to run part of the unit test in another thread, and change the culture only for that thread.

[TestMethod]
public async Task TestGetDate_CanParseFrenchDate()
{
	//arrange
	DateTime expectedDate = DateTime.Parse("7/30/2020", new CultureInfo("en-US"));
	DateTime actualDate = new DateTime();
	await Task.Run(() =>
	{
		//Change the current culture from another thread,
		//therefore this won't impact the other unit tests
		CultureInfo.CurrentCulture = new CultureInfo("fr");
		string convertFromValue = "30/07/2020"; //French format dd/mm/yyyy

		//act
		actualDate = DataProcessor.GetDate(convertFromValue);
	});

	Assert.AreEqual(expectedDate, actualDate);

}

Now when you run both of the unit tests they’ll both pass. This is because this unit test is now only changing the CultureInfo.CurrentCulture for the new thread, and therefore it doesn’t impact the other unit test.

Leave a Comment