Gemorroj » 2013.02.04 18:50

Иногда встречается задача организовать счетчик времени (часы, таймер) на JS.
Типовые реализации на JS практически не учитывают погрешности на сам "тик".
Приведу код реализации высчитывающей реально прошедшее время за тик.

Код:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
var $time = $("#time");
var date = new Date(Config.time * 1000);
var oldTime = (new Date()).getTime();
(function timer () {
var newTime = (new Date()).getTime();
var diff = newTime - oldTime;
 
date.setMilliseconds(diff);
 
var h = date.getHours();
var m = date.getMinutes();
var s = date.getSeconds();
 
h = h < 10 ? '0' + h : h;
m = m < 10 ? '0' + m : m;
s = s < 10 ? '0' + s : s;
 
$time.text(h + ":" + m + ":" + s);
oldTime = newTime;
window.setTimeout(timer, 1000);
})();

Config.time - это timestamp полученный от php функции time(). Там нужно будет вставить свое серверное время.
Идея обсчета реально прошедшего времени за тик очень проста. Мы сравниваем результаты от new Date().getTime() в текущем тике и в предыдущем. Их разница и есть реально прошедшее время за тик.

Влад23 » 2013.12.09 08:10

Код:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<script type="text/javascript">
function fulltime ()
{
var time=new Date();
var newYear=new Date("2013,12,10"); // сюда дату, можно 2013,12,10 или 2013,december,10
var totalRemains=(newYear.getTime()-time.getTime());
if (totalRemains>1){
var RemainsSec = (parseInt(totalRemains/1000));//сколько всего осталось секунд
var RemainsFullDays=(parseInt(RemainsSec/(24*60*60)));//осталось дней
var secInLastDay=RemainsSec-RemainsFullDays*24*3600; //осталось секунд в неполном дне
var RemainsFullHours=(parseInt(secInLastDay/3600));//осталось часов в неполном дне
if (RemainsFullHours<10){RemainsFullHours="0"+RemainsFullHours};
var secInLastHour=secInLastDay-RemainsFullHours*3600;//осталось секунд в неполном часе
var RemainsMinutes=(parseInt(secInLastHour/60));//осталось минут в неполном часе
if (RemainsMinutes<10){RemainsMinutes="0"+RemainsMinutes};
var lastSec=secInLastHour-RemainsMinutes*60;//осталось секунд
if (lastSec<10){lastSec="0"+lastSec};
document.getElementById("RemainsFullDays").innerHTML=RemainsFullDays+"дн. ";
document.getElementById("RemainsFullHours").innerHTML=RemainsFullHours+"час. ";
document.getElementById("RemainsMinutes").innerHTML=RemainsMinutes+"мин. ";
document.getElementById("lastSec").innerHTML=lastSec+"сек. ";
setTimeout('fulltime()',10)
}
else{
document.getElementById("clock").innerHTML="ФИЛЬМ БУДЕТ ДОСТУПЕН В БЛИЖАЙШЕЕ ВРЕМЯ!";
}
}
</script>
<div class="4566">
<div id="timer">
<div class="example3">
<img src="/356/567/46/note.png">
<div class="example_text">
<!--<span class="do_ocnalos" id="clock"> Посмотреть фильм вы сможете через: <br>-->
<b> Посмотреть фильм вы сможете через:
<span class="tooltip"> <img src="/45/46/33/what.png" width="13"
height="13" alt="Подсказка" title="Подсказка"/><em>В скором будущем фильм появится на сайте, и вы сможете узнать о нем побольше.<i></i></em> </span>
</b><br />
<b><span id="RemainsFullDays"></span></b>
<b><span id="RemainsFullHours"></span></b>
<b><span id="RemainsMinutes"></span></b>
<b><span id="lastSec"></span></b>
</span>
<script type="text/javascript">fulltime();</script>
</div>
</div>
</div>

А у меня вот

Gemorroj » 2013.12.09 11:05

Ну вот так вот делать как раз и не надо)

Влад23 » 2013.12.09 12:43

почему? Удобно, я заполняю в форму дату, и мне выводится дата и считается в реальном времени

Gemorroj » 2013.12.09 14:23

сам код страшный. т.н. лапшекод.

Влад23 » 2013.12.09 17:59

да похер главное работает, пока гугл и яша не пасимизируют сайты из за говнокода в js

TLENS » 2013.12.13 14:56

Вот мой вариантик. Показывает ежедневно отчет времени к 20:00 после этого времени скрывается таймер и опять же в 8:00 отображается.
Смотрите метод интервал

Код:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
var timer = {
lastDate: null,
timerIntervalId: null,
blockStatus: false,
timeShowBlock: {
hourse: 8,
minutes: 0,
seconds: 0
},
timeHideBlock: {
hourse: 20,
minutes: 0,
seconds: 0
},
dom: {
hourse: null,
minutes: null,
second: null,
checkVars: function () {
if (this.hourse && this.minutes && this.second) {
return true;
} else {
return false;
}
},
init: function () {
if (this.checkVars()) {
return true;
}
this.hourse = document.getElementById('h');
this.minutes = document.getElementById('m');
this.second = document.getElementById('s');
if (this.checkVars()) {
return true;
} else {
return false;
}
},
hide: function () {
timer.start(30000);
if (timer.blockStatus == true) {
document.getElementById('second-blank').className += 'hidden';
timer.blockStatus = false;
}
},
show: function () {
if (timer.blockStatus == false) {
document.getElementById('second-blank').className = '';
timer.blockStatus = true;
timer.start(1000);
}
}
},
setLastDate: function(d) {
if (d) {
this.lastDate = d;
} else {
this.lastDate = new Date();
}
this.lastDate.setHours(this.timeHideBlock.hourse, this.timeHideBlock.minutes, this.timeHideBlock.second);
},
range: function (h, m, s) {
if (!this.dom.init()) {
return false;
}
this.dom.hourse.innerHTML = h;
this.dom.minutes.innerHTML = m;
this.dom.second.innerHTML = s;
},
arrToSec: function (h, m, s) {
if (m>0) s+= m*60;
if (h>0) s+=h*60*60;
return s;
},
interval: function () {
if (!this.dom.init()) {
return false;
}
d = new Date();
lastTime = new Date();
lastTime.setHours(this.timeHideBlock.hourse, this.timeHideBlock.minutes, this.timeHideBlock.seconds)
lastSecond = lastTime - d;
firstTime = new Date();
firstTime.setHours(this.timeShowBlock.hourse, this.timeShowBlock.minutes, this.timeShowBlock.seconds)
firstSecond = d - firstTime;
if ( firstSecond > 0 && lastSecond > 0) {
this.dom.show();
} else {
this.dom.hide();
return;
}
rem = new Date(lastSecond);
h = rem.getHours() + (d.getTimezoneOffset() / 60);
m = rem.getMinutes();
s = rem.getSeconds();
if (h<10) h = '0'+h;
if (m<10) m = '0'+m;
if (s<10) s = '0'+s;
this.range(h, m, s);
},
start: function (time) {
clearInterval(this.timerIntervalId);
this.timerIntervalId = setInterval(function () {timer.interval()}, (time?time:1000));
}
};
window.onload = function () {
timer.start(5000);
}
Gemorroj » 2013.12.13 15:49

TLENS, к твоему бы коду тоже замер тика добавить)
т.к. если оставить таймер на продолжительное время то погрешность набегает приличная

TLENS » 2013.12.13 17:57

Gemorroj написал:

TLENS, к твоему бы коду тоже замер тика добавить)
т.к. если оставить таймер на продолжительное время то погрешность набегает приличная

Это почему же? У меня таймер будет точным даже по истечению очень большого времени. Так как Я не по тикам измеряю время. А по времени клиента. Каждый тик читает текущее время.

Gemorroj » 2013.12.13 18:06

а, точно. это получается клиентское время, а не серверное.