2

I'm using the code from here to wrap NodaTime functions to convert to/from UTC/Local times for a .NET Core 2.1 web app.: https://www.joeaudette.com/blog/2016/06/23/cross-platform-timezone-handling-for-aspnet-core

This works fine locally on Windows, but when deployed to a linux server the conversion to local time drops the timezone information (eg. the +13:00 after the datetime).

I'm using NodaTime 2.4.2.

The wrapper returns a DateTime which is being implicitly converted to a DateTimeOffset.

Does anyone know why this might be happening?

DeLucas
  • 101
  • 1
  • 6
  • Welcome to Stack Overflow. Please could you provide a [mcve] (ideally as a console app rather than a web app), including the time zone ID and time zone provider you're using? – Jon Skeet Dec 11 '18 at 09:11
  • Separate question what is the exact issue you are having with .net time APIs that makes you choose a 3rd party api with an unpredictable support and quality – Dogu Arslan Dec 11 '18 at 09:19
  • 2
    @DoguArslan: I suspect if you find a bug in Noda Time I'll fix it much quicker than if you find a bug in `DateTime` :) You might want to read https://blog.nodatime.org/2011/08/what-wrong-with-datetime-anyway.html for motivations behind the library. – Jon Skeet Dec 11 '18 at 09:56
  • @JonSkeet question is for OP. I am interested to know what specific issue he had with .Net implementation to revert to a custom 3rd party api. – Dogu Arslan Dec 12 '18 at 22:56
  • @DoguArslan: The OP doesn't seem to be responding, and I thought I'd offer just some of the reasons someone might want to use Noda Time. There are plenty of others, such as the use of IANA time zone IDs, and more control over which time zone data version is in use. Would you ask someone why they used Json.NET over JavaScriptSerializer? It seemed like an odd question for you to ask about a reasonably commonly-used and mature library, particularly casting aspersions on the quality of the implementation and support. – Jon Skeet Dec 13 '18 at 06:13
  • Hi guys. Sorry for the late response. I was amazed at how fast you replied actually! – DeLucas Dec 14 '18 at 01:31
  • I have solved my issue, but I don't have time right now to create an example but I can explain what happened. I was using the .NET type DateTimeOffset to store my dates, backed by the SQL Server datetimeoffset type. When I used the above wrapper (which uses NodaTime) it was returning the dates converted in to the desired timezone correctly, but this was then implicitly cast from DateTime to DateTimeOffset... – DeLucas Dec 14 '18 at 01:38
  • ... On Windows the Offset field was populated with +13 (NZ) but on Linux it was empty. So when this field was sent to my Angular front-end, Angular was applying a local conversion as it assumed it was in UTC. Hence the dates when the server was hosted on Linux were all +26 hours ahead as they had two local conversions applied. I have managed to fix this by changing from DateTimeOffset to DateTime as that removes the timezone and the front end doesn't apply any conversion. – DeLucas Dec 14 '18 at 01:40
  • @DoguArslan The issue I had is that I am running the web app in two environments: Windows and Linux, and need to provide international date support using a common timezone standard. Using classes like TimeZoneInfo on Windows is fine but this doesn't work in Linux which uses the IANA standard. Here is a good explanation: https://stackoverflow.com/questions/41566395/timezoneinfo-in-net-core-when-hosting-on-unix-nginx So, that is why I chose NodaTime. Because it works with the IANA time zone Ids which work on both platforms. I didn't want to write a mapper or need to detect the OS. – DeLucas Dec 14 '18 at 01:48
  • @DeLucas: I would suggest either taking the time to reproduce the issue (which it sounds like you should be able to do without using Noda Time at all, if it was the conversion from `DateTime` to `DateTimeOffset` that was the problem) or deleting the question. My guess is that the difference is actually that your Linux server has a system default time zone of UTC whereas your Windows server has a system default time zone of NZ. That would explain what you saw... and is a great example of why Noda Time doesn't use the system default time zone anywhere implicitly. – Jon Skeet Dec 14 '18 at 07:08
  • @JonSkeet You are right, it's not a NodaTime issue. I will delete the question. Many thanks. – DeLucas Dec 14 '18 at 21:10

2 Answers2

4

Firstly, I'd recommend that if you use Noda Time, you use it as widely as possible rather than in small pockets like this. The less code you have using the BCL types (DateTime etc) the better.

The problem here isn't caused by Noda Time though - it's caused by the conversion from DateTime to DateTimeOffset.

The code you've got converts a LocalDateTime to a DateTime with a Kind of Unspecified. As noted in comments, you're actually using DateTimeOffset in your code. The implicit conversion from DateTime to DateTimeOffset will perform a time zone conversion using the default system time zone when the Kind is either Unspecified or Local. (This sort of implicit use of ambient context is one of the things Noda Time tries to prevent.) It sounds like your Linux server has one system time zone, and the Windows server has a different one.

If you want to keep the DateTimeOffset part of your code, but accurately represent an instant in a particular time zone, the simplest fix is to change the methods to return DateTimeOffset, and just call ZonedDateTime.ToDateTimeOffset at the end of ConvertToLocalTime:

return new ZonedDateTime(instant, timeZone).ToDateTimeOffset();
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
0

Not a NodaTime issue. Issue caused by default timezone in different servers.

DeLucas
  • 101
  • 1
  • 6
  • I'll add a more detailed answer if you think it's worth keeping the question. – Jon Skeet Dec 18 '18 at 10:12
  • @JonSkeet Hi. I'm happy to keep it or close it. Your question has helped me a lot, so perhaps it's worth keeping just for the explanation of the correct usage of DateTimeOffset. However, perhaps it's in the wrong place? I tried to close the ticket before but I couldn't figure out how. What is the correct thing to do? – DeLucas Dec 19 '18 at 08:03
  • At this point, it's probably worth leaving as it is. You could improve it by mentioning `DateTimeOffset` in the question, but at that point it's okay. – Jon Skeet Dec 19 '18 at 08:10