I have an admin panel where items entered will have a time_posted and an expiration time. These times use a timestamp (time()) upon being entered.
I want the entering of the expiration time to use a fancy date/time selector, but the selector uses JavaScript client time rather than server time.
A way to fix this would be to save the timezone a user is in, then use that as offset for the data entered, but it's something that has to be 100% correct.
Is there any 'proper' way to approach this? I saw that some PHP functions do use the timezone setting but others do not, for instance the actual time() function doesn't and even if I create a DateTime object, output the current timestamp, change the timezone and output the timestamp again it just returns the same timestamp twice.
Any pointers would be lovely
I assume that the actual timestamp value would still be correct (independent) regardless of what settings/timezone the end user has.
Problems may apper when/if you want to generate date strings server-side and thus return times with offsets.
Either
1. dont generate date strings server side, if you are not sure about the timezone offsets or
2. warn users and make sure that they specify their timezone and then force that timezone whenever you output date string from timestamps
A few things:
You probably don't need to identify the user's time zone for the scenario you describe, but if you did then please recognize that a time zone and an offset are two different things. See "time zone != offset" in the timezone tag wiki. If you actually think you need the user's time zone (such as "America/Los_Angeles"), then refer to this answer.
If you want the entered date to be relative to the client's local time zone, then you need to use either a Date object, or a library like moment.js in JavaScript. Use the individual date/time components from the date picker to get either a unix timestamp, or an ISO8601 formatted date/time string at UTC. For example, "2016-09-02T01:23:45Z"
If you want the entered date to be relative to some other time zone, then you need to transmit the actual values the client entered without modification. The best way is in ISO8601 format without offset. For example, "2016-09-02T08:00:00". On the server side, parse that value and apply whatever time zone is applicable.
If you are only selecting a date, and not a time, then you should really think about whether any time is applicable or not. Is 00:00 really applicable? Or should it be 24:00 or 23:59:59.999? If you don't care about the user's time zone, then really you shouldn't assign any time value at all. Just pass the date. For example: "2016-09-02"
Don't rely on the server's time zone setting to be anything in particular. Though PHP has functionality for setting a "default" time zone, you should try to avoid using it. It is much safer to be explicit about time zones on a per-operation basis. Use the DateTime class in PHP, not time().
Be sure to read Daylight saving time and time zone best practices, and to search thoroughly for other questions on StackOverflow, as much of this has been answered already in various other questions.
Related
Im currently working in an application where users can set their own time zones.
In this case the user's time zone is set to
{
"value": "Africa/Accra",
"label": "Africa/Accra"
}
We then hit an api for times an action has been performed, all the times come back as GMT.
2020-04-02 16:24
Is there a way to tell moment.js that the initial 2020-04-02 16:24 value is GMT?
I've been reading around and it seems like i need to manually set the offset depending on what the users timezone is? But wasnt sure if this was the correct answer.
For named timezones instead of numeric values you can use moment-timezone and the .tz() function.
You should convert the date-time string 2020-04-02 16:24 to a moment object first.
moment('2020-04-02 16:24').tz('Africa/Accra').format('YYYY-MM-DD HH:mm')
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 need to write a web application that show events of people in different locale. I almost finished it, but there're 2 problems with date:
using date javascript object, the date depends on user computer settings and it's not reliable
if there's an event in a place with dfferent timezone respect user current position, i have to print it inside (). Is it possible in javascript to build a date object with a given timezone and daylight settings?
I also find some workaround, such as jsdate and date webservices, but they don't overcome the problem of having a javascript object with the correct timezone and daylight settings (for date operation such as adding days and so on).
A couple of things to keep in mind.
Store all event datetimes in UTC time
Yes, there is no getting around this.
Find out all the timezones...
...of all the users in the system. You can use the following detection script: http://site.pageloom.com/automatic-timezone-detection-with-javascript. It will hand you a timezone key such as for example "America/Phoenix".
In your case you need to store the timezone together with the event, since a user may switch timezone - but the event will always have happened in a specific one. (argh)
Choose your display mechanism
If you want to localize your event dates with Javascript, there is a nifty library for that too (which can use the keys supplied with the previous script). Here: https://github.com/mde/timezone-js.
with that library you can for example do this:
var dt = new timezoneJS.Date(UTC_TIMESTAMP, 'America/New_York');
or
var dt = new timezoneJS.Date(2006, 9, 29, 1, 59, 'America/Los_Angeles');
where UTC_TIMESTAMP for example could be 1193855400000. And America/New_Yorkis the timezone you have detected when the event took place.
The dt object that you get from this will behave as a normal JavaScript Date object. But will automatically "correct" itself to the timezone you have specified (including DST).
If you want to, you can do all the corrections in the backend - before you serve the page. Since I don't know what programming language you are using there, I cannot give you any immediate tips. But basically it follows the same logic, if you know the timezone, and the UTC datetime -> you can localize the datetime. All programming languages have libraries for that.
You're missing the point of a Date object. It represents a particular point in time. As I speak, it is 1308150623182 all over the world. Timezone only comes into play when you want to display the time to the user. An operation like "adding a day" does not involve the time zone at all.
One possibility might be to use UTC date and time for everything. That way, there is nothing to convert.
Another is to have your server provide the time and date. Then you don't have to depend on the user to have it set correctly, and you don't have to worry about where your user's timezone is.
Use getUTCDate(), getUTCHours(), ... instead of getDate(), getHours(),...
getTimetoneOffset() could be useful, too.
I have set a deadline in UTC, as shown below, and I'm wondering what exactly the toLocaleString() method will do to it on user's local machines. For instance, will it account for daylight savings if they are in a timezone that recognizes it? Or will I need to insert additional code that checks where the user is, and then fixes the displayed time?
http://javascript.about.com/library/bldst.htm
var deadline = new Date('5/1/2013 ' + "16:15" + ' UTC');
alert(deadline.toLocaleString());
In general, the answer is yes. JavaScript will represent the UTC value at the appropriate local time based on the time zone settings of the computer it is running on. This includes adjustment for DST. However, as others have pointed out, the details are implementation specific.
If you want a consistent output, I would use a library to format your dates instead of relying on the default implementation. The best library (IMHO) for this is moment.js. The live examples on their main page will give you an idea of what it can do.
UPDATE
If you are passing UTC values that you want converted to the correct local time, and that time falls into a period where the time zone rules are different than the current one - then the results will be invalid. This is crazy, but true - and by design in the ECMA spec. Read - JavaScript Time Zone is wrong for past Daylight Saving Time transition rules
We don't know what exactly the toLocaleString method does (§15.9.5.5):
This function returns a String value. The contents of the String are
implementation-dependent, but are intended to represent the Date in
the current time zone in a convenient, human-readable form that
corresponds to the conventions of the host environment’s current
locale.
But yes, most implementations will consider DST if it is active in the current local timezone. For your example I'm getting "Mittwoch, 1. Mai 2013 18:15:00" - CEST.
Will I need to insert additional code that checks where the user is, and then fixes the displayed time?
I think you can trust toLocaleString - the browser should respect the user's settings. If you want to do it manually, check out timezone.js.
As you use "UTC" the date itself will be UTC format, but the toLocaleString() takes client's locale into account, which means it'll return the date in string updated with all and every changes typical to client's regional and locale settings (DST, date/time format, etc).As JS documentation describes this: "The toLocaleString() method converts a Date object to a string, using locale settings.".If you want to avoid this, use the toUTCString() method instead.I'd also recommend reading the accepted solution for the question Javascript dates: what is the best way to deal with Daylight Savings Time? to avoid (at least, to try to avoid :) future issues related to JS, browsers and locales.Hope this helps!