Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing exact date entered by user from Javascript to .NET

In our ASP.NET MVC web application for private schools, a user can input dates for calendar events (and other things, i.e. homework due dates) that are meant to be interpreted using the school's time zone, which may not necessarily be the same as their own computer (i.e. if they are using the web app while on vacation in another state).

I would like to just pass dates literally, so that when I receive them on the server, I can know exactly what value was entered by the user and let the server take care of converting it to UTC time based on the school's time zone.

On the flip side, I would also like for the server to pass already adjusted dates to the client, and then the client should display those dates as-is. I don't want the dates to be automatically converted to the computer's time zone because I want all dates to be displayed in the school's time zone.

We're using Json.NET for serializing/deserializing JSON. Our current settings for dates are:

serializerSettings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
serializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;

Perhaps I should be using a different option for DateTimeZoneHandling...?

The big problem when deserializing Dates is the actual date the user entered is not preserved, unless they are in the same time zone as our server. So if a client in Pacific enters a date with a time of 4:00 PM, then the server (in Central time) will see it as 6:00 PM, which is correct in that they represent the same time in UTC, but what I really want is to know that the user input 4:00 PM, and take care of figuring out what UTC time that actually represents on the server side.

I'm using NodaTime on the server to handle the conversion of user-input times to an actual UTC time to be stored in the database.

My current solution in javascript, when receiving dates from the server, is to convert them back to UTC so that I have the actual date the server passed. This part feels pretty hacky.

    function convertToUTCDate(date) {
        var utcDate = new Date(
            date.getUTCFullYear(),
            date.getUTCMonth(),
            date.getUTCDate(),
            date.getUTCHours(),
            date.getUTCMinutes(),
            date.getUTCSeconds()
        );

        return utcDate;
    }

I've looked at a lot of StackOverflow questions, and I've gone through Matt Johnson's Date and Time Fundamentals course in PluralSight. I've learned a lot of good principles regarding dates in javascript and .NET, but they all seemed to be different from my case in this: I don't care what the user's time zone is, I want all dates to be displayed in the school's time zone, and also treat date inputs as if they were entering a time in the context of the school's time zone.

Is there an easy and non-hacky way to do what I'm trying to do, in both directions? (client sending dates to server, server sending dates to client)

like image 713
jamebob Avatar asked Sep 05 '25 17:09

jamebob


1 Answers

From the scenario you described, it sounds like the easiest thing to do is to just pass unqualified date and time values, rather than local or UTC.

  • On the server, use DateTime values with Unspecified kind, or use Noda Time's LocalDateTime.

  • Leave JSON.Net's date format handling at the defaults, which are DateFormatHandling.IsoDateFormat and DateTimeZoneHandling.RoundtripKind. You rarely need to modify these, as long as you pay attention to Kind properly.

    • If you're serializing Noda Time types directly, then be sure to wire up the NodaTime.Serialization.JsonNet library using ConfigureForNodaTime, as described in the user guide.
  • Over the wire, the data should look like "eventTime" : "2016-03-01T10:00:00". Don't include a Z, as you're not sending UTC. Don't include an offset either.

  • On the client side, don't use the Date object. It is always going to be working in the local time zone. Instead, consider using moment.js.

    • There's no "unspecified" mode in moment, but you can fake it by using UTC mode, even though the value isn't actually in UTC, this will still work well for formatting. Call moment.utc(yourvalue). Don't use moment(yourvalue), because it will then be in local mode, and will take on the DST behavior of the local time zone just like the Date object.

    • Alternatively, you really can just use strings as RobG suggested in comments. You just have to parse and format them between user input and wire-format yourself. Some may find that easy, others prefer to let a library do it.

Lastly, recognize that I'm making this recommendation based on a lot of assumptions from the scenario you described. It may or may not be ideal, if there are additional use cases you didn't explain. For example, if you're sending the same values to some third-party over this API, then a DateTimeOffset, serialized with the offset included, might be more appropriate.

Also recognize that you could do this all client-side, using something like moment-timezone. However that's probably not necessary for this particular case.

like image 94
Matt Johnson-Pint Avatar answered Sep 07 '25 12:09

Matt Johnson-Pint