I am having an issues passing a JSON containing DateTime to asp.net code-behind (c#).
If the client browser is in the same timezone as the server I have no issue, but if they are in different timezones my time is getting modified by the offset value of the two timezones.
But all my datetimes need to be the date with a time of 00:00, regardless of the time zone this datetime comes from.
Thanks
If you want the client and the server to share the same relative time like that, have the client pass back a string describing the date in some easy-to-parse format. Then your server code can parse that string as if it's local time.
Alternatively you could have everything work in UTC time.
You have to be careful with things like this of course. For example, if the client is expecting to schedule some activity to take place at the server, then the server's midnight may not be the same as the midnight at the client. The client therefore needs to make it clear that the time setting is for the server's time zone.
Related
I've got a Go app and I store all datetimes as UTC:
dateTime, err := time.Parse("2006-01-02T15:04:05.000Z", myDateTime)
This becomes something like: 2022-09-29T19:40:36.150Z.
Now I want to show this datetime client side (on a website), but showing the user the time in their timezone.
Since it's all UTC I could have the user pick their timezone from a list, like this one https://gist.github.com/valo/c07f8db33d223f57a4cc9c670e1b6050.
Then it's just a matter of adding/subtracting some time from the UTC and showing it.
But the problem is with daylight savings time, the client side timezone would have to change when it's summer, and change again when it's winter.
How are people doing this?
Usually, this happens on the client side. Information about the client's timezone is stored on the browser and is available to you if you need it. However, there are functions that sort this out automatically like toLocaleDateString.
Step 1.
Parse the time string 2022-09-29T19:40:36.150Z to a Date object in javascript
Step 2.
Use toLocaleDateString on the date. This will display the Date in the client's timezone setting stored in the browser
MDN docs for toLocaleDateString()
I'm searching for a way to get client's timezone offset in ExpressJS (with req object, for example, would be really great).
If you control the client, you can do this with client-side JavaScript.
If you don't (e.g. you're building a server-side component like an API), then you can't pull it out of the HTTP request (unless you're using sessions, but even that's not necessarily reliable).
On the upside, if it's only server-side, you shouldn't worry about it either: set all your date objects as UTC or a Unix timestamp and leave it to the client developer to handle timezones.
As others have mentioned, getting the client-side browser/OS timezone offset is not available via HTTP, so you need to send this data from the client side.
In my case I have an app that requires login...so I can store a user's preferences. The default is to use browser timezone, but the user can also configure a specific timezone to use all the time instead which is stored in their user profile (e.g. America/Dallas or Europe/Amsterdam).
I don't trust browser time to be correct. The user may have also screwed up their OS timezone setting...so timezone offset may also not be correct. However most modern OSes set timezone automatically based on Geo-IP implied location...so for many users the convenience of being able to travel around the world and login to the app and see date/time in whatever local timezone they happen to be in is worth the effort for the user experience. Users that always want to see a specific timezone can configure that and we will use that preference instead.
The way I do this is the following... on the login form add a hidden field and set the value with javascript. When the user logs in, store this timezone offset in the session. If the user hasn't set a preferred timezone, then we use this offset when rendering date/time. This means that if you have long sessions and a user can travel around between countries...they will still show the old timezone offset until the next logout/login. You can of course get this data more frequently or even on every request if you want...but for my purposes getting this on login is enough. My sessions are expired on IP address change anyway...so yeah. Of course if their session crosses a daylight savings switch then the offset won't be accurate until the next login (assuming their OS/browser TZ is correct in the first place).
Client Side
<input type="hidden" name="tzOffset" id="tzOffset">
<!-- ... -->
<script>
var tzOffset = new Date().getTimezoneOffset(),
tzInput = document.getElementById('tzOffset');
tzInput.value = tzOffset*(-1);
</script>
Note that I multiple it by -1 because I am going to use moment.js for formatting on the express end and the offset is backwards (utc offset from local vs local offset from utc). You could also do this on the server end. You should probably validate this number as well before using it...just minimal example code here.
Server Side
Then on the server side (express) if there is a successful login, I stick that tzOffset value in the session.
Then when formatting dates in express with moment-timezone I can do something like the following. This function is a "formatter" which I can expose to pug/views and then format any random date object with the right timezone/formats for the user.
function formatDateTimeForUser (date) {
var userTZ, // user specified TZ like Europe/Berlin
userTZoffset, // tzOffset we got from login form
userDateFormat, // user specified date format (or default)
userTimeFormat; // user specified time format (or default)
if (userTZ)
return moment(date).tz(userTZ).format(userDateFormat+' '+userTimeFormat+' zz');
else
return moment(date).utcOffset(userTZoffset).format(userDateFormat+' '+userTimeFormat+' ZZ');
}
The ZZ format is for showing timezone in numeric offset format (relevant when we use a fixed numeric offset from client.
The zz format is for showing timezone in character format (e.g. PDT, PST, EST, etc) which is relevant when we have a timezone like Europe/Berlin instead of a fixed numerical offset.
Another approach
Push raw dates to client and do client-side formatting. Downside is less control and consistency and more js to push to the browser. moment will also run client side if you like.
I just configure my formatters server-side based on user locale and user prefs and then expose those formatters for use in my pug templates in express. So far it works pretty well for me.
Funny Story
I had a co-worker that manually set the wrong timezone on their computer and so the time was wrong. Instead of fixing the timezone they disabled network time and manually set the time to be the "correct" time.
Then they got grumpy when everyone was showing up to meetings they scheduled an hour late.
So yeah...no guarantees the client-side time or timezone offset will be correct.
The reality is, even if you have got the timezone offset, it doesn't mean you have the the correct time on client side, considering some area have "daylight saving time".
But, you could "guess" which timezone the user is in, considering the following data:
req.get('Accept-Language'), for which country is the user may live in now;
req.ip, to search in a database and find out the approximate location;
client-side (new Date).getTimezoneOffset(), for timezone offset;
Finally, through the calculation of the above result, your guess should be almost there. The timezone should be stored in string like 'America/New_York' but not a timezone offset number.
http://momentjs.com/timezone/ should be a good tool to deal with timezone.
After you save the "almost correct" timezone, don't forget to leave a place where user can change it.
Some people like using the library momentJS for anything dealing with time, but I believe the Date object in Javascript suffices what you are looking for and does not require a library. The getTimezoneOffset is what you will need. I hope this helps! Let me know if you have other questions!
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.
I would start by sending all dates and times to the server as UTC times. If you store UTC times only then you should be able to show the correct time that something is scheduled on the client side.
When you create your moment on the client side, do you run it out .toDate() first before sending it to the server side? What code are you running on the server side? Is it a .Net WebApi?
I have an ajax call, which returns datetime. Javascript displays it using client timezone. I not need in any client timezone, I want to show datetime the same as server return. Is it possible?
I get date via:
var d = eval('new' + date.replace(/\//g, ' '));
First off, there's no reason to use eval here (or almost anywhere), and generally lots of reasons not to.
JavaScript has only "local" time (the timezone of the client) and UTC (universal coordinated time, effectively the same as GMT). So your best bet normally is to have the server send you the time in UTC. But in your case, since you want to display the date in the server's timezone, it doesn't really matter whether JavaScript thinks the date is in local time or server time, and it's fine to send it in the server's timezone.
Note that when parsing date strings, JavaScript only recently (as of ECMAScript5) got a standard format for date strings, which is a simplified version of ISO-8601. Details here. Note that some older browsers will not yet support that format.
It's impossible to offer much more guidance without an example of what you're trying to parse.
Diodeus' suggestion also seems to me to make a lot of sense: If you want the date to be displayed in the server's timezone and format, just display the string you're given without interpreting it (again, subject to what the string looks like; I can't immediately come up with a reasonable format that would work with your posted code).
What is the best approach for dealing with DST values when your web service accepts requests from different timezones than that of your server?
My webservice accepts date strings using the ISO8601 standard (2012-02-21T05:00:00.000-05:00)
I want to account for DST but don't want the overhead of maintaining or connecting to a database to get the DST for each request which comes in from a different timezone to my server.
One approach im considering is using the servers default DST settings and then for each request that comes in convert it to the same timezone as my server is in. Then when the processing is done , convert the string back to the timezone of the client and return. The conversion of the response data could be done on the server or the client.
Any suggestions?
You could also take a look at the XDate project for handling date objects in Javascript. It's quite similar to JodaTime (in Java). Very easy to use and semantic.
XDate project
Here's what I would do. Before you submit your data/time, parse the strings into a JavaScript Date object. Then call getTime() and submit that value. getTime() returns the number of milliseconds since the UTC epoch, so in effect, it normalizes your times. Then when you return data to the user, pass in your UTC millisecond value to the constructor of a Date object and display the time as you would. By default, it'll display in the user's timezone.