Using timezones with moment.js fromNow() or from()

12,883

Solution 1

Ideally, you would want to pass a UTC timestamp from your server to the client. That doesn't mean you have to switch your whole server over to UTC, it just means that you would convert from the time in your database to UTC on the server before sending it over the web. Sure, it would be even better if you actually stored times in UTC, but you said you aren't in a position to make that sort of change right now. But let's just work off the assumption that you can't change anything at all on the server.

We'll also assume that your server is fixed to the UTC-07:00 offset. In real life, this would only be true for places like Arizona that don't follow daylight saving time. So if you are in Los Angeles and are in Pacific Time, then some of your data is based on UTC-07:00, but some of it is based on UTC-08:00. That requires a lot more work if you want to do it in JavaScript.

Let's also assume that the input is already a string in ISO8601 format. (If it's not, then let me know and I will adjust this code.)

var s = "2013-09-11 18:00:00";  // from action.timeStamp

var actionTime = moment(s + "-07:00", "YYYY-MM-DD HH:mm:ssZ");

var timeAgo = actionTime.fromNow();

The reason your other code didn't work is because in the first line, you are affected by the time zone of the browser. The zone setter in the second line just changes the zone for formatting, not changing the actual moment in time.

Also, when you dump a moment to the console for debugging, make sure you format it for output. Otherwise you are just looking at its internal property values, which may or may not make sense directly.

Solution 2

I have solved it in a different way, maybe this option was not possible back when the question was asked, but might be easier now.

I used moment-timezone.js (which requires moment.js 2.6.0+).

I set the default timezone to my server's timezone like this:

moment.tz.setDefault("America/New_York"); // "America/New_York" in my case

and then just use it normally. fromNow() will use the timezone in the client to calculate the time that has passed since that moment.

moment(myDatetime).fromNow();

Solution 3

i had the same issue and used the above comments to modify my code. I did the following to get it resolved:

  transform(value: string) {
    var time = moment(value).utc();
    return moment(time, "YYYYMMDD").fromNow();
  }

I was missing the .utc() to convert it before I applied the .fromNow()

Things to note this is being used within a Pipe for Ionic 3 and the above code is from the pipe logic.

Share:
12,883

Related videos on Youtube

gregory boero.teyssier
Author by

gregory boero.teyssier

https://ali.actor

Updated on June 13, 2022

Comments

  • gregory boero.teyssier
    gregory boero.teyssier almost 2 years

    I want to show users how long has been elapsed since they performed an action.

    The date+time of the action happening is stored on the server, in the server's timezone. That's what's causing the trouble, since if the user's computer's timezone is 12 hours ahead of the server's timezone, then if the user adds something right now, moment.js will show '12 hours ago' as the output of fromNow() rather than just now.

    To try to solve this, I'm trying the following method:

    var actionTime = moment( action.timeStamp);//time of when user performed action 
    var serverTime = moment().zone('-07:00'); //current server time
    
    console.debug( serverTime);//outputs Wed Sep 11 2013 15:19:51 GMT-0700
    
    var timeAgo = serverTime.from( actionTime);
    

    But despite of all this, timeAgo still shows the difference between the client's timezone and the server's timezone (i.e showing '12 hours ago' instead of 'now');

    Anyone know how to fix this or what I'm doing wrong?

  • gregory boero.teyssier
    gregory boero.teyssier over 10 years
    Thanks Matt, I had figured i'd have to add/subtract the hours manually, but I didn't know exactly how to do it. One question, say if the server's timezone is GMT -7 (mountain), and the user is in GMT +2, then in order to show the correct 'fromNow' to user, I'd have to first get the difference between server and user timezones (+2 -7 = -5), and subtract -5 hrs from the actionTime, correct? Is there a way to change this to subtract based on that?
  • Matt Johnson-Pint
    Matt Johnson-Pint over 10 years
    You don't have to consider the client's time zone. The only thing your asking the client for is "now" which is based on UTC with either moment or Date.
  • Matt Johnson-Pint
    Matt Johnson-Pint over 10 years
    When you pass the offset in to the moment constructor, you're saying "this moment is in this offset". But from there on out its a specific moment in time. If you add or subtract, you'll be talking about a different moment in time.
  • gregory boero.teyssier
    gregory boero.teyssier over 10 years
    I see.. but are you sure? E.g, if I simply do moment(), will I get the current date on the client's computer, or will I get the date according to UTC?
  • Matt Johnson-Pint
    Matt Johnson-Pint over 10 years
    moment() is just like new Date(). It internally tracks UTC, while outputting and parsing at local time. So the answer is both, depending on how you look at it.
  • gregory boero.teyssier
    gregory boero.teyssier over 10 years
    It doesn't seem to be working. The problem is, I have actionTime in a MySQL datetime format (YYYY-MM-DD HH:MM:SS). To parse it, I'm using this format: YYYY-MM-DD HH:mm:ss. How would I change your code above to make it work with this format?
  • gregory boero.teyssier
    gregory boero.teyssier over 10 years
    thanks a lot. although its still over my head how and why this works, it works and that's what matters. thanks again!
  • Rohit Parte
    Rohit Parte over 4 years
    This worked perfectly! for tz we can user moment.tz("Asia/Kolkata").format("Z")

Related