.zone() always returns the local zone #611

Closed
mj1856 opened this Issue Feb 6, 2013 · 19 comments

Comments

Projects
None yet
9 participants
Owner

mj1856 commented Feb 6, 2013

If I create a moment such as:

var m = moment("2013-01-01T00:00:00-04:00");

And then look at the zone:

var z = m.zone();

I would expect to always get back -240, because I created it with the specific -4:00 offset.

Instead, I always get back 420. I am in UTC-7 (Arizona), so this is coming from my local clock.

Even that seems wrong though, because I would expect -420. This seems to be a direct passthrough to getTimezoneOffset(), which also exhibits this behavior. I expect more from moment.js.

It seems that as soon as you create a moment with an offset, that offset is applied and then lost. Is that correct?

Owner

timrwood commented Feb 6, 2013

Yeah, because javascript only has access to the local timezone and the UTC timezone, a moment is only in one of those two states.

Adding functionality for switching to any timezone is much more complicated. You have to include all the Olson timezone info in order to handle DST correctly. Work has been started on a plugin that handles this over at timrwood/moment-timezone, but it is not ready for production yet.

Owner

mj1856 commented Feb 6, 2013

I get that. I use timezonejs if I need to work with Olson timezones in javascript. I prefer to do it server side though.

I suggest that .zone() is misnamed, it should be .offset().

I was just thinking that if I give you an offset, you should retain it in a local variable, so you can give it back to me when requested. If you wanted, you could also use it to calculate the time at that offset and return the time at that offset in different property.

Owner

timrwood commented Feb 7, 2013

The offset is sort of useless though. For PST, the offset could be 8 hours or 7 hours depending on whether or not it is Daylight Saving Time. What type of thing were you hoping to do with the offset?

With some of the latest changes, we do store the parsed offset hours and minutes, so you could get those values this way. http://jsfiddle.net/NjCtA/

Owner

mj1856 commented Feb 7, 2013

It's not useless at all. It's quite valuable actually. Coming from a .Net perspective, it lines up perfectly with DateTimeOffset class. You can ready my take on it's value here.

The short of it is, while you can't determine the zone from the offset, you can gather two pieces of important data: 1) The exact moment something happened (by applying the offset to determine the UTC time), and 2) The locally relevant time according to the person who recorded it. If you just apply the offset and throw it out, you might as well have just been handed a UTC time without an offset at all.

To get more specific - I may be looking at an event recorded in another part of the world. For example, an employee of a global company clocks in at 8:00 AM in Florida. It happens to be EST, so I record 8:00-0500. If it was EDT, I would record 8:00-0400. A manager of the company in California wants to look at that time. They need to know BOTH the fact that it corresponds to 5:00-0800 (their local time), and that it was recorded at 8:00 AM relative to that person. Without the offset, I could only do the first part.

There are many other scenarios. It's good to see that I can pull out the _tzh and _tzm values. I'll have to play with these to see if they are accurate. I assume they are. Thanks.

Owner

timrwood commented Feb 7, 2013

Ok, I see what you mean.

Moment.js is intended to deal with exact moments in time, regardless of what string representation was used to create the moment. I'm not too familiar with .Net, but I imagine it's more like the DateTime class than the DateTimeOffset class.

I can see the value in knowing both the timezone and the exact moment in time something happened, but I feel like the original offset is best left out of the domain of moment.js and in application specific logic.

Owner

mj1856 commented Feb 7, 2013

That's ok, I understand that most JS libraries aren't targeting .Net developers. But we use them all the same.

DateTime in .Net doesn't actually represent a single moment in time very well. It's better used for local time, or an ambiguous time. It can be used for UTC time, but it's hard to enforce it. DateTimeOffset is better because it unambiguously represents a single moment in time. That's why it lines up better with momentjs.

Forget about .Net for a minute and just consider the ISO8601 standard. It allows for the offset, which I assume is why you are accepting them. Correct me if I am wrong, but I think you are applying the offset and the moment just tracks the UTC time, right? All you need to complete the loop is some way to get the offset back. So if I can safely use _tzh and _tzm, then that's good enough. Are these safe to use?

You might consider two additions to moment that would make life easier for me (and hopefully others):

  1. Add a new .offset() method that combines the _tzh and _tzm into a single value. I don't care if it's a string of [-]HHMM, or if it's an integer number of total minutes. Either would work.
  2. Add an optional parameter called offset to the .format() method. Whatever offset is provided would be applied before outputting the formatted string. I could provide the value obtained from .offset(), or I could provide a different value determined by my application logic.

Neither of these would be breaking changes for you, and would open up a lot more usability - even outside of .Net.

Thanks for your consideration, and your excellent work. I already recommend momentJS whenever I can. This would make it that much better.

obie commented Feb 8, 2013

I think I'm having the same issue as @mj1856 with moment.js on my own project. I supply a source string to moment that is carefully crafted with the offset that I want to end up displaying to the user. (My app absolutely needs to show times that are not necessarily in the same timezone as the user's browser timezone offset setting.)

No matter how I try, I can't get moment to show me the desired time -- I am limited (perhaps by design, according to this thread) to only showing the local time or UTC. Both options are unacceptable for my current application.

Going to try to do a workaround and/or supply a patch, but in the meantime wanted to chime in to let you know that this is a big obstacle.

b3nj4m commented Feb 19, 2013

I'm having the same issue as well, and adding a zone() setter would make my life a lot easier.

Owner

timrwood commented Feb 20, 2013

I've started work on this on the feature/zone-setter branch.

It's mostly working, but I need to add a bunch more tests as noted in #616.

In case others are here looking for the same thing:
We just needed to be able to use .format() and print the time in the zone it was given in an ISO 8601 string.
As a temporary work around we went for this:

function momentInZone(stamp) {
    return moment.utc(stamp.replace(/Z|[\+\-]\d\d:\d\d/, ''));
}

So you can:

>>> momentInZone('2013-02-14T19:52:47+05:00'').format('hh:mma');
"07:52pm"
Owner

timrwood commented Mar 19, 2013

@dukedave, once the zone setter lands, you will be able to use a string to set the offset as well. timrwood#671 (comment)

var input = "2013-03-07T07:00:00-08:00";
moment(input).zone(input).format(); // 2013-03-07T07:00:00-08:00
Owner

mj1856 commented Mar 19, 2013

@timrwood - I just want to say again how much I appreciate your efforts with moment.js, and this issue in particular. You continue to astound me with the level of thought and detail you put into this library. THANK YOU!

Owner

timrwood commented Mar 19, 2013

You're welcome @mj1856!

ejain commented Mar 20, 2013

I also need to show timestamps with the original time zone offset preserved; glad to see that a solution is near!

luksch commented Mar 23, 2013

yes, keeping the zone would help also with my application. Thanks for working on that.

@dukedave's suggestion meets my need as well.

I think it would be useful to implement an "ignore timezone" option, similar to that of jQuery fullcalendar: http://arshaw.com/fullcalendar/docs/event_data/ignoreTimezone/. Sometimes I just want to display the date in a the timezone it was given in and I don't care about performing date/time arithmetic. In that case I need to explicitly ignore the timezone offset in order for the resultant JavaScript Date object to work reliably.

Owner

mj1856 commented Apr 23, 2013

Hi Tim, just checking in. Any movement on this issue?

There are some other things that could open up when this is resolved, like a solution for these posts on StackOverflow:
http://stackoverflow.com/q/16147253/634824
http://stackoverflow.com/q/16177531/634824

I've been doing some talks on datetime and Moment.js is highlighted in my presentation. You can check out the slides and code samples here: http://sdrv.ms/Z6lX1Y
The moment.js stuff is in Demo2 in the code samples, and I'm just comparing it to the native Date object for now. It would be nice to show off this feature when it is ready.

Thanks
-Matt

dr0bz commented Apr 24, 2013

Hi all,

I'm facing the same problem. We have to show flight times, regardless the time zone where the user sits. Like shown here http://stackoverflow.com/q/16177531/634824 php is working other way. I've a similar solution like @dukedave

function momentRtz(datetime) {
    return moment(datetime, "YYYY-MM-DD HH:mm");
}

momentRtz('2013-06-10T10:40:00.000+04:00').format('D.M.YYYY h:mm:ss');

Would result in:
"10.6.2013 10:40:00"

@timrwood are there any caveats to make using these solutions?

Regards

Owner

timrwood commented May 12, 2013

This has been merged into the develop branch and will go out in the 2.1.0 release.

#671

@timrwood timrwood closed this May 12, 2013

@mj1856 mj1856 referenced this issue in runspired/Date.toString.js Jan 28, 2016

Open

Seems rather limited #1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment