Top-Themen

AppleEntwicklungHardwareInternetLinuxMicrosoftMultimediaNetzwerkeOff TopicSicherheitSonstige SystemeVirtualisierungWeiterbildungZusammenarbeit

Aktuelle Themen

Administrator.de FeedbackApache ServerAppleAssemblerAudioAusbildungAuslandBackupBasicBatch & ShellBenchmarksBibliotheken & ToolkitsBlogsCloud-DiensteClusterCMSCPU, RAM, MainboardsCSSC und C++DatenbankenDatenschutzDebianDigitiales FernsehenDNSDrucker und ScannerDSL, VDSLE-BooksE-BusinessE-MailEntwicklungErkennung und -AbwehrExchange ServerFestplatten, SSD, RaidFirewallFlatratesGoogle AndroidGrafikGrafikkarten & MonitoreGroupwareHardwareHosting & HousingHTMLHumor (lol)Hyper-VIconsIDE & EditorenInformationsdiensteInstallationInstant MessagingInternetInternet DomäneniOSISDN & AnaloganschlüsseiTunesJavaJavaScriptKiXtartKVMLAN, WAN, WirelessLinuxLinux DesktopLinux NetzwerkLinux ToolsLinux UserverwaltungLizenzierungMac OS XMicrosoftMicrosoft OfficeMikroTik RouterOSMonitoringMultimediaMultimedia & ZubehörNetzwerkeNetzwerkgrundlagenNetzwerkmanagementNetzwerkprotokolleNotebook & ZubehörNovell NetwareOff TopicOpenOffice, LibreOfficeOutlook & MailPapierkorbPascal und DelphiPeripheriegerätePerlPHPPythonRechtliche FragenRedHat, CentOS, FedoraRouter & RoutingSambaSAN, NAS, DASSchriftartenSchulung & TrainingSEOServerServer-HardwareSicherheitSicherheits-ToolsSicherheitsgrundlagenSolarisSonstige SystemeSoziale NetzwerkeSpeicherkartenStudentenjobs & PraktikumSuche ProjektpartnerSuseSwitche und HubsTipps & TricksTK-Netze & GeräteUbuntuUMTS, EDGE & GPRSUtilitiesVB for ApplicationsVerschlüsselung & ZertifikateVideo & StreamingViren und TrojanerVirtualisierungVisual StudioVmwareVoice over IPWebbrowserWebentwicklungWeiterbildungWindows 7Windows 8Windows 10Windows InstallationWindows MobileWindows NetzwerkWindows ServerWindows SystemdateienWindows ToolsWindows UpdateWindows UserverwaltungWindows VistaWindows XPXenserverXMLZusammenarbeit

Zeit-Differenz zwischen Zeit- und Datumsangaben mit Batchprogramm berechnen

Tipp Entwicklung Batch & Shell

Mitglied: Ringelkrat

Ringelkrat (Level 1) - Jetzt verbinden

18.10.2009, aktualisiert 18.10.2012, 14776 Aufrufe, 13 Kommentare, 3 Danke

Ich habe lange nach einem Skript gesucht, welches Zeit-Differenzen berechnet. Schließlich habe ich versucht es selber zu programmieren. Vielleicht kann ja jemand davon profitieren.
Mit Batchprogrammen habe mich bisher nur wenig beschäftigt. Ich bin noch "blutiger Anfänger" und programmiere normalerweise in höheren Sprachen.

Ich habe mir die Mühe gemacht ein Skript zu schreiben, welches die Zeit berechnet, welche zwischen zwei Datumsangaben liegt. Dabei werden die Regeln von Schaltjahren beachtet.
Die Datumsangaben werden als Parameter übergeben und das Resultat wird über %result% zurückgegeben.
Es gibt bestimmt Möglichkeiten das Batch-Skript zu verbessern! Ich hoffe, dass es aber keine Fehler gibt.

Das Skript kann z.B. so aufgerufen werden:
01.
datums_diff.bat 09.11.1990 13:00:59 18.10.2008 00:00:00 
02.
echo %result%
Hier der Quellcode von datums_diff.bat in der Version 1.1.33:
01.
@echo off 
02.
REM Dieses Skript liefert die Differenz von zwei Datums-Angaben (mit Uhrzeit) in Sekunden und beachtet dabei die Schaltjahre 
03.
REM Die Zeiten müssen in folgender Form übergeben werden: datums_diff.bat 31.12.1987 02:34 01.04.2009 14:01 
04.
:start_DatumsDiff 
05.
	REM Rufe die Funktion DateToSec zwei mal auf 
06.
	set datum=%1 && set zeit=%2 
07.
	call :DateToSec 
08.
	set /a sek1=%result% 
09.
	set datum=%3 && set zeit=%4 
10.
	call :DateToSec 
11.
	set /a sek2=%result% 
12.
 
13.
	REM Berechne Differenz 
14.
	set /a result=%sek1%-%sek2% 
15.
	goto ende 
16.
:end_DatumsDiff 
17.
 
18.
:DateToSec 
19.
	REM Hier ist die Subroutine für die Berechnung der Sekunden seit dem 00.00.0000 00:00:00. Benötigt werden die Parameter %zeit% und %datum% in denen die Daten in folgender Form stehen: HH:MM:SS bzw. DD.MM.YYYY mit führenden Nullen. Der Rückgabewert liegt in %result%. 
20.
	REM Parameter einlesen (dabei werden die führenden Nullen eliminiert): 
21.
	for /F "eol=; tokens=1,2,3 delims=." %%i in ("%datum%") do ( 
22.
		set /a d1=1%%i-100 && set /a m1=1%%j-100 && set /a y1=1%%k-10000 
23.
24.
 
25.
	for /F "eol=; tokens=1,2,3 delims=:" %%i in ("%zeit%") do ( 
26.
		set /a h1=1%%i-100 && set /a i1=1%%j-100 && set /a s1=1%%k-100 
27.
28.
	REM @echo Folgendes wurde also eingegeben: %d1%.%m1%.%y1% %h1%:%i1%:%s1% 
29.
 
30.
	REM Tage für die Jahre hinzufügen 
31.
	set /a d1=%d1%+(365*%y1%) 
32.
 
33.
	REM Tage für die Monate hinzufügen 
34.
	if %m1% EQU 2 set /a d1=%d1%+31 
35.
	if %m1% EQU 3 set /a d1=%d1%+59 
36.
	if %m1% EQU 4 set /a d1=%d1%+90 
37.
	if %m1% EQU 5 set /a d1=%d1%+120 
38.
	if %m1% EQU 6 set /a d1=%d1%+151 
39.
	if %m1% EQU 7 set /a d1=%d1%+181 
40.
	if %m1% EQU 8 set /a d1=%d1%+212 
41.
	if %m1% EQU 9 set /a d1=%d1%+243 
42.
	if %m1% EQU 10 set /a d1=%d1%+273 
43.
	if %m1% EQU 11 set /a d1=%d1%+304 
44.
	if %m1% EQU 12 set /a d1=%d1%+334 
45.
 
46.
	REM Schaltjahres-Korrektur (dies ist nur für die Tage nach dem 15. Oktober 1582 gültig) 
47.
	set /a zusaetzlicheTage=%y1%/4 
48.
	set /a zusaetzlicheTage=%zusaetzlicheTage% - (%y1%/100) 
49.
	set /a zusaetzlicheTage=%zusaetzlicheTage% + (%y1%/400) 
50.
	set /a d1=%d1%+%zusaetzlicheTage% 
51.
 
52.
	REM Berechne nun die Sekunden 
53.
	set /a result=%s1% + 60*(%i1% + 60*(%h1% + 24*%d1%)) 
54.
	goto :eof 
55.
:end_DateToSec 
56.
 
57.
:ende
Ich habe auch bewusst auf VBS, PowerShell o.a. externe Hilfsmittel verzichtet.

In der aktuellen Version wurden die Verbesserungsvorschläge von bastla (3) und Biber (4) berücksichtigt.
Mitglied: bastla
18.10.2009 um 12:13 Uhr
Hallo Ringelkrat und willkommen im Forum!

Nur als Anmerkung: Den Aufwand für das Entfernen der führenden Nullen kannst Du (am Beispiel von der in %%i enthaltenen Zahl) so reduzieren:
set /a d1=1%%i-100
Grüße
bastla
Bitte warten ..
Mitglied: Biber
18.10.2009 um 13:00 Uhr
Moin Ringelkrat,

willkommen im Forum und danke für diesen Beitrag.

Gefällt mir bezüglich Aufbau, Struktur, Nachvollziehbarkeit und Kommentierung sehr gut.
Ich habe es deshalb von "Allgemeinem Beitrag" als "Anleitung" umgestuft.

Und ich bin gespannt, ob auch diese Skriptversion 1.0 im Lauf der Zeit noch Updates erfahren wird.

Rein handwerklich bzw. aus Gewohnheit würde ich zwei Sachverhalte anders angehen:

1) In einem Algorithmus wie diesem
... 
REM Tage für die Monate hinzufügen 
if %m1% GTR 1 set /a d1=%d1%+31 
if %m1% GTR 2 set /a d1=%d1%+28 
if %m1% GTR 3 set /a d1=%d1%+31 
if %m1% GTR 4 set /a d1=%d1%+30 
if %m1% GTR 5 set /a d1=%d1%+31 
if %m1% GTR 6 set /a d1=%d1%+30 
if %m1% GTR 7 set /a d1=%d1%+31 
if %m1% GTR 8 set /a d1=%d1%+31 
if %m1% GTR 9 set /a d1=%d1%+30 
if %m1% GTR 10 set /a d1=%d1%+31 
if %m1% GTR 11 set /a d1=%d1%+30 
...
...wird ein Programm im Schnitt 6x, im worst case 12x erst eine IF-Prüfung und dann eine SET /A-Anweisung ausführen.

Wenn Du es so machst:
REM Tage für die Monate hinzufügen 
if %m1% EQU 1 set /a d1=%d1%+31 
if %m1% EQU 2 set /a d1=%d1%+31+28 
if %m1% EQU 3 set /a d1=%d1%+31+28+31 
if %m1% EQU 4 set /a d1=%d1%+31+38+31+30 
....
...dann sind es im Schnitt 6, im schlimmsten Fall 12 IF-Prüfungen und immer nur EINE SET /A-Anweisung.

2)
Ich würde, wenn doch die Berechnung/Umrechnung für "Datumswert1" und "Datumswert2" den gleichen Algorithmus verwendet, diesen wiederverwendbaren Algorithmus in eine Unterroutine/einen Call:Block packen.
Aber das ist rein handwerklich - und wie gesagt: Dein Beispiel ist sehr gut verständlich und nachvollziehbar aus und macht, was ein Skript machen soll.

Werde es entsprechend bewerten.

Grüße
Biber
Bitte warten ..
Mitglied: bastla
18.10.2009 um 13:27 Uhr
Hallo Ringelkrat und Biber!

Zu 1) ließe sich zB auch ein Array nachbilden:
01.
set /a md1=0 
02.
set /a md2=31 
03.
set /a md3=31+28 
04.
set /a md4=31+28+31 
05.
... 
06.
 
07.
call set /a d1+=md%m1%
Grüße
bastla
Bitte warten ..
Mitglied: Ringelkrat
18.10.2009 um 14:36 Uhr
Hallo bastla,

vielen Dank für den Verbesserungsvorschlag! Er hat den Umfang des Codes gut reduziert. Habe ihn eben in der Anleitung eingebaut (s.o.).

Grüße, Ringelkrat
Bitte warten ..
Mitglied: Ringelkrat
18.10.2009 um 14:47 Uhr
Hallo Biber,

freut mich, dass mein Beitrag Dir gefällt. Ich war mir nicht sicher, ob ich ihn als Anleitung einstufen sollte, da die Aussicht bestand, dass man einiges verbessern könnte und somit noch nicht als Anleitung dienen kann. Aber ich denke der Beitrag ist jetzt richtig platziert.

Zu:
  1. Es geht natürlich schneller wenn man die Variable nur einmal verändert. Habe deinen Vorschlag übernommen (s.o.).
  2. Auch diesen Vorschlag habe ich mir zu Herzen genommen. Er hat den Umfang des Codes gut reduziert. Habe den Beitrag 'HowTo - Wie man Subroutinen in Batchfiles erstellt' von fritzo als Hilfe genommen und ihn in die Anleitung eingebaut (s.o.).

Grüße, Ringelkrat
Bitte warten ..
Mitglied: Ringelkrat
18.10.2009 um 15:02 Uhr
Hallo bastla,

interessante Methode mit dem Array! Was passiert denn genau in Zeile 07.:
01.
call set /a d1+=md%m1%
?

Ach so, warum sollte eigentlich die Methode über das Array performanter sein?
    • In der Array-Version müssen 12 Variablen angelegt werden und am Ende wieder freigegeben (von cmd.exe). Hinzu kommt noch ein Aufruf und eine Zuweisung.
    • In Bibers Vorschlag müssen lediglich 11 Vergleiche durchgeführt werden (die auch parallel durchgeführt werden können) und eine Zuweisung.

Das würde ich gerne besser verstehen.

Grüße, Ringelkrat
Bitte warten ..
Mitglied: Biber
18.10.2009 um 15:54 Uhr
Moin Ringelkrat,

zu deinem Bedenken...
Ich war mir nicht sicher, ob ich ihn als Anleitung einstufen sollte...
Der Bereich "Batch & Shell" ist ja ein Unterbereich von "Entwicklung" und "Programmierung".

Ich sehe deine Anleitung als Anleitung,
  • weil du aufzeigst wie ein mittelkomplexes Problem schrittweise strukturiert in lösbare Teilprobleme zerlegt wird
  • weil du einen Algorithmus entwickelst, der nachvollziehbar und übertragbar ist
  • weil du auf Lesbarkeit und Wartbarkeit Wert legst

Ob da nun handwerklich etwas zu verbessern sein mag, ob es sich nun auf 20 oder 30 Zeilen eindampfen ließe, das ist nicht das Wesentliche.

Irgendwelche wundersamen Zauberzeilen, die irgendwas ganz furchtbar Undokumentiertes vollbringen, die lassen wir in den Tankstellen-PC-Zeitschriften - hier im Forum sind mir Algorithmen wichtiger.

Grüße
Biber
Bitte warten ..
Mitglied: bastla
18.10.2009 um 19:06 Uhr
Hallo Ringelkrat!
warum sollte eigentlich die Methode über das Array performanter sein?
Habe ich ja gar nicht behauptet ...

Du hattest erwähnt, dass Du ansonsten in "höheren" Sprachen schreibst, weshalb ich annahm, dass Dich das "Batch-Array-Konzept" interessieren könnte.
Was passiert denn genau in Zeile 07
Durch "call" wird temporär eine weitere CMD-Instanz aufgerufen, in welcher der "Index" (die Variable %m1%) aufgelöst wird, wodurch sich im "Hauptprogramm" eine Zuweisung der Art
set /a d1+=md3
für ein Datum im März ergibt - dadurch wird dann der Wert von %d1% um den Wert von %md3% erhöht (die Schreibweise += ist Dir ja sicher geläufig).

Grüße
bastla
Bitte warten ..
Mitglied: Ringelkrat
18.10.2009 um 19:55 Uhr
Hi bastla,

Danke für die Erklärung. Ich glaube es in etwa verstanden zu haben. Das ist wahrscheinlich wie wenn man in PHP:
01.
<?  
02.
  $foo=2;  
03.
  $wrapper="foo";  
04.
  $bar=$$wrapper; //$bar==2 
05.
?>
verwendet. Bin mir aber nicht sicher, habe auch schon lange kein PHP mehr geschrieben.

Was mir neu ist ist, dass man eine Zuweisung der Art
01.
set /a d1+=md3
machen kann. Ich dachte, dass man die Variablen auf der rechten Seite der Zuweisung in Prozent-Zeichen schreiben muss. Warum macht man dann nicht gleich:
01.
set /a array1=17 
02.
set /a index=1 
03.
set /a erg=array%index% 
04.
echo %erg%
statt dem Code mit dem call davor!?

Grüße, Ringelkrat
Bitte warten ..
Mitglied: bastla
18.10.2009 um 20:17 Uhr
Hallo Ringelkrat!

Du hast mit Deinen Überlegungen völlig Recht - es genügte eigentlich (auch wenn das "call" nicht schadet, aber wir sind ja am Optimieren )
set /a d1+=md%m1%
Da es hier um eine Berechnung geht, gilt:
Alle nicht-nummerischen Zeichenfolgen im Ausdruck werden als Zeichenfolgen von Umgebungsvariablen behandelt, deren Werte vor der Verwendung in Zahlen konvertiert werden. Wenn eine Umgebungsvariable angegeben wird, die nicht definiert ist, wird für diese der Wert Null verwendet. Somit können Sie mit Umgebungsvariablen Berechnungen vornehmen, ohne %-Zeichen einzugeben (siehe Online-Hilfe zu "set").

Ich hatte zunächst gewohnheitsmäßig (da die Prozentzeichen bei einem gewöhnlichen "set" erforderlich sind):
call set /a d1+=%%md%m1%%%
In dieser Form wird tatsächlich "call" benötigt, um zunächst %m1% aufzulösen (wie oben als Beispiel zum Wert 3) und danach dann %md3%.

Bei meinem vorigen Post hatte ich offensichtlich noch immer diese Version im Hinterkopf ...

Grüße
bastla
Bitte warten ..
Mitglied: Ringelkrat
03.11.2009 um 12:54 Uhr
Hey Biber,

noch mal ein wichtiger Nachtrag zu 1.: Du hast geschrieben:
01.
if %m1% EQU 1 set /a d1=%d1%+31
. Damit werden aber im Januar 31 Tage addiert, im Februar 28 usw. Richtig muss es aber heißen:
01.
if %m1% EQU 2 set /a d1=%d1%+31
Hatte es leider genau so übernommen. Ist mir jetzt im neuen Monat aufgefallen und ich habe es auch oben korrigiert (Version 1.1.33).

Leider ist mir noch ein schlimmer Fehler unterlaufen: Ich hatte die Schalttage abgezogen statt zu addieren. Ist jetzt auch behoben.

Ich hoffe es haben noch nicht so viele davon Gebrauch gemacht und, dass jetzt alles richtig ist!

Grüße, Ringelkrat
Bitte warten ..
Mitglied: Biber
03.11.2009 um 13:59 Uhr
Moin Ringelkrat,

besten Dank für den Bugfix und deine Rückmeldung.

Den Bug hab ich genauso dreimal überlesen und hätte es wahrscheinlich nie erfahren ohne dich.

Grüße
Biber
Bitte warten ..
Mitglied: pieh-ejdsch
30.05.2010, aktualisiert 18.10.2012
Hi Ringelkrat,

wenn ein Schaltjahr ist und das Datum ist vor dem 1.3. , dann musst Du den Schalttag wieder abziehen weil dieser ja noch nicht vergangen ist.
01.
:: LY  = Schaltjahr 
02.
set /a LY = JJ / 4 - ( JJ - 1 ) / 4  - (JJ / 100 - ( JJ - 1 ) / 100) + ( JJ / 400 - ( JJ - 1 ) / 400 )
Normal berechnest Du ja immer die Vergangenen Jahre aber bei den zusätzlichen Tagen den Schalttag vom Aktuellem Jahr, also musst Du den Schalttag LY für Januar und bis 28. Februar wieder rausrechnen.
01.
if %m1% EQU 1 set /a d1 - = LY 
02.
if %m1% EQU 2  if not %d1% == 29 set /a d1 + = 31 - LY
dann nicht gleich die Sekunden komplett ausrechnen, da ja CMD nur bis 2.147.483.647 (2^32) richtig rechnet. also erst bis zu den Vergangenen Minuten ausrechen und die Sekunden in eine ExtraVariable schreiben. Wenn Du dann von den ersten Vergangenen Minuten die zweiten Verganen Minuten abziehst wird es aber auch ein NegativWert. Also Zeile 14. den Zweiten Wert vom ersten abziehen. Dann wenn die Minuten fertig abgezogen sind in Sekunden umrechnen und die ersten sekunden abziehen und die zweiten Sekunden dazurechnen.

Wenn Du in Sekunden ausrechnest kannst Du nur eine Spanne von ca. 68 Jahren und knapp 3 Wochen berechnen!

ein anderer Ansatz fürs Datumausrechnen in Tage allerdings ab 01.01.1600 ist von hier http://www.administrator.de/forum/datei-verschieben-um-bestimmte-uhrzei ...
01.
echo off 
02.
for /f "tokens=2 delims=()" %%i in ('echo.^|date') do set "Format=%%i" 
03.
set "Format=%Format:-=.%" 
04.
echo %Format:JJ=JJJJ% %date% 
05.
for /f "tokens=1-3 delims=-." %%i in ("%Format%") do for /f "tokens=1-3 delims=.-" %%l in ("%date%") do set "%%i=%%l" & set "%%j=%%m" & set "%%k=%%n" 
06.
:: LY              Schaltjahr 
07.
set /a LY = JJ / 4 - ( JJ - 1 ) / 4  - (JJ / 100 - ( JJ - 1 ) / 100) + ( JJ / 400 - ( JJ - 1 ) / 400 ) 
08.
set /a xday = 0 
09.
set /a MM=10%MM% %% 100 
10.
:: beforemonthdays    Vergangene Tage im Jahr bis zum Vormonat 
11.
if %MM% lss 3 ( 
12.
	set /a LY = 0 
13.
	if %MM% equ 2 (set /a xday = 2 
14.
	) else set /a xday = 1 
15.
) else if %MM% equ 3 set /a xday = - 1 
16.
set /a beforemonthdays =  (( MM - 4 + MM / 8 ) / 2 + ( MM - 1 ) * 30 ) + LY + xday 
17.
set /a TT=10%TT% %% 100 
18.
:: alldays         Vergangene Tage bis Dato als TageZahl 
19.
set /a alldays=((JJ-1600)*365)+((JJ-1601)/4)+((JJ-1601)/100)-((JJ-1601)/400) + beforemonthdays + TT 
20.
echo Vergangene Tage von 1600 sind %alldays%&pause
[Edit] in der Set /a Anweisung kannst Du die Prozentzeichen um die Variable weglassen. [Edit]
Gruß Phil
Bitte warten ..
Neuester Wissensbeitrag
Windows 10

Powershell 5 BSOD

(1)

Tipp von agowa338 zum Thema Windows 10 ...

Ähnliche Inhalte
LAN, WAN, Wireless
Windows 10 - Nach einiger Zeit Internetausfall (14)

Frage von Irepeps zum Thema LAN, WAN, Wireless ...

Backup
gelöst Datensicherung von Daten, auf denen die ganze Zeit gearbeitet wird (8)

Frage von Windows11 zum Thema Backup ...

Heiß diskutierte Inhalte
LAN, WAN, Wireless
gelöst Server erkennt Client nicht wenn er ausserhalb des DHCP Pools liegt (28)

Frage von Mar-west zum Thema LAN, WAN, Wireless ...

Outlook & Mail
Outlook 2010 findet ost datei nicht (18)

Frage von Floh21 zum Thema Outlook & Mail ...

Windows Server
Server 2008R2 startet nicht mehr (Bad Patch 0xa) (18)

Frage von Haures zum Thema Windows Server ...