Patrick Peters
Patrick Peters

Reputation: 9568

Local time specific unit test fails

I am developing a dot net core 2.2 console application to convert .csv files to .xml files.

I have a unit test to test the creation of a specific xml filename. Part of the filename is a time. This timepart should always be a local time. Using dotnet core 2.2 with xUnit.

The test succeeds locally (Netherlands, culture nl-NL), but fails when testing in Azure using a Hosting Agent. This Hosting Agent is hosted somewhere in the US (culture en-US).

To fix this test, I created a specific run scope in a specific culture. I assumed that the .LocalTime of the DateTimeOffset gives me the culture specific local time, but it stays in nl-NL when I debug it in VS2019.

Why ?

Here are some code parts (removed some code for better reading):

public class OutputIdentifierServiceTests
{
   [Fact(DisplayName = "Valid filename is created")]
   public void GetOutputIdentifier_ReturnsFilename()
   {
       // Arrange

       // utc time          = 16:52:33
       // local nl-NL time  = 18:52:33

       using (new CurrentCultureScope("en-US"))
       {
           var currentTimeUtc = new DateTimeOffset(2019, 6, 14, 16, 52, 33, TimeSpan.Zero);

           _systemClockServiceMock.SetupGet(s => s.UtcNow).Returns(currentTimeUtc);

           var sut = CreateSut();

           // Act
           var filename = sut.GetOutputIdentifier();

           // Assert
           Assert.Equal("20190614T165233", filename);
       }
   }
}

And the CurrentCultureScope class:

public class CurrentCultureScope : IDisposable
    {
        private readonly CultureInfo _culture;
        private readonly CultureInfo _uiCulture;

        private bool _disposed = false;

        public CurrentCultureScope(string name)
        {
            _culture = Thread.CurrentThread.CurrentCulture;
            _uiCulture = Thread.CurrentThread.CurrentUICulture;

            Thread.CurrentThread.CurrentCulture = new CultureInfo(name);
            Thread.CurrentThread.CurrentUICulture = new CultureInfo(name);
        }

        public void Dispose()
        {
            Dispose(true);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!_disposed)
            {
                if (disposing)
                {
                    Thread.CurrentThread.CurrentCulture = _culture;
                    Thread.CurrentThread.CurrentUICulture = _uiCulture;
                }

                _disposed = true;
            }
        }
    }
}

And the class creating the output identifier:

public string GetOutputIdentifier()
        {
            var currentTimeUtc = _systemClockService.UtcNow;

            var localTime = currentTimeUtc.LocalDateTime;

            var creationDate = localTime.ToString("yyyyMMdd");
            var creationTime = localTime.ToString("HHmmss");

            // code removed
        }

Upvotes: 1

Views: 2655

Answers (1)

Patrick Peters
Patrick Peters

Reputation: 9568

I fixed it in the output identifier function (thanks to Panagiotis Kanavos, see comments). The CurrentCultureScope is not needed.

 var currentTimeUtc = _systemClockService.UtcNow;

 var nlZone = TimeZoneInfo.FindSystemTimeZoneById("W. Europe Standard Time");

 var localTime = TimeZoneInfo.ConvertTime(currentTimeUtc, nlZone);

Upvotes: 1

Related Questions