Zeit-Differenz zwischen Zeit- und Datumsangaben mit Batchprogramm berechnen
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
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:
Hier der Quellcode von
Ich habe auch bewusst auf VBS, PowerShell o.a. externe Hilfsmittel verzichtet.
In der aktuellen Version wurden die Verbesserungsvorschläge von @bastla (Zeit-Differenz zwischen Zeit- und Datumsangaben mit Batchprogramm berechnen) berücksichtigt.
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:
datums_diff.bat 09.11.1990 13:00:59 18.10.2008 00:00:00
echo %result%
Hier der Quellcode von
datums_diff.bat
in der Version 1.1.33: @echo off
REM Dieses Skript liefert die Differenz von zwei Datums-Angaben (mit Uhrzeit) in Sekunden und beachtet dabei die Schaltjahre
REM Die Zeiten müssen in folgender Form übergeben werden: datums_diff.bat 31.12.1987 02:34 01.04.2009 14:01
:start_DatumsDiff
REM Rufe die Funktion DateToSec zwei mal auf
set datum=%1 && set zeit=%2
call :DateToSec
set /a sek1=%result%
set datum=%3 && set zeit=%4
call :DateToSec
set /a sek2=%result%
REM Berechne Differenz
set /a result=%sek1%-%sek2%
goto ende
:end_DatumsDiff
:DateToSec
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%.
REM Parameter einlesen (dabei werden die führenden Nullen eliminiert):
for /F "eol=; tokens=1,2,3 delims=." %%i in ("%datum%") do (
set /a d1=1%%i-100 && set /a m1=1%%j-100 && set /a y1=1%%k-10000
)
for /F "eol=; tokens=1,2,3 delims=:" %%i in ("%zeit%") do (
set /a h1=1%%i-100 && set /a i1=1%%j-100 && set /a s1=1%%k-100
)
REM @echo Folgendes wurde also eingegeben: %d1%.%m1%.%y1% %h1%:%i1%:%s1%
REM Tage für die Jahre hinzufügen
set /a d1=%d1%+(365*%y1%)
REM Tage für die Monate hinzufügen
if %m1% EQU 2 set /a d1=%d1%+31
if %m1% EQU 3 set /a d1=%d1%+59
if %m1% EQU 4 set /a d1=%d1%+90
if %m1% EQU 5 set /a d1=%d1%+120
if %m1% EQU 6 set /a d1=%d1%+151
if %m1% EQU 7 set /a d1=%d1%+181
if %m1% EQU 8 set /a d1=%d1%+212
if %m1% EQU 9 set /a d1=%d1%+243
if %m1% EQU 10 set /a d1=%d1%+273
if %m1% EQU 11 set /a d1=%d1%+304
if %m1% EQU 12 set /a d1=%d1%+334
REM Schaltjahres-Korrektur (dies ist nur für die Tage nach dem 15. Oktober 1582 gültig)
set /a zusaetzlicheTage=%y1%/4
set /a zusaetzlicheTage=%zusaetzlicheTage% - (%y1%/100)
set /a zusaetzlicheTage=%zusaetzlicheTage% + (%y1%/400)
set /a d1=%d1%+%zusaetzlicheTage%
REM Berechne nun die Sekunden
set /a result=%s1% + 60*(%i1% + 60*(%h1% + 24*%d1%))
goto :eof
:end_DateToSec
:ende
In der aktuellen Version wurden die Verbesserungsvorschläge von @bastla (Zeit-Differenz zwischen Zeit- und Datumsangaben mit Batchprogramm berechnen) berücksichtigt.
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 127350
Url: https://administrator.de/contentid/127350
Ausgedruckt am: 23.11.2024 um 05:11 Uhr
13 Kommentare
Neuester Kommentar
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
...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:
...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
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
...
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
....
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
Moin Ringelkrat,
zu deinem Bedenken...
Ich sehe deine Anleitung als Anleitung,
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
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
Hallo Ringelkrat!
Du hattest erwähnt, dass Du ansonsten in "höheren" Sprachen schreibst, weshalb ich annahm, dass Dich das "Batch-Array-Konzept" interessieren könnte.
für ein Datum im März ergibt - dadurch wird dann der Wert von %d1% um den Wert von %md3% erhöht (die Schreibweise
Grüße
bastla
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 Artset /a d1+=md3
+=
ist Dir ja sicher geläufig).Grüße
bastla
Hallo Ringelkrat!
Du hast mit Deinen Überlegungen völlig Recht - es genügte eigentlich (auch wenn das "
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 "
Ich hatte zunächst gewohnheitsmäßig (da die Prozentzeichen bei einem gewöhnlichen "
In dieser Form wird tatsächlich "
Bei meinem vorigen Post hatte ich offensichtlich noch immer diese Version im Hinterkopf ...
Grüße
bastla
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%
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%%%
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
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.
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.
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 Datei verschieben um bestimmte Uhrzeit.
[Edit] in der Set /a Anweisung kannst Du die Prozentzeichen um die Variable weglassen. [Edit]
Gruß Phil
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.
:: LY = Schaltjahr
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.
if %m1% EQU 1 set /a d1 - = LY
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 Datei verschieben um bestimmte Uhrzeit.
echo off
for /f "tokens=2 delims=()" %%i in ('echo.^|date') do set "Format=%%i"
set "Format=%Format:-=.%"
echo %Format:JJ=JJJJ% %date%
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"
:: LY Schaltjahr
set /a LY = JJ / 4 - ( JJ - 1 ) / 4 - (JJ / 100 - ( JJ - 1 ) / 100) + ( JJ / 400 - ( JJ - 1 ) / 400 )
set /a xday = 0
set /a MM=10%MM% %% 100
:: beforemonthdays Vergangene Tage im Jahr bis zum Vormonat
if %MM% lss 3 (
set /a LY = 0
if %MM% equ 2 (set /a xday = 2
) else set /a xday = 1
) else if %MM% equ 3 set /a xday = - 1
set /a beforemonthdays = (( MM - 4 + MM / 8 ) / 2 + ( MM - 1 ) * 30 ) + LY + xday
set /a TT=10%TT% %% 100
:: alldays Vergangene Tage bis Dato als TageZahl
set /a alldays=((JJ-1600)*365)+((JJ-1601)/4)+((JJ-1601)/100)-((JJ-1601)/400) + beforemonthdays + TT
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