Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Скриптовые языки администрирования Windows (http://forum.oszone.net/forumdisplay.php?f=102)
-   -   [решено] Посчитать количество дней между двумя датами (http://forum.oszone.net/showthread.php?t=335009)

wlad1164 24-05-2018 16:55 2815290

Посчитать количество дней между двумя датами
 
Имеется 2 переменных
Код:

Set /a Date1=180312
Set /a Date2=180523

Date2 всегда больше Date1
Формат всегда ГГММДД
Нужно посчитать кол-во дней между ними ( = 72 )

Запнулся на такой задаче, предположение как решить:
посчитать разность лет,месяцев,дней
затем перемножить и сложить и играться с этими данными добавив условия
но думаю есть решение проще... Буду благодарен за подсказку если таковое есть.

Все это нужно сделать именно в bat

Iska 24-05-2018 17:08 2815293

Цитата:

Цитата wlad1164
Все это нужно сделать именно в bat »

Причина?

Elven 24-05-2018 17:43 2815296

wlad1164, мсье знает толк в извращениях. Тут час убить только на то чтобы прописать условия для всех месяцев, учесть високосный год, имхо, если так уж нужно получать эти данные в bat - проще выполнять вычисления, например, в powershell, в нужном формате возвращать результат и разбив его извращаться дальше.

Iska 24-05-2018 18:09 2815308

Elven, ну, коллеги тут делать-то делали подобное, при большом желании напишут. А так — да, хотелось бы понять причины требования «только пакетный файл».

megaloman 24-05-2018 20:01 2815333

bat+js
Код:

@set @E=1; /*
@Echo Off
cls

Set /A Date1=180312
Set /A Date2=180523

Set /A Vek=20

FOR /F "usebackq delims=" %%d IN (`Cscript //NoLogo /E:jscript "%~dpnx0" %Vek%%Date2%  %Vek%%Date1%`) DO Set /A Days=%%d

Echo %Date2%-%Date1%=%Days%
Pause
GoTo :Eof

*/
var oArg = WScript.Arguments;
if (oArg.Count()<2) WScript.Quit(1);

var msek1=Date.UTC(oArg(0).substr(0,4),oArg(0).substr(4,2)-1,oArg(0).substr(6,2));
var msek2=Date.UTC(oArg(1).substr(0,4),oArg(1).substr(4,2)-1,oArg(1).substr(6,2));

WScript.Echo((msek1-msek2)/86400000);
WScript.Quit(0);


wlad1164 24-05-2018 22:31 2815373

Iska, ну главный вопрос был в том а нет ли какой-либо функции для этого, насколько понял нет...
megaloman, спасибо что не поленились затратить время, но хотелось бы без JS....

Попыхтев пару часов получилось что то вроде этого:
Коряво, но вроде работает
Код:

echo off
Chcp 1251
cls
:: Установка дат
        Set /a Date1=180312
        Set /a Date2=180523
echo %time%
:: Разбивка первой даты
        Set /a God1= %Date1:~0,2%+2000
        Set /a Mes1= %Date1:~2,2%
        Set /a Day1= %Date1:~4,2%
:: Разбивка второй даты
        Set /a God2= %Date2:~0,2%+2000
        Set /a Mes2= %Date2:~2,2%
        Set /a Day2= %Date2:~4,2%
:: Считаем кол-во дней в за годы первой даты
        Set /a GodVis1=%God1%/4
        Set /a GodNeVis1=%God1%/4-1
        Set /a VisGod1=%God1%%%4
                If "%VisGod1%"=="0" (Set /a KolNeVisGod1=%God1%-%GodNeVis1%)
                If "%VisGod1%"=="1" (Set /a KolNeVisGod1=%God1%-%GodNeVis1%)
                If "%VisGod1%"=="2" (Set /a KolNeVisGod1=%God1%-%GodVis1%)
                If "%VisGod1%"=="3" (Set /a KolNeVisGod1=%God1%-%GodVis1%)
        Set /a KolVisGod1=%God1%-%KolNeVisGod1%
        Set /a DaysGod1=%KolVisGod1%*366+%KolNeVisGod1%*365
:: Считаем кол-во дней за годы второй даты
        Set /a GodVis2=%God2%/4
        Set /a GodNeVis2=%God2%/4-1
        Set /a VisGod2=%God2%%%4
                If "%VisGod2%"=="0" (Set /a KolNeVisGod2=%God2%-%GodNeVis2%)
                If "%VisGod2%"=="1" (Set /a KolNeVisGod2=%God2%-%GodNeVis2%)
                If "%VisGod2%"=="2" (Set /a KolNeVisGod2=%God2%-%GodVis2%)
                If "%VisGod2%"=="3" (Set /a KolNeVisGod2=%God2%-%GodVis2%)
        Set /a KolVisGod2=%God2%-%KolNeVisGod2%
        Set /a DaysGod2=%KolVisGod2%*366+%KolNeVisGod2%*365
:: Разность жней меду годами
        Set /a RaznostGod=%DaysGod2%-%DaysGod1%
:: Считаем кол-во дней за месяца первой даты
        :: Февраль первой даты
        If "%VisGod1%"=="0" (Set /a FebDate1=29) else (Set /a FebDate1=28)
        :: Дни
        If "%Mes1%"=="1" (Set /a DayMes1=%Day1%)
        If "%Mes1%"=="2" (Set /a DayMes1=31+%Day1%)
        If "%Mes1%"=="3" (Set /a DayMes1=31+%FebDate1%+%Day1%)
        If "%Mes1%"=="4" (Set /a DayMes1=31*2+%FebDate1%+%Day1%)
        If "%Mes1%"=="5" (Set /a DayMes1=31*2+%FebDate1%+30+%Day1%)
        If "%Mes1%"=="6" (Set /a DayMes1=31*3+%FebDate1%+30+%Day1%)
        If "%Mes1%"=="7" (Set /a DayMes1=31*3+%FebDate1%+30*2+%Day1%)
        If "%Mes1%"=="8" (Set /a DayMes1=31*4+%FebDate1%+30*2+%Day1%)
        If "%Mes1%"=="9" (Set /a DayMes1=31*5+%FebDate1%+30*2+%Day1%)
        If "%Mes1%"=="10" (Set /a DayMes1=31*5+%FebDate1%+30*3+%Day1%)
        If "%Mes1%"=="11" (Set /a DayMes1=31*6+%FebDate1%+30*3+%Day1%)
        If "%Mes1%"=="12" (Set /a DayMes1=31*6+%FebDate1%+30*4+%Day1%)
:: Считаем кол-во дней за месяца второй даты
        :: Февраль второй даты
        If "%VisGod2%"=="0" (Set /a FebDate2=29) else (Set /a FebDate2=28)
        :: Дни
        If "%Mes2%"=="1" (Set /a DayMes2=%Day2%)
        If "%Mes2%"=="2" (Set /a DayMes2=31+%Day2%)
        If "%Mes2%"=="3" (Set /a DayMes2=31+%FebDate2%+%Day2%)
        If "%Mes2%"=="4" (Set /a DayMes2=31*2+%FebDate2%+%Day2%)
        If "%Mes2%"=="5" (Set /a DayMes2=31*2+%FebDate2%+30+%Day2%)
        If "%Mes2%"=="6" (Set /a DayMes2=31*3+%FebDate2%+30+%Day2%)
        If "%Mes2%"=="7" (Set /a DayMes2=31*3+%FebDate2%+30*2+%Day2%)
        If "%Mes2%"=="8" (Set /a DayMes2=31*4+%FebDate2%+30*2+%Day2%)
        If "%Mes2%"=="9" (Set /a DayMes2=31*5+%FebDate2%+30*2+%Day2%)
        If "%Mes2%"=="10" (Set /a DayMes2=31*5+%FebDate2%+30*3+%Day2%)
        If "%Mes2%"=="11" (Set /a DayMes2=31*6+%FebDate2%+30*3+%Day2%)
        If "%Mes2%"=="12" (Set /a DayMes2=31*6+%FebDate2%+30*4+%Day2%)
:: Разность жней меду днями года
        Set /a RaznostDayMes=%DayMes2%-%DayMes1%
:: Разность между
        Set /a Day=%RaznostGod%+%RaznostDayMes%
echo %Date2%-%Date1%=%Day% дн.
echo %time%
pause



Високосный год вроде бы тоже работает... по крайней мере мне так показалось)))

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

UPD
Немного улучшенный вариант
Код:

echo off
Chcp 1251
cls

call :СчитатьРазностьДат Day 20180312 20180523
echo Разность %Day% дн.
pause

:СчитатьРазностьДат
:: Получение дат
        Set /a Date1=%~2 & Set /a Date2=%~3
:: Разбивка даты
        Set /a God1= %Date1:~0,4% & Set /a God2= %Date2:~0,4%
        Set /a Mes1= %Date1:~4,2% & Set /a Mes2= %Date2:~4,2%
        Set /a Day1= %Date1:~6,2% & Set /a Day2= %Date2:~6,2%
:: Определяем вискокосные ли даты
        Set /a VisGod1=%God1%%%4 & Set /a VisGod2=%God2%%%4
:: Считаем дни
        call :СчитатьДниПрошедшихЛет DaysGod1 %VisGod1% %God1%
        call :СчитатьДниПрошедшихЛет DaysGod2 %VisGod2% %God2%
        call :СчитатьДниГода DayMes1 %VisGod1% %Mes1% %Day1%
        call :СчитатьДниГода DayMes2 %VisGod2% %Mes2% %Day2%
        Set /a %~1=(%DaysGod2%-%DaysGod1%)+(%DayMes2%-%DayMes1%)
exit /b
:СчитатьДниГода
        If "%~2"=="0" (Set /a FebDay=29) else (Set /a FebDay=28)
        If "%~3"=="1" (Set /a %~1=%~4)
        If "%~3"=="2" (Set /a %~1=31+%~4)
        If "%~3"=="3" (Set /a %~1=31+%FebDay%+%~4)
        If "%~3"=="4" (Set /a %~1=31*2+%FebDay%+%~4)
        If "%~3"=="5" (Set /a %~1=31*2+%FebDay%+30+%~4)
        If "%~3"=="6" (Set /a %~1=31*3+%FebDay%+30+%~4)
        If "%~3"=="7" (Set /a %~1=31*3+%FebDay%+30*2+%~4)
        If "%~3"=="8" (Set /a %~1=31*4+%FebDay%+30*2+%~4)
        If "%~3"=="9" (Set /a %~1=31*5+%FebDay%+30*2+%~4)
        If "%~3"=="10" (Set /a %~1=31*5+%FebDay%+30*3+%~4)
        If "%~3"=="11" (Set /a %~1=31*6+%FebDay%+30*3+%~4)
        If "%~3"=="12" (Set /a %~1=31*6+%FebDay%+30*4+%~4)
exit /b
:СчитатьДниПрошедшихЛет
        Set /a GodVis=%~3/4
        Set /a GodNeVis=%~3/4-1
                If "%~2"=="0" (Set /a NeVis=%~3-%GodNeVis%)
                If "%~2"=="1" (Set /a NeVis=%~3-%GodNeVis%)
                If "%~2"=="2" (Set /a NeVis=%~3-%GodVis%)
                If "%~2"=="3" (Set /a NeVis=%~3-%GodVis%)
        Set /a VisGod=%~3-%NeVis%
        Set /a %~1=%VisGod%*366+%NeVis%*365
exit /b


megaloman 25-05-2018 09:34 2815409

wlad1164, Меня количество Ваших если ужасает.
Вот мой вариант. Нормальные ленивые герои всегда идут в обход
Идея как и в JS: сделал функцию, которая вычислит порядковый номер заданного дня в дате начиная от 1 января 2000 (точнее -00) года . Затем разность посчитать - нет труда.
Код:

@Echo Off
cls

Set "Date1=180312"
Set "Date2=180523"

Call :Days %Date1:~0,2%  %Date1:~2,2% %Date1:~4,2% "ND1"
Call :Days %Date2:~0,2%  %Date2:~2,2% %Date2:~4,2% "ND2"
Set /A ND=%ND2%-%ND1%

Echo %Date2%-%Date1%=%ND2%-%ND1%=%ND%
Pause
GoTo :Eof

:Days
SetLocal
        Set /A N01=0, N02=31, N03=59, N04=90, N05=120, N06=151, N07=181, N08=212, N09=243, N10=273, N11=304, N12=334
        Set /A V01=0, V02=31, V03=60, V04=91, V05=121, V06=152, V07=182, V08=213, V09=244, V10=274, V11=305, V12=335
        Set /A NN=%1-%1/4*4
        Set /A Dy=%1/4*1461+%NN%*365
        If %NN%==0 (Call Set MM=%%V%2%%) Else (Set /A Dy+=1 &Call Set MM=%%N%2%%)
        EndLocal &Set /A %~4=%Dy%+%MM%+%3
GoTo :Eof

Замечание: Если год начинается с 0, то надо его определять не как численный
Set /a Date1=080312
а как строковый
Set "Date1=080312"

Вариант использования функции
Код:

..................................
Set "Date1=18 03 12"
Set "Date2=18 05 23"

Call :Days %Date1% "ND1"
Call :Days %Date2% "ND2"
..................................

В принципе, не сложно переделать и под четырёхзначный год, например, дни отсчитывать начиная с 1900 года, но задача Вами так не ставилась
Верю: это же можно сделать элегантнее, но я пока не знаю как

greg zakharov 26-05-2018 14:13 2815572

Есть такая штука, julian day называется, значительно облегчает расчет разницы между датами.
Код:

@echo off
  setlocal
    2>nul set /a "d1=180312, d2=180523" % rem : даты, между которыми будет считаться разница
    call:expandDate %d1% d1
    call:expandDate %d2% d2
    set /a "delta=d2-d1"
    echo %delta%
  endlocal
exit /b

:expandDate
  set "d=%~1"
  call:toJulianDay %d:~4,2% %d:~2,2% 20%d:~0,2%
  set "%~2=%jdn%"
exit /b

:toJulianDay
  set /a "jdn=(1461*(%3+4800+(%2-14)/12))/4+(367*(%2-2-12*((%2-14)/12)))/12-(3*((%3+4900+(%2-14)/12)/100))/4+%1-32075"
exit /b


wlad1164 08-06-2018 11:28 2817404

greg zakharov, наконец тор снова добрался до батника, предложенный Вами вариант работает, но не всегда, к примеру

2>nul set /a "d1=180312, d2=180508"

Уже не сработает

greg zakharov 08-06-2018 12:15 2817419

wlad1164, ошибка возникает из-за того, что командная строка считает числа начинающиеся с нуля в восьмеричной системе счисления, отсюда 08, например, будет недопустимым значением для данной СЧ. Чтобы избежать подобной ошибки нужно значения вроде того же 08 приводить к тому, что в понимании командного интерпретатора будет десятичным числом. Иначе говоря:
Код:

set /a "n=10%var%%%100"
Исправленный вариант с julianday будет выглядеть так:
Код:

@echo off
  setlocal
    2>nul set /a "d1=180312, d2=180508" % rem : даты, между которыми будет считаться разница
    call:expandDate %d1% d1
    call:expandDate %d2% d2
    set /a "delta=d2-d1"
    echo %delta%
  endlocal
exit /b

:expandDate
  set "d=%~1"
  set /a "a=10%d:~4,2%%%100, b=10%d:~2,2%%%100"
  call:toJulianDay %a% %b% 20%d:~0,2%
  set "%~2=%jdn%"
exit /b

:toJulianDay
  set /a "jdn=(1461*(%3+4800+(%2-14)/12))/4+(367*(%2-2-12*((%2-14)/12)))/12-(3*((%3+4900+(%2-14)/12)/100))/4+%1-32075"
exit /b



Время: 06:15.

Время: 06:15.
© OSzone.net 2001-