Daniel Jonce Evans
Daniel Jonce Evans

Reputation: 236

Display server time on client in Meteor

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

Answers (5)

willkuerlich
willkuerlich

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

Andrew Mao
Andrew Mao

Reputation: 36900

There is very good information on this thread. I've pulled everything together into a smart package for Meteor:

https://github.com/mizzao/meteor-timesync

There are two main things I added beyond what is already here:

  • A more accurate computation of the server/client offset using NTP-style math, as opposed to just diffing the client and server time and ignoring round trip time.
  • The ability to use the server timestamps reactively to display values that will update themselves in templates and reactive computations.

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

zeroasterisk
zeroasterisk

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

Daniel Jonce Evans
Daniel Jonce Evans

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

TimDog
TimDog

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

Related Questions