質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

91.35%

  • JavaScript

    11205questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • Swift

    5036questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

  • Node.js

    1221questions

    Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

  • UNIX

    313questions

    UNIXとは、AT&Tのベル研究所で開発されたコンピューター用のマルチユーザー・マルチタスクのオペレーションシステム(OS)です。政府や教育機関や研究所で広範囲に採用されています。

  • DateTime

    29questions

    多くのプログラミング言語におけるDateTimeオブジェクトは、日付と時間に関する演算と出力を行います。

実行時間が負の値になる場合がある(UNIXタイムの誤差?)

受付中

回答 3

投稿 2017/11/25 14:02 ・編集 2017/11/25 14:03

  • 評価
  • クリップ 0
  • VIEW 315

raaacho

score 20

UNIXタイムでコードの実行時間を測定しようとした結果,マイナスの値が出てしまいます.

具体的なシステム構成を以下に述べます.
まず,iPhoneアプリ上でタップした時のタイムスタンプをswiftで取得します.
swiftではマイクロ秒で出てくるため1000をかけてミリ秒に変換します.

        let today = Date();
        let sec = today.timeIntervalSince1970
        let timestamp = String(UInt64(sec * 1000))
        socket.emit("tap", timestamp)

その後,上記のコードにあるようにすぐにnodeで作ったサーバにタイムスタンプを送信し,サーバはPCブラウザにそのデータを送信します.

    socket.on("tap", function(msg){
        console.log("tap_at: " + msg);
        io.sockets.emit('server_to_chrome_tap', msg);
    });

ブラウザがデータを受信した時のタイムスタンプをJavaScriptで取得し,
それらのタイムスタンプを”終了時間ー開始時間”で引き算した結果をブラウザのコンソールに出力します.

    socket.on("server_to_chrome_tap", function(dataFromServer) {
        var startTimeStamp = dataFromServer;
        end = new Date();
        var endTimeStamp = end.getTime();
        console.log(startTimeStamp);
        console.log(endTimeStamp);
        console.log(endTimeStamp - startTimeStamp);
    });

以上のコードを実行した結果,70や68など自然数が表示される場合と-1や-3といった負の値が表示される時があります
だいたい半分くらいの割合で負の値になります.

これはUNIX時間の誤差の問題なのでしょうか?

それとも私が書いたコードが悪いのでしょうか?

どちらにせよ,この問題点と解決策を教えていただけると助かります.

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • defghi1977

    2017/11/26 21:08

    システム構成をもっと明確化して下さい(WEBソケットの通信先等). タイムスタンプに絡む問題には多くの落とし穴が存在するため, 皆さんアドバイスに苦慮しています.

    キャンセル

  • fuzzball

    2017/11/27 09:32

    質問の本質とは関係ないですが .timeIntervalSince1970 って秒単位ですよ。

    キャンセル

回答 3

+5

最も気にするべきはスマホとNode.jsサーバーの現在時刻の差だね。
パソコン機器の時計は精度が悪いから平気で数秒狂うし、スマホの時刻だってそんな正確かどうかなんて保証出来ないからね。

それらのタイムスタンプを”終了時間ー開始時間”で引き算した結果をブラウザのコンソールに出力します.

この一文を見てると、
スマホの現在時刻を開始時点にして、サーバーの終了時刻で引き算してるように思えるんだよね。
もしスマホがサーバーより数秒間進んでいたら、受け取ったサーバは未来のタイムとして認識するから、負の値が出て当然。


どっちかが両方の時刻の差を尊重するしかない。
例えばスマホから「サーバーさんは今何時何分版秒よ?」というリクエストを10分程度といった間隔で送って、受け取った時刻と端末の時刻の差を考慮に入れたタイムスタンプを生成するか、
Node.js鯖が受け取った時刻のタイムスタンプは参考記録としておいておいて、自分のサーバーで生成した時刻を元に計算して、最後にタイムスタンプを加工するとか…ね

投稿 2017/11/25 15:23

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/11/25 17:45

    回答の趣旨に同意なので、ここにコメントします.

    > 最も気にするべきはスマホとNode.jsサーバーの現在時刻の差だね。
    私もこれが原因だと思いますが、これが原因ならクライアントorサーバだけでタイムスタンプを取得すれば、解決するように思いました。
    必要なのが処理時間であれば、時差は関係なくて「開始時刻」「終了時刻」を同じ媒体から取得すれば、正確な時間差を得ることが出来ます。
    HTTPリクエストする時間を処理時間にふくめるならクライアントでタイムスタンプを取得し、HTTPリクエスト時間を含めないならサーバでタイムスタンプを得れば良いと思います。
    両方取得すれば、HTTPリクエスト時間を引き算で算出できます。

    キャンセル

  • 2017/11/25 18:01

    そうですね。
    おっしゃるように基本的にサーバ側が常に正で、ローカルの時刻は捨ててしまえば解決すると思います。

    今回私が想像したのは下記のようなサイトです。
    このサービスは現在時刻を正確なサーバと通信して割り出し、差分を表示してくれるWebアプリになっています。
    https://www.nict.go.jp/JST/JST5.html

    ローカルからタイムスタンプを何故送る事を考えたのかという視点で、
    (非常にニッチなケースとなりそうですが)上手く両者の辻褄を合わせる事が目的の場合、
    何をしなければならないかを共有しておこうと思い、今回の回答文を用意しています。

    キャンセル

  • 2017/11/26 20:47

    調べてみましたが、NTPでは通信遅延時間も考慮したアルゴリズムになっているようで、別のアプローチが必要なようです。
    詳しくは、回答欄に書きました。

    キャンセル

  • 2017/11/26 20:56

    nodeサーバーはタイムスタンプを扱ってない気がするのですが?
    ただ見直してみたら, スマホ(タイムスタンプ取得)→node(タイムスタンプをスルー)→WEBブラウザ(現在時刻と比較)とすると, スマホとWEBブラウザの関係がよくわからず.

    キャンセル

  • 2017/11/26 21:01

    Node.js は門外漢ですが、「npm install date-utils」で解決できないでしょうか。
    https://qiita.com/n0bisuke/items/dd28122d006c95c58f9c

    キャンセル

  • 2017/11/26 21:14

    素直に読み取ればスマホの自己申告時刻(タイムスタンプ)を利用しています。
    `socket.on("server_to_chrome_tap", function(dataFromServer) {`からの
    ` var startTimeStamp = dataFromServer;`なんで、
    Swiftがemitした文字列をそのままstartTimeStamp変数に流し込んでいます。

    最後がNumber - Stringなので気持ち悪いですが、弊害は出ていないかと思います。

    https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Date/getTime
    (new Date()).getTime()
    // 1511698093227
    new Date(1511698093227)
    // Sun Nov 26 2017 21:08:13 GMT+0900 (東京 (標準時))

    キャンセル

+2

 NTP (Network Time Protocol)

NTPとは、NTPサーバとクライアント端末が交信する事でクライアント端末の時刻をNTPサーバの時刻に同期するプロトコルの事です。
NTPサーバから正しい時刻を受信して同期をとればいいわけですが、NTPでは通信遅延時間を考慮したプロトコルになっています。

次のように、通信されたと仮定します。

変数 サーバ時刻 クライアント時刻 処理内容
ts 20:00:00 20:00:04 クライアントがリクエストを送信した時刻
Tr 20:00:01 20:00:05 サーバがクライアントのリクエストを受信した時刻
Ts 20:00:03 20:00:07 サーバがレスポンスを送信した時刻
tr 20:00:04 20:00:08 クライアントがサーバのレスポンスを受信した時刻

往路(クライアント->サーバ)と復路(サーバ->クライアント)の通信時間に差がないと仮定すれば、次の計算式でサーバとクライアントの時刻差を算出できます。

(Ts + Tr) / 2 - (ts + tr) / 2; // 20:00:02 - 20:00:06 = -00:00:04

よって、クライアント端末の時刻を4秒マイナスする事になり、20:00:08から20:00:04にクライアント端末の時刻を修正することが出来ます。

 処理時間

処理時間にも単位があります。

(A) クライアントからサーバへHTTPリクエスト
(B) サーバ処理
(C) サーバからクライアントへHTTPレスポンスし、クライアントで受け取る

処理時間が「(A), (B), (C) の合算」な場合は下記手順で解決します。

(A) クライアント側で「開始時刻」を記録
(C) クライアント側で「終了時刻」を記録

(B) だけが必要な場合は、下記手順で解決します。

(B) サーバで処理開始時に「開始時刻」を記録し、処理終了時に「終了時刻」を記録

それ以外の組み合わせが必要な場合は、NTPと同じ原理で時刻を修正する必要があります。
クライアント端末側からみれば、NTPと同じ仕組みで実装可能ですが、サーバ側で記録をとる場合はもう一度、クライアントからサーバへリクエストを投げ返す必要があります。
サーバから見れば、クライアントへのレスポンスが「サーバからのリクエスト」となるからです。

Re: raaacho さん

投稿 2017/11/26 20:45

編集 2017/11/26 20:54

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

コードの内容と時刻の分解能の点から察するにDate.now()よりHigh Resolution Time仕様で定義されているTimeperformance.timing.navigationStart + performance.now()の方が良かろうと感じます.

※詳しくは試していないのであくまでヒントということで.

[参考]
https://developer.mozilla.org/ja/docs/Web/API/Performance/now

投稿 2017/11/25 14:30

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

ただいまの回答率

91.35%

関連した質問

同じタグがついた質問を見る

  • JavaScript

    11205questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • Swift

    5036questions

    Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

  • Node.js

    1221questions

    Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

  • UNIX

    313questions

    UNIXとは、AT&Tのベル研究所で開発されたコンピューター用のマルチユーザー・マルチタスクのオペレーションシステム(OS)です。政府や教育機関や研究所で広範囲に採用されています。

  • DateTime

    29questions

    多くのプログラミング言語におけるDateTimeオブジェクトは、日付と時間に関する演算と出力を行います。