Reputation: 236
Using Meteor, what would be an efficient way to keep a running clock (h:m:s) on the client that displays the server's time?
The JavaScript/PHP answers I've found typically involve getting the server time periodically and calculating the difference between that and the client.
What would that look like with Meteor?
UPDATE: A lot has changed since I originally posted this question. If you're interested in a pre-built solution, I recommend taking a look at Meteor Timesync by @mizzao. Install it by running meteor add mizzao:timesync
in your console.
Upvotes: 11
Views: 7983
Reputation: 1
Just subscribe to a normal collection and put your date in it: (no roundtrip calculations)
import { Meteor } from 'meteor/meteor';
import { Mongo } from 'meteor/mongo';
export const ServerDate = new Mongo.Collection(null);
if (Meteor.isServer) {
// This code only runs on the server
Meteor.publish('serverDate', function serverDatePublication() {
return ServerDate.find({});
});
console.log('<ServerDate>:', new Date());
Meteor.setInterval(updateDate, 1000 * 1);
}
function updateDate() {
// Clean out result cache
ServerDate.remove({});
ServerDate.insert(new Date());
}
Upvotes: 0
Reputation: 36900
There is very good information on this thread. I've pulled everything together into a smart package for Meteor:
There are two main things I added beyond what is already here:
Feel free to open pull requests on this, especially if you have ideas for better/more efficient ways to compute and maintain the offset.
Upvotes: 9
Reputation: 2209
As a followup on this question, is this a performance drain? We are calculating offset every second, and changing the Session based on this re-calculation.
Does this mean anything else dependent on Session would also get recalculated every second?
Might it be better to set into something else?
Or simply make a method which does the local date adjustments as needed, vs setting up the interval and session variable.
let me know what you've found.
Upvotes: 0
Reputation: 236
Thanks @TimDog for the help. I've expanded that code a bit to only check the server periodically while still having a running clock displayed on the client. This is what I ended up with:
Client code:
Meteor.startup(function () {
function setServerTime(){
//get server time (it's in milliseconds)
Meteor.call("getServerTime", function (error, result) {
//get client time in milliseconds
localTime = new Date().getTime();
//difference between server and client
var serverOffset = result - localTime;
//store difference in the session
Session.set("serverTimeOffset", serverOffset);
});
}
function setDisplayTime(){
var offset = Session.get("serverTimeOffset");
var adjustedLocal = new Date().getTime() + offset;
Session.set("serverTime", adjustedLocal);
}
//run these once on client start so we don't have to wait for setInterval
setServerTime();
setDisplayTime();
//check server time every 15min
setInterval(function updateServerTime() {
setServerTime();
}, 900000);
//update clock on screen every second
setInterval(function updateDisplayTime() {
setDisplayTime();
}, 1000);
});
//pass the clock to the HTML template
Template.register.clock = function () {
return new Date(Session.get("serverTime"));
};
Server code:
Meteor.methods({
//get server time in milliseconds
getServerTime: function () {
var _time = (new Date).getTime();
console.log(_time);
return _time;
}
});
Upvotes: 7
Reputation: 8928
David Greenspan gets the client time in this presentation on Spark around 14:30. I've modified this code slightly to get server side time:
Javascript:
if (Meteor.isClient) {
Meteor.startup(function () {
setInterval(function () {
Meteor.call("getServerTime", function (error, result) {
Session.set("time", result);
});
}, 1000);
});
Template.main.time = function () {
return Session.get("time");
};
}
if (Meteor.isServer) {
Meteor.methods({
getServerTime: function () {
var _time = (new Date).toTimeString();
console.log(_time);
return _time;
}
});
}
And the HTML:
<body>
{{> main}}
</body>
<template name="main">
{{time}}
</template>
Upvotes: 21