Can you tell moment.js what time zone a value is in? - javascript

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')

Related

Moment and new Date() not displaying local time

I want to display the local date of the user, but nothing is working for me. It always returns the UTC time.
I have tried:
This returns UTC - also in here offset comes as zero.
let visitDate = moment.utc().format();
let offset = moment().utcOffset();
let visitDate1 = moment.utc(visitDate).utcOffset(offset)
This returns UTC
let visitDate = new Date()
let visitDate1 = moment(visitDate).local().format('MM-DD-YYYY hh:mm:ss');
This returns UTC
let visitDate = new Date()
let visitDate1 = visitDate.toLocaleDateString()
I have tried several methods, but it doesn't matter what I do, I always get UTC time. If I try on localhost then it displays the correct time, but once I host the page it displays UTC.
How can I transform to local?
moment().local() uses the timezone of the local machine, that's why it works in localhost
if you know it, I would specify the timezone:
moment.tz("America/Los_Angeles").format()
There seem to be several possible points of failure. I'll list the ones I think of below, and you can assess whether they're relevant to your setup.
1) The code that manipulates the date is executed on the server, not locally
Most of our Javascript code is written to execute in the user's browser, so that's the default assumption. If that assumption is wrong in this case, and the code is being executed on the server, then "local" means "on the server." Your server should be running with UTC time, which could produce the results you're seeing.
2) The user is running a browser set to UTC
If the browser you're using for testing is set to consider UTC as local time, it'd produce the results you're seeing. Since you're probably using the same machine for localhost and for testing, it's an unlikely source of the problem...but worth noting nonetheless.
3) Changing how the date is displayed does not change how the date is stored
Many of the tools we have for setting/changing the time zone affect how the date is displayed. However, Date objects in Javascript are stored using Unix Time (in milliseconds), which is UTC. When you create a Date object--even with a time zone specified--the behind-the-scenes representation will still be an integer (representing a number of milliseconds) and based on UTC. If you're checking the stored value rather than the displayed value, when you're testing, then there's a good chance you'll always see UTC. However, the work you're doing with the moment library should have the date formatted correctly. If you're checking the moment object, you should be seeing the time zone you expect to see.
If none of these three possible failure points applies to your context, then perhaps they spark an idea for you. (The third one, especially, feels like it might be on the right track even if it's not what's happening in your case.)

PHP dates and timezones

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.

Passing a time zone into a web api call from moment with nodatime

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?

Rails Time Zone Mapping for browser detected Timezones

I am working on a application, which detects the browser's time zone and asks the user's to set the time zone to the browser detected values.
So, I have populated, a select drop down which list all the All the keys present in ActiveSupport::TimeZone::MAPPING.
Now, I have a user whose timezone is (GMT-08:00) Pacific/Pitcairn.
There are many such values which are not present in ActiveSupport::TimeZone.
How should I handle such values. I've checked many js files which claim to send in Rails Supported Values, but none of them seem to work.
If I set my timezone to UTC-08:00 in Windows machine then my javascript plugin detects a time zone and sends in a value of America/Los Angeles.
We have a check box to not allow DST Timings on Windows machine.
So in this case with UTC-08:00 as time zone and DST box unchecked we're getting a value Pacific/Pitcairn.
So to go with matching before / for two different values of America/Los Angeles and Pacific/Pitcairn it's not possible.
Set the value by UTC offset, by ignoring name also wouldn't help. We have two seperate value with (UTC-08:00) Pacific Time (US & Canada) and (UTC-08:00) for Tijuana. So how do I decide which value to set.
showTimeZoneInfo: function(member_time_zone, timeZoneInfo, invertTZHash){
var tzValue = jQuery().get_timezone({'defaultvalue' : 'Etc/UTC'});
var railsOffset = TimeZoneFlash.extractOffset(timeZoneInfo[member_time_zone]);
var browserOffset = TimeZoneUtils.zoneWithoutDST();
if ( railsOffset != browserOffset) {
jQuery(".time_zone_text").text(browserOffset + " " + invertTZHash[tzValue]);
jQuery('.cjs_display_time_zone').removeClass('hide');
}
}
Now we have a case where invertTZHash doesn't contain Pacific/Pitcairn. And It returns a undefined value.
I am working on building a alert box for users who are in a different time zone compared to their browser's timezone. Even Intl.DateTimeFormat().resolved.timeZone wouldn't help because most of my traffic is from IE and FF browsers
Time Zone != Offset. See the timezone tag wiki. So just swapping it for another time zone that happens to be on UTC-8 is not a good idea. You will pick up all the DST rules for that zone, which don't necessarily apply.
Even Pacific/Pitcairn isn't purely UTC-8 if you deal with past dates. It moved from UTC-08:30 to UTC-08:00 in 1998 - you can see that here.
This is one of the reasons I'm not happy with ActiveSupport::TimeZone. They make it quite clear in their docs that it is limited:
Limit the set of zones provided by TZInfo to a meaningful subset of 146 zones.
This seems rather arbitrary. Who is it that determines what is "meaningful" and what isn't? If it wasn't meaningful, it wouldn't have been in the database to begin with!
You should look at using the tzinfo gem, which is what ActiveSupport based theirs on anyway. It has the full TZDB with all of its time zone data instead of a limited subset.
Regarding time zone detection, I'm not sure what JavaScript you are using to "detect" the time zone. You show calling some functions get_timezone and TimeZoneFlash.extractOffset that must be custom to your app or provided by external libraries. Please elaborate on exactly what you're using.
The only timezone detection library for JavaScript that I am aware of is jsTimeZoneDetect - which makes it quite clear that it just takes an educated guess. Unless you are depending on the new internationalization APIs in the very newest Chrome an Opera (which I don't think you are), then there's no guaranteed way to detect a time zone without user involvement. See also this answer.
We have a check box to not allow DST Timings on Windows machine. So in this case with UTC-08:00 as time zone and DST box unchecked we're getting a value Pacific/Pitcairn.
Yes, that is an awful reality. IMHO - that should never be unchecked. It would be better if the checkbox wasn't there. Whether DST applies or not is handled by the time zone, so there's no good reason to disable it. I'm sure that they left it there specifically for cases like Pitcairn, because there isn't a Windows time zone entry for them specifically.
Update
From your comments:
I already have a drop-down for this. I am working on building a alert box for users who are in a different time zone compared to their browser's timezone.
Take the current offset from JavaScript using new Date().getTimezoneOffset(). (It's in minutes, and the sign is reversed, so you may need some simple math.) Compare it to the current offset for the selected time zone in your drop down. (You should be able to get that from your server-side code.)
If they don't match, then alert your user. No need for jsTimeZoneDetect at all for this.
First Option: Set by UTC Offset
Get the UTC Offset
Search for UTC offset in your ruby array.
Set value by UTC offset, ignore name. Choose the first timezone which has the correct UTC offset.
Some code for this:
timezone = ActiveSupport::TimeZone.all.select { |tz| tz.utc_offset == my_offset }.first
Second Option: Add a new Timezone to the list
If you know the UTC offset, add a new TimeZone to the list. See Docs.
Hope that helps!

Javascript date object in different locale and timezone

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.

Categories