Question

Previous answers on here pointed me to moment.js for javascript date handling and I am really happy to find it. I can parse and manipulate quite happily.

The users on my website look at info relating to diverse physical sites/locations, and I want to show associated datetimes in the time specific to that location, not the users location.

Each physical site has a timezone attribute string like "Europe/London" or "Europe/Amsterdam"

My datetimes are all stored and delivered from the DB in UTC.

Is there a clever simple way I can render my moment.js object in any specified timezone?

Était-ce utile?

La solution

Theoretically, you could do something like this.

moment.fn.formatInZone = function(format, offset) {
    return this.clone().utc().add('hours', offset).format(format);
}

moment().formatInZone('HH:mm:ss', 7);
moment().formatInZone('HH:mm:ss', -7);

However, this requires that you know the correct offset, so it won't take into consideration daylight saving time.

Autres conseils

If you want to display dates in ANOTHER timezone than the user is actually in, then you need to start looking into stuff like https://bitbucket.org/pellepim/jstimezonedetect (if you need to detect which timezone a user is in) and https://github.com/mde/timezone-js if you need to localize dates between zones.

jsTimezoneDetect which I linked to above will help you provide a shortlist of relevant timezones.

That you have your datetimes stored in UTC will make it pretty damn easy for you thanks to mde/timezone-js.

In node.js this is actually pretty simple using node-time (https://github.com/TooTallNate/node-time). Override the global Date object, then extend moment.js:

var time = require('time')(Date),
    moment = require('moment');

moment.fn.setTimezone = function(timezone, relative) {
    this.toDate().setTimezone(timezone, relative);
    return this;
}

moment.fn.getTimezone = function() {
    return this.toDate().getTimezone();
}

For good measure let's throw in a utility function to convert "incoming" date/time strings to UTC:

moment.fromTimezone = function(datetime, timezone) {
    return moment(datetime, "YYYY-MM-DD HH:mm").setTimezone(timezone, true).setTimezone("UTC");
}

And you can do this:

var fmt = "YYYY-MM-DD HH:mm",
    datetime = "2013-03-21 00:40",
    timezone = "Israel",
    m = moment.fromTimezone(datetime, timezone);

console.log(datetime, "in", timezone, "is", m.format(fmt), "in UTC");
console.log(m.format(fmt), "in UTC is", m.setTimezone(timezone).format(fmt), "in", m.getTimezone());

Shell output:

$ node mtz.js
2013-03-21 00:40 in Israel is 2013-03-20 22:40 in UTC
2013-03-20 22:40 in UTC is 2013-03-21 00:40 in Israel
$

About a year after this question was asked, Moment Timezone was introduced. Here's an example of how Moment Timezone can solve this problem.

const databaseDate = '2014-05-01T12:00:00Z';
const databaseTimezone = 'America/New_York';
const formatString = 'MMMM Do YYYY, h:mm:ss a';

const dateInUTC = moment.utc(databaseDate);
document.getElementById('dateInUTC').textContent = dateInUTC.format(formatString) + ' in UTC';


const dateInDbTZ = moment.utc(databaseDate).tz(databaseTimezone);
document.getElementById('dateInDbTZ').textContent = dateInDbTZ.format(formatString)  + ' in ' + databaseTimezone;

const dbDateWithoutTZ = '2014-05-01T12:00:00'; // no 'Z'
const dateInLocalTime = moment(dbDateWithoutTZ);
   document.getElementById('dateInLocalTime').textContent = dateInLocalTime.format(formatString) + ' in local time or ' + dateInLocalTime.utc().format(formatString) + ' in UTC';
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.22.1/moment.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.17/moment-timezone-with-data.min.js"></script>
<dl>
<dt>UTC Date</dt>
<dd id="dateInUTC"></dd>
<dt>Timezone-formatted Date</dt>
<dd id="dateInDbTZ"></dd>
<dt>Bad: non-UTC date interpreted as "local time"</dt>
<dd id="dateInLocalTime"></dd>
</dl>

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top