2

I am working on a news website and I am saving all dates in the database in UTC. Then, depending on the browser/machine location, I want to display the date/time correspondingly (Convert from UTC to the Local time of the machine/browser).

First of all, I would like to know if I am doing this the way it should be done or not (UTC dates in the database).

Second, I wonder why isn't it that straightforward to do so in VB.NET? Below are the approaches I tried but none worked as needed:

Approach 1:

TimeZoneInfo.ConvertTimeFromUtC

This kept returning the server time and not the client/machine time.

Approach 2:

Dim TimeZone As TimeZoneInfo = TimeZoneInfo.FindSystemTimeZoneById("Middle East Standard Time")
Dim Dated As DateTime = TimeZoneInfo.ConvertTimeFromUtC(TempDate, TimeZone)

This worked but not as intended. This converted the UTC date/time in the database to the Middle East Time Zone but any user from any other place in the world will only see the date/time in Middle East Time Zone and not in the actual timezone of his place. Also, I am not sure if the conversion considers DayLightSaving or not.

Approach 3:

I tried to fix this using JavaScript. I created a cookie that saves the offset from UTC and tried handling the offset in VB.NET and do the conversion.

<script>
    function setCookie(cname, cvalue, exdays) {
        var d = new Date();
        d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
        var expires = "expires=" + d.toUTCString();
        document.cookie = cname + "=" + cvalue + ";" + expires + ";path=/";
    }

    function getTimeOffset() {
        var offset = new Date().getTimezoneOffset();
        setCookie("_tz", offset);
    }
</script>  

JavaScripts returns the correct Offset and I am saving this offset in a cookie. Since JavaScript launches after Page_Load, I am calling the JavaScript function getTimeOffset() on Page_Init:

ScriptManager.RegisterStartupScript(Me, Page.GetType, "Script", "getTimeOffset();", True)

The cookie is being created before the page is rendered and the offset stored in the cookie is correct (This is what I actually want!). The problem here is on the first load. VB.NET reads the cookie value as empty string on the first load. On the second Page_Load onwards, VB.NET reads the cookie value and does the conversion correctly.

Approach 4

Tried to get the offset using all the examples in this fiddle but the offset is always 0 which is wrong.

Summary

I wonder if there is any function I missed in VB.NET to avoid all that hassle. Shouldn't it be an easy task to convert date/time from UTC to Local?

Please let me know if there is anything I am doing wrong or if there is a better alternative.

Rami Zebian
  • 539
  • 1
  • 5
  • 23
  • You might find [this DotNetHeaven article](https://www.dotnetheaven.com/article/get-current-time-zone-in-vb.net) useful. I found this as the first Google hit for the search terms [vb.net get computer current time zone](https://www.google.com/search?q=vb.net+get+computer+current+time+zone) – Jeff Zeitlin Sep 28 '18 at 18:50
  • Your approach is right, but just use DateTime.SpecifyKind. Take a look at this example: https://dotnetfiddle.net/XxOiCb – David Sep 28 '18 at 19:07
  • You could do it in the browser. Render the datetime into a `` with a `data-time` [attribute](https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes) set to the UTC datetime, then use, say, jQuery to render the converted datetime into the innerHtml of the span in the $(document).ready event. Or something like that. – Andrew Morton Sep 28 '18 at 19:13
  • @JeffZeitlin The `GetUtcOffset` returning 0 and I am 2 hours ahead of UTC. Check this example: https://dotnetfiddle.net/6aaF0a @David I checked the example and it returns UTC time. I tried placing `DateTimeKind.Local` instead of `DateTimeKind.Utc` but still I get UTC time. Any advice? @AndrewMorton I guess this is what I tried in approach 3 but works on the second reload and not the first. I want to avoid reloading the page on the first hit. Any clear example of this? – Rami Zebian Sep 29 '18 at 08:57

1 Answers1

1

Your back-end code doesn't know anything about the time zone of the browser. It doesn't matter what language you are using, only the browser will know anything about the user's time zone.

When .Net code (regardless of VB or C#) refers to "local", it means the local time zone of where that code is running. In other words, in an ASP.Net web application, that's the local time zone of your server, not of the user. Generally speaking, the server's local time zone is usually irrelevant.

To achieve your goal, break the problem up into two parts.

  1. Get the user's time zone in the browser, send it to the server.
  2. Convert time on the server, using the time zone passed in.

For step 1, read this answer I posted to a different question. Note that the output will be an IANA time zone identifier. Do not pass a numeric offset, as it does not carry enough information to properly convert different points in time (consider daylight saving time, and other anomalies with time zones).

For step 2, you'll need to choose between one of these approaches:

  • You can use the IANA time zone identifier natively with TimeZoneInfo if you're running .NET Core on a non-Windows OS, or with the Noda Time library on any platform.

  • You can convert the IANA time zone identifier to a Windows time zone identifier using my TimeZoneConverter library, and then you can use the result with the TimeZoneInfo class on Windows.

One little thing: You used TimeZoneInfo.ConvertTimeToUtc, where I think you meant TimeZoneInfo.ConvertTimeFromUtc. Be careful of the directionality of the conversions.

I'll also point out that there's an alternative approach, which is to pass the UTC timestamp all the way down to the browser, and just convert from UTC to local time in JavaScript. Then you don't need to do any time zone detection at all.

Matt Johnson-Pint
  • 230,703
  • 74
  • 448
  • 575
  • Thank you for the info and suggestions. Step 1: the link does not work.You suggested to get the timezone from the browser and send it to the server. This will possibly be a good scenario when using register/sign in functionalities. However, if the landing page shows the time, the JS won't run before the Page_Load. This means that the approach will work starting from the second page_load (if we are using sessions/cookies). Step 2: I will perform a test and mark the answer as "solved" if it worked. Thank you for that! – Rami Zebian Oct 04 '18 at 12:30
  • Not sure why, but apparently that long-standing question was just deleted. [Here is another one that's similar](https://stackoverflow.com/a/34602679/634824). Basically you want to call `Intl.DateTimeFormat().resolvedOptions().timeZone`. – Matt Johnson-Pint Oct 04 '18 at 16:45