I'm about to go insane dealing with datetime issues and the web.
I have a web server hosted in the Central Time Zone. When clients in the Eastern Time Zone try and schedule an item for a given day using my app, they pass in the value of (for example) 3/14/2015. When we pass the code back to our model, which is sent to the web api, we persist is using something like the code below.
moment.utc($("#mydatepicker").val).hour(0).minute(0).second(0)).toISOString();
This results in a string like the following:
2015-03-14T04:00:00.000Z
When the item is converted back on the server in web api, it converts to
3/13/2015 11:00:00 PM
Logic then strips off time and you can see what happens from here. Since I stripped off the time, it is now the day prior and that is the value persisted to the database.
I need to know some way to send a value from moment, into the web api preferrably as a ZonedDateTime in the client's time zone. I can then convert it to UTC for persistance in the DB.
I've seen things about using NodaTime.Serialization.JsonNet, but I am unclear on how to to use it with Moment and pass it back and forth across web api/ajax.
I need to know some way to send a value from moment, into the web api preferrably as a ZonedDateTime in the client's time zone. I can then convert it to UTC for persistance in the DB.
If that's what you want, then:
In your moment.js code, use .format()
instead of .toISOString()
, which will still give you an ISO8601 string, but will include the local offset instead of setting it to UTC.
In your ASP.Net code, define your values as a DateTimeOffset
(or a noda OffsetDateTime
) rather than a DateTime
.
However, I don't think that's really what you want. When it comes to dates and times, context is super important. Here, you said you were picking a date from a date picker. When you do that - what time is being chosen by the user? In most cases, they aren't choosing a time - they're just picking a date. But since the JavaScript Date
object is really a "date + time" object, it assigns midnight as a default time. Moment is no better in this regard.
Really, converting to UTC doesn't make logical sense when you are just talking about a calendar date. The string value you probably should be sending across the wire should just be a whole date, as in "2015-03-14"
. My guess is that is what you are starting with anyway. If not, then do moment.utc(yourvalue).format("YYYY-MM-DD")
to get it. (Using UTC here is just a way to avoid local time zone issues, like midnight not existing in Brazil on the spring-forward day.)
This corresponds to the NodaTime LocalDate
type in your .NET code. If you weren't using Noda Time, you would define the type as a DateTime
and just ignore the time portion. In your database, if there's a date-only type available, then use it. For example, SQL Server has a date
type.
I'd also encourage you to watch my Pluralsight course, Date and Time Fundamentals - which covers many of these issues.
Regarding using NodaTime.Serialization.JsonNet
in WebAPI (so you can use LocalDate
directly), in your WebApiConfig.cs
file, wire it up like so:
config.Formatters.JsonFormatter.SerializerSettings
.ConfigureForNodaTime(DateTimeZoneProviders.Tzdb);
Then it should just work.