[Ajax] einfache Uhr mit serverseitiger Zeit

J

j-l-n

Guest
Eine serverseitige Uhrzeitanzeige hat den Vorteil, dass alle User die selbe Uhrzeit sehen und nicht - ihre evtl. auch noch falsche - Systemzeit.
Unser Skript auf Serverseite sieht folgendermaßen aus:
PHP:
/*
im Bsp. verwendeter Dateiname: servertime.php
*/

$timestamp = time();

//Monatsnamen als Array
$monat_name = array(
   "01" => "Januar",
   "02" => "Februar",
   "03" => "März",
   "04" => "April",
   "05" => "Mai",
   "06" => "Juni",
   "07" => "Juli",
   "08" => "August",
   "09" => "September",
   "10" => "Oktober",
   "11" => "November",
   "12" => "Dezember"
);

//Namen der Wochentage als Array
$wochentag_name = array(
   "Sonntag",
   "Montag",
   "Dienstag",
   "Mittwoch",
   "Donnerstag",
   "Freitag",
   "Samstag"
);


//Variablen festlegen

$jahr = date("Y", $timestamp);
$monat = date("m", $timestamp);
$tag = date("d", $timestamp);
$wochentag = date("w", $timestamp);
$uhrzeit = date("G:i", $timestamp);
$sekunden = date("s", $timestamp);

//Namen aus Array auslesen und ersetzen
$monat = $monat_name[$monat];
$wochentag = $wochentag_name[$wochentag];


//gesamtes Datum + Uhrzeit zusammenbauen

$uhr = "$wochentag, $tag. $monat $jahr<br>$uhrzeit:$sekunden Uhr";

echo"$uhr";

Nicht vergessen dürfen wir natürlich, auch die dt. Zeit einzustellen - dies ist oft nicht der Fall...
PHP:
//Serverzeit: dt. Zeitzone
ini_set('date.timezone', 'Europe/Berlin');

Kommen wir nun zum clientseitigen Teil:
Hier benötigen wir zuerst
HTML:
<div id="uhrzeit">
,in den dann mittels .innerHTML die Uhrzeit geschrieben wird.

Das Laden per Ajax sieht dann so aus:
Code:
function uhrzeit() {

 var http = AjaxObject();
 function AjaxObject(){
 //unterschiedliche Ajax-Methoden für z.B. Internet Explorer

   if(window.XMLHttpRequest) {
   return new XMLHttpRequest();
   }
   else if(window.ActiveXObject) {
   //wenn Internet Explorer, der Ajax über ActiveX realisiert
   return new ActiveXObject("Microsoft.XMLHTTP");
   }
   else{ //wenn Ajax nicht unterstützt
   alert("FEHLER: Verwendeter Browser unterstützt die AJAX-Technik nicht!");
   }
 }

 //Pfad zum PHP-Skript
 http.open("GET", "servertime.php", true);
 http.onreadystatechange=function() {

   if(http.readyState == 4) {
   document.getElementById("uhr").innerHTML = http.responseText;
   //ID des HTML-Elements, in dem die Ausgabe erfolgen soll, im Bsp. "uhr"
   }

 }

 http.send(null);
 window.setTimeout("uhrzeit()", 1000);

}


Livedemo: AJAX-Uhr (.../uhr.srf)

Wie immer bin ich offen für Anregungen, konstruktive Kritik und Verbesserungsvorschläge!

PS: Ich war mir nicht ganz sicher, ob das in Tutorials JS oder PHP gehört - falls nötig, bitte einfach verschieben!
Ach ja, was mir gerade aufgefallen ist: in der Beschreibung vom "Tutorials JavaScript" ist ein Rechtschreibfehler ;)
 
Das ganze mit jQuery: [jQuery] Optimaler Ajax-Request

Julian, einen neuen Request sollte man erst auf die Schiene schieben, wenn der alte garantiert beendet ist. Das kann sonst schnell zu Problemen bis hin zu Browserabstürzen führen. Also dein window.setTimeout() immer in den success und error Zweig, nicht übergreifend.
 
Zuletzt bearbeitet:
Die Systemzeit kann falsch eingestellt sein, aber eine Sekunde sollte trotzdem eine Sekunde sein.

Deswegen könnte man die Anzahl der HTTP-Requests deutlich reduzieren, wenn man die Serverzeit mit der lokalen Zeit vergleicht und die Differenz als Korrekturoffset speichert. Dann kann man jede Sekunde die lokale Zeit abrufen, entsprechend korrigieren und dann anzeigen. Den Server würde ich dann immer nur zur vollen Stunde kontaktieren (um z.B. verschiedene Einstellungen zur Sommer-/Winterzeit zu kompensieren).

Das wäre dann eine Einsparung von 3599 Requests.
 
Deswegen könnte man die Anzahl der HTTP-Requests deutlich reduzieren, wenn man die Serverzeit mit der lokalen Zeit vergleicht und die Differenz als Korrekturoffset speichert. Dann kann man jede Sekunde die lokale Zeit abrufen, entsprechend korrigieren und dann anzeigen.

Das wäre auch eine Überlegung wert - wie du sagtest würde man sich viele Reuqests sparen.
 
Dein succes Zweig ist der mit http.readyState == 4
error Zweig musst du noch einbauen.
Ich würde es nicht ohne jQuery machen.

Dann könnte ich es doch auf
Code:
if(http.readyState == 4 && http.status == 200) {
erweitern und dann über else gehen, oder?
 
Zuletzt bearbeitet:
Nein, else geht nicht, weil der Status während des Requests von 0 auf 4 hochwechselt. Ein else würde den ganzen Request spätestens bei 1 abbrechen.
 
.readyState === 4 heißt nicht, dass der Request erfolgreich war, sondern nur, dass er beendet wurde. Der Statuscode gibt an, ob alles glatt gelaufen ist.

So gesehen sind sowohl success, als auch error schon mit dem Code oben abgedeckt.
 
.readyState === 4 heißt nicht, dass der Request erfolgreich war, sondern nur, dass er beendet wurde. Der Statuscode gibt an, ob alles glatt gelaufen ist.

Also dann so:
Code:
if(http.readyState == 4 && http.status == 200) {
//entspricht status:success
}
else if(http.readyState == 4 && http.status != 200) {
//ERROR (z.B. HTTP 500)
}
 
Was ich meinte war, dass man auf if(http.readyState == 4 && http.status = 200) nicht einfach ein else schreiben kann. Man muss readyState von status getrennt abfragen, also wenn überhaupt dann else if status != 200, um den error Zweig zu schreiben. Einfach nur else reicht nicht, weil das bei readyState == 0 auch zutreffen würde.
Oder meinst du was anderes, Korbinian?

Julian, wir waren wieder gleichzeitig :)
Ich glaube, so kannst du es machen. Weil der status glaube ich eh erst bei 4 geliefert wird.
 
klar, damit hattest du natürlich Recht - ich wusste auch, was du gemeint hattest :)
Ich hab ja bloß selber den Denkfehler gemacht gehabt - aber jetzt im letzten Post berichtigt (mit else if).

Und schon wieder ein gleichzeitiger Post und außerdem mal wieder schneller geändert, als ich schreibe :D
 
Deswegen könnte man die Anzahl der HTTP-Requests deutlich reduzieren, wenn man die Serverzeit mit der lokalen Zeit vergleicht und die Differenz als Korrekturoffset speichert.
Wie sähe das dann praktisch aus?
Ich meine mich zu erinnern, dass du irgendwo mal gesagt hast, dass der setTimeout() nur näherungsweise richtig geht. Wenn ich also alle 60 Sekunden die Zeit anzeige, ist das ja garnicht alle 60 Sekunden sondern vielleicht alle nur alle 65 Sekunden, das heißt, irgendwann fängt die Uhr an zu hängen.
Wie würdest du da vorgehen?
 
Habe mal was gebastelt. Meintest du das so, Korbinian?

Live: Test Uhrzeit mit JS über Offset

Code:
Code:
#!/usr/bin/perl
use strict;
use warnings;
use CGI;

my $serverzeit = time()*1000;
print STDOUT CGI->new->header(-charset=>'utf-8').<<HTML_DOC
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Test Uhrzeit mit JS über Offset</title>
<script>
function uhrzeitanzeige(szeit) {
	var czeit = new Date();
	var offset = czeit.getTime()-szeit;
	document.getElementById('clientzeit').innerHTML = czeit.getTime();
	document.getElementById('offset').innerHTML = offset;
	var gib_zeit = function(dateobj) {
		var h = dateobj.getHours();
		if (h < 10) { h = '0'+h; }
		var m = dateobj.getMinutes();
		if (m < 10) { m = '0'+m; }
		var s = dateobj.getSeconds();
		if (s < 10) { s = '0'+s; }
		return h+':'+m+':'+s;
	};
	var zeit_aktualisieren = function(offset) {
		czeit = new Date();
		czeit.setTime(czeit.getTime()+offset);
		document.getElementById('zeit').innerHTML = gib_zeit(czeit);
		window.setTimeout(function () {zeit_aktualisieren(offset);},1000);
	};
	zeit_aktualisieren(offset);
}
</script>
</head>

<body onload="uhrzeitanzeige('$serverzeit');">

<div>Serverzeit: $serverzeit</div>
<div>Clientzeit: <span id="clientzeit"></span></div>
<div>Offset: <span id="offset"></span></div>
<div id="zeit"></div>

</body>

</html>
HTML_DOC
;
 
@mikdoe: so ähnlich hatte ich mir das gedacht. Nur würde ich Datum und Stunde immer komplett vom Server holen (wegen der Sommer-/Winterzeitproblematik) und nur Minuten und Sekunden auf dem Client aktualisieren. Deswegen würde ich immer zu vollen Stunde vom Server neue Daten holen.

Mit window.setTimeout() kann man natürlich keine Uhr machen, aber mit dem Date-Objekt wunderbar.
 
Aber window.setTimeout nutze ich ja im Code auch. Und wenn man die Sekunden weg lässt und nur alle 60 Sekunden aktualisiert und das window.setTimeout unrund läuft hängt die Uhr ja irgendwann. Das meinte ich.
 
Korbinian, meinst du so?

Code:
#!/usr/bin/perl
use strict;
use warnings;
use CGI;

(my $script = $0) =~ s/^.*[\\\/]//g;
my $serverzeit = time()*1000;

my $cgi = new CGI;
if (defined $cgi->param('act') && $cgi->param('act') eq 'serverzeit') {
	print STDOUT CGI->new->header(-charset=>'utf-8').$serverzeit;
}
else {
	print STDOUT CGI->new->header(-charset=>'utf-8').<<HTML_DOC
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Test Uhrzeit mit JS über Offset</title>
<script src="../javascript/jquery.js"></script>
<script>
function uhrzeitanzeige(szeit) {
	var czeit = new Date();
	var offset = czeit.getTime()-szeit;
	document.getElementById('clientzeit').innerHTML = czeit.getTime();
	document.getElementById('offset').innerHTML = offset;
	var gib_zeit = function(dateobj) {
		var h = dateobj.getHours();
		if (h < 10) { h = '0'+h; }
		var m = dateobj.getMinutes();
		if (m < 10) { m = '0'+m; }
		var s = dateobj.getSeconds();
		if (s < 10) { s = '0'+s; }
		return h+':'+m+':'+s;
	};
	var zeit_aktualisieren = function(offset,akt_stunde) {
		czeit = new Date();
		czeit.setTime(czeit.getTime()+offset);
		document.getElementById('zeit').innerHTML = gib_zeit(czeit);
		var stunde = czeit.getHours();
		if (akt_stunde != stunde) {
			document.getElementById('log').innerHTML = 'Ajax Request...'+document.getElementById('log').innerHTML;
			jQuery.ajax ({
				url: '$script',
				data: 'act=serverzeit',
				type: 'POST',
				cache: false,
				success: function (data) {
					czeit = new Date();
					offset = czeit.getTime()-data;
					akt_stunde = stunde;
					window.setTimeout(function () {zeit_aktualisieren(offset,akt_stunde);},1000);
				},
				error: function () {
					window.setTimeout(function () {zeit_aktualisieren(offset,akt_stunde);},1000);
				}
			});
		}
		window.setTimeout(function () {zeit_aktualisieren(offset,akt_stunde);},1000);
	};
	var akt_stunde = czeit.getHours();
	zeit_aktualisieren(offset,akt_stunde);
}
</script>
</head>

<body onload="uhrzeitanzeige('$serverzeit');">

<div>Serverzeit: $serverzeit</div>
<div>Clientzeit: <span id="clientzeit"></span></div>
<div>Offset: <span id="offset"></span></div>
<div id="zeit"></div>
<div id="log"></div>

</body>

</html>
HTML_DOC
;
}

Live: Test Uhrzeit mit JS über Offset

Bliebe noch die Frage wegen der Ungenauigkeit mit windows.setTimeout. Hier wird ja sekündlich neu angezeigt. Ich möchte das bei mir aber gern nur minütlich machen, das heißt, ich setze den Wert auf 60000. Mit welcher Ungenauigkeit muss ich denn dann rechnen?
 
Zurück
Oben