Molto spesso ci sono domande relative relative a data / ora da risolvere con file batch. L'interprete della riga di comando cmd.exe non ha alcuna funzione per i calcoli di data / ora. Molte buone soluzioni funzionanti che utilizzano applicazioni o script di console aggiuntivi sono già state pubblicate qui, su altre pagine di Stack Overflow e su altri siti Web.
Comune per le operazioni basate su data / ora è il requisito di convertire una stringa di data / ora in secondi da un determinato giorno. Molto comune è 1970-01-01 00:00:00 UTC. Ma qualsiasi giorno successivo potrebbe essere utilizzato anche in base all'intervallo di date richiesto per supportare un'attività specifica.
Jay ha pubblicato 7daysclean.cmd contenente una soluzione rapida "data in secondi" per l'interprete della riga di comando cmd.exe . Ma non ci vogliono anni bisestili corretti in considerazione. JR ha pubblicato un componente aggiuntivo per tenere conto del giorno bisestile nell'anno in corso, ma ignorando gli altri anni bisestili dall'anno base, ovvero dal 1970.
Uso da 20 anni tabelle statiche (array) create una volta con una piccola funzione C per ottenere rapidamente il numero di giorni inclusi i giorni bisestili dal 1970-01-01 nelle funzioni di conversione data / ora nelle mie applicazioni scritte in C / C ++.
Questo metodo di tabella molto veloce può essere utilizzato anche nel codice batch usando il comando FOR . Così ho deciso di codificare la subroutine batch GetSeconds
che calcola il numero di secondi dal 1970-01-01 00:00:00 UTC per una stringa data / ora passata a questa routine.
Nota: i secondi di salto non vengono presi in considerazione poiché anche i file system di Windows non supportano i secondi di salto.
Innanzitutto, le tabelle:
Giorni dal 1970-01-01 00:00:00 UTC per ogni anno inclusi i giorni bisestili.
1970 - 1979: 0 365 730 1096 1461 1826 2191 2557 2922 3287
1980 - 1989: 3652 4018 4383 4748 5113 5479 5844 6209 6574 6940
1990 - 1999: 7305 7670 8035 8401 8766 9131 9496 9862 10227 10592
2000 - 2009: 10957 11323 11688 12053 12418 12784 13149 13514 13879 14245
2010 - 2019: 14610 14975 15340 15706 16071 16436 16801 17167 17532 17897
2020 - 2029: 18262 18628 18993 19358 19723 20089 20454 20819 21184 21550
2030 - 2039: 21915 22280 22645 23011 23376 23741 24106 24472 24837 25202
2040 - 2049: 25567 25933 26298 26663 27028 27394 27759 28124 28489 28855
2050 - 2059: 29220 29585 29950 30316 30681 31046 31411 31777 32142 32507
2060 - 2069: 32872 33238 33603 33968 34333 34699 35064 35429 35794 36160
2070 - 2079: 36525 36890 37255 37621 37986 38351 38716 39082 39447 39812
2080 - 2089: 40177 40543 40908 41273 41638 42004 42369 42734 43099 43465
2090 - 2099: 43830 44195 44560 44926 45291 45656 46021 46387 46752 47117
2100 - 2106: 47482 47847 48212 48577 48942 49308 49673
Il calcolo dei secondi per l'anno dal 2039 al 2106 con epoca a partire dal 1970-01-01 è possibile solo utilizzando una variabile a 32 bit senza segno, ovvero unsigned long (o unsigned int) in C / C ++.
Ma cmd.exe usa per le espressioni matematiche una variabile con segno a 32 bit. Pertanto, il valore massimo è 2147483647 (0x7FFFFFFF), ovvero 2038-01-19 03:14:07.
Informazioni sull'anno bisestile (No / Sì) per gli anni dal 1970 al 2106.
1970 - 1989: N N Y N N N Y N N N Y N N N Y N N N Y N
1990 - 2009: N N Y N N N Y N N N Y N N N Y N N N Y N
2010 - 2029: N N Y N N N Y N N N Y N N N Y N N N Y N
2030 - 2049: N N Y N N N Y N N N Y N N N Y N N N Y N
2050 - 2069: N N Y N N N Y N N N Y N N N Y N N N Y N
2070 - 2089: N N Y N N N Y N N N Y N N N Y N N N Y N
2090 - 2106: N N Y N N N Y N N N N N N N Y N N
^ year 2100
Numero di giorni al primo giorno di ogni mese nell'anno corrente.
Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
Year with 365 days: 0 31 59 90 120 151 181 212 243 273 304 334
Year with 366 days: 0 31 60 91 121 152 182 213 244 274 305 335
La conversione di una data in numero di secondi dal 1970-01-01 è abbastanza facile usando queste tabelle.
Attenzione prego!
Il formato delle stringhe di data e ora dipende dall'area di Windows e dalle impostazioni della lingua. I delimitatori e l'ordine dei token assegnati alle variabili di ambiente Day
, Month
e Year
nel primo ciclo FOR di, GetSeconds
devono essere adattati al formato data / ora locale, se necessario.
È necessario adattare la stringa di data della variabile di ambiente se il formato della data nella variabile di ambiente DATE è diverso dal formato di data utilizzato dal comando FOR on %%~tF
.
Ad esempio, quando si %DATE%
espande a Sun 02/08/2015
mentre si %%~tF
espande al 02/08/2015 07:38 PM
seguente codice può essere utilizzato con la modifica della riga 4 per:
call :GetSeconds "%DATE:~4% %TIME%"
Ciò comporta il passaggio alla subroutine 02/08/2015
: la stringa della data senza le 3 lettere dell'abbreviazione del giorno della settimana e il carattere di spazio di separazione.
In alternativa, è possibile utilizzare la seguente per passare la data corrente nel formato corretto:
call :GetSeconds "%DATE:~-10% %TIME%"
Ora gli ultimi 10 caratteri dalla stringa di data vengono passati alla funzione GetSeconds
e quindi non importa se la stringa di data della variabile di ambiente DATE è con o senza giorno della settimana, purché il giorno e il mese siano sempre con 2 cifre nell'ordine previsto, cioè nel formato dd/mm/yyyy
o dd.mm.yyyy
.
Ecco il codice batch con spiegazione dei commenti che mostra semplicemente quale file eliminare e quale file conservare nell'albero delle C:\Temp
cartelle, vedere il codice del primo ciclo FOR .
@echo off
setlocal EnableExtensions EnableDelayedExpansion
rem Get seconds since 1970-01-01 for current date and time.
call :GetSeconds "%DATE% %TIME%"
rem Subtract seconds for 7 days from seconds value.
set /A "LastWeek=Seconds-7*86400"
rem For each file in each subdirectory of C:\Temp get last modification date
rem (without seconds -> append second 0) and determine the number of seconds
rem since 1970-01-01 for this date/time. The file can be deleted if seconds
rem value is lower than the value calculated above.
for /F "delims=" %%F in ('dir /A-D-H-S /B /S "C:\Temp"') do (
call :GetSeconds "%%~tF:0"
rem if !Seconds! LSS %LastWeek% del /F "%%~fF"
if !Seconds! LEQ %LastWeek% (
echo Delete "%%~fF"
) else (
echo Keep "%%~fF"
)
)
endlocal
goto :EOF
rem No validation is made for best performance. So make sure that date
rem and hour in string is in a format supported by the code below like
rem MM/DD/YYYY hh:mm:ss or M/D/YYYY h:m:s for English US date/time.
:GetSeconds
rem If there is " AM" or " PM" in time string because of using 12 hour
rem time format, remove those 2 strings and in case of " PM" remember
rem that 12 hours must be added to the hour depending on hour value.
set "DateTime=%~1"
set "Add12Hours=0"
if "%DateTime: AM=%" NEQ "%DateTime%" (
set "DateTime=%DateTime: AM=%"
) else if "%DateTime: PM=%" NEQ "%DateTime%" (
set "DateTime=%DateTime: PM=%"
set "Add12Hours=1"
)
rem Get year, month, day, hour, minute and second from first parameter.
for /F "tokens=1-6 delims=,-./: " %%A in ("%DateTime%") do (
rem For English US date MM/DD/YYYY or M/D/YYYY
set "Day=%%B" & set "Month=%%A" & set "Year=%%C"
rem For German date DD.MM.YYYY or English UK date DD/MM/YYYY
rem set "Day=%%A" & set "Month=%%B" & set "Year=%%C"
set "Hour=%%D" & set "Minute=%%E" & set "Second=%%F"
)
rem echo Date/time is: %Year%-%Month%-%Day% %Hour%:%Minute%:%Second%
rem Remove leading zeros from the date/time values or calculation could be wrong.
if "%Month:~0,1%" EQU "0" ( if "%Month:~1%" NEQ "" set "Month=%Month:~1%" )
if "%Day:~0,1%" EQU "0" ( if "%Day:~1%" NEQ "" set "Day=%Day:~1%" )
if "%Hour:~0,1%" EQU "0" ( if "%Hour:~1%" NEQ "" set "Hour=%Hour:~1%" )
if "%Minute:~0,1%" EQU "0" ( if "%Minute:~1%" NEQ "" set "Minute=%Minute:~1%" )
if "%Second:~0,1%" EQU "0" ( if "%Second:~1%" NEQ "" set "Second=%Second:~1%" )
rem Add 12 hours for time range 01:00:00 PM to 11:59:59 PM,
rem but keep the hour as is for 12:00:00 PM to 12:59:59 PM.
if "%Add12Hours%" == "1" (
if %Hour% LSS 12 set /A Hour+=12
)
set "DateTime="
set "Add12Hours="
rem Must use 2 arrays as more than 31 tokens are not supported
rem by command line interpreter cmd.exe respectively command FOR.
set /A "Index1=Year-1979"
set /A "Index2=Index1-30"
if %Index1% LEQ 30 (
rem Get number of days to year for the years 1980 to 2009.
for /F "tokens=%Index1% delims= " %%Y in ("3652 4018 4383 4748 5113 5479 5844 6209 6574 6940 7305 7670 8035 8401 8766 9131 9496 9862 10227 10592 10957 11323 11688 12053 12418 12784 13149 13514 13879 14245") do set "Days=%%Y"
for /F "tokens=%Index1% delims= " %%L in ("Y N N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N") do set "LeapYear=%%L"
) else (
rem Get number of days to year for the years 2010 to 2038.
for /F "tokens=%Index2% delims= " %%Y in ("14610 14975 15340 15706 16071 16436 16801 17167 17532 17897 18262 18628 18993 19358 19723 20089 20454 20819 21184 21550 21915 22280 22645 23011 23376 23741 24106 24472 24837") do set "Days=%%Y"
for /F "tokens=%Index2% delims= " %%L in ("N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N N") do set "LeapYear=%%L"
)
rem Add the days to month in year.
if "%LeapYear%" == "N" (
for /F "tokens=%Month% delims= " %%M in ("0 31 59 90 120 151 181 212 243 273 304 334") do set /A "Days+=%%M"
) else (
for /F "tokens=%Month% delims= " %%M in ("0 31 60 91 121 152 182 213 244 274 305 335") do set /A "Days+=%%M"
)
rem Add the complete days in month of year.
set /A "Days+=Day-1"
rem Calculate the seconds which is easy now.
set /A "Seconds=Days*86400+Hour*3600+Minute*60+Second"
rem Exit this subroutine
goto :EOF
Per prestazioni ottimali sarebbe meglio rimuovere tutti i commenti, cioè tutte le righe che iniziano con rem dopo 0-4 spazi iniziali .
E le matrici possono essere ridotte anche, ovvero diminuendo l'intervallo di tempo dal 1980-01-01 00:00:00 al 2038-01-19 03:14:07 come attualmente supportato dal codice batch sopra, ad esempio al 2015-01 -01 al 2019-12-31 come usa il codice seguente che elimina davvero i file più vecchi di 7 giorni nell'albero delle C:\Temp
cartelle.
Inoltre il codice batch di seguito è ottimizzato per il formato orario di 24 ore.
@echo off
setlocal EnableDelayedExpansion
call :GetSeconds "%DATE:~-10% %TIME%"
set /A "LastWeek=Seconds-7*86400"
for /F "delims=" %%F in ('dir /A-D-H-S /B /S "C:\Temp"') do (
call :GetSeconds "%%~tF:0"
if !Seconds! LSS %LastWeek% del /F "%%~fF"
)
endlocal
goto :EOF
:GetSeconds
for /F "tokens=1-6 delims=,-./: " %%A in ("%~1") do (
set "Day=%%B" & set "Month=%%A" & set "Year=%%C"
set "Hour=%%D" & set "Minute=%%E" & set "Second=%%F"
)
if "%Month:~0,1%" EQU "0" ( if "%Month:~1%" NEQ "" set "Month=%Month:~1%" )
if "%Day:~0,1%" EQU "0" ( if "%Day:~1%" NEQ "" set "Day=%Day:~1%" )
if "%Hour:~0,1%" EQU "0" ( if "%Hour:~1%" NEQ "" set "Hour=%Hour:~1%" )
if "%Minute:~0,1%" EQU "0" ( if "%Minute:~1%" NEQ "" set "Minute=%Minute:~1%" )
if "%Second:~0,1%" EQU "0" ( if "%Second:~1%" NEQ "" set "Second=%Second:~1%" )
set /A "Index=Year-2014"
for /F "tokens=%Index% delims= " %%Y in ("16436 16801 17167 17532 17897") do set "Days=%%Y"
for /F "tokens=%Index% delims= " %%L in ("N Y N N N") do set "LeapYear=%%L"
if "%LeapYear%" == "N" (
for /F "tokens=%Month% delims= " %%M in ("0 31 59 90 120 151 181 212 243 273 304 334") do set /A "Days+=%%M"
) else (
for /F "tokens=%Month% delims= " %%M in ("0 31 60 91 121 152 182 213 244 274 305 335") do set /A "Days+=%%M"
)
set /A "Days+=Day-1"
set /A "Seconds=Days*86400+Hour*3600+Minute*60+Second"
goto :EOF
Per ulteriori informazioni sui formati di data e ora e confronti dei tempi dei file su Windows, vedere la mia risposta su Scopri se il file è più vecchio di 4 ore nel file batch con molte ulteriori informazioni sui tempi dei file.