Пакет Windows: відформатована дата в змінну


105

Як зберегти поточну дату у форматі YYYY-MM-DD у певну змінну у файлі Windows .bat?

Аналог оболонки Unix:

today=`date +%F`
echo $today



1
adarshr, відповідь на це питання використовує досить жахливий і схильний до помилок спосіб вирішення цього питання. Я б радив не використовувати його.
Джої

Це посилання корисно, щоб зрозуміти відповіді нижче. ss64.com/nt/for_f.html
smwikipedia

Відповіді:


151

Ви можете отримати поточну дату локально-агностично, використовуючи

for /f "skip=1" %%x in ('wmic os get localdatetime') do if not defined MyDate set MyDate=%%x

Потім ви можете витягти окремі частини за допомогою підрядків:

set today=%MyDate:~0,4%-%MyDate:~4,2%-%MyDate:~6,2%

Іншим способом, де ви отримуєте змінні, які містять окремі частини, буде:

for /f %%x in ('wmic path win32_localtime get /format:list ^| findstr "="') do set %%x
set today=%Year%-%Month%-%Day%

Набагато приємніше, ніж поспіль з підрядками, за рахунок забруднення вашого змінного простору імен.

Якщо вам потрібен UTC замість місцевого часу, команда більш-менш однакова:

for /f %%x in ('wmic path win32_utctime get /format:list ^| findstr "="') do set %%x
set today=%Year%-%Month%-%Day%

1
@ user2023861 Виявляється, навіть якщо я відкрию командний рядок, я завжди отримую правильну дату / час у момент виклику команди, а не тоді, коли я відкрив командний рядок.
ADTC

5
Зауважте, що якщо ви будете запускати вищезазначений рядок кілька разів, ви не отримаєте нову дату для кожного виклику, оскільки він перевіряє, чи не вказана змінна. Це потрібно, оскільки for /fповертає два рядки, останній з яких є порожнім. Ви можете вирішити це, використовуючи set MyDate=між ними. Я думаю, що саме про це натрапив користувач2023861.
Джої

1
@CharlesWood, принаймні я прагну до надійності у власних пакетних файлах, хоча в наші дні я часто використовую PowerShell замість цього.
Джої

1
Змінні , які будуть встановлені: Year, Month, Day, Hour, Minute, Second, Quarter, WeekInMonth,DayOfWeek
користувач

2
for /f %%x in ('wmic path win32_localtime get /format:list ^| findstr "="') do set %%x set today=%Year%-%Month%-%Day% невірна відповідь: вона повертає один раз місяць і день. Як отримати двозначну ліву підкладку з нульовим місячним і денним рядком дати?
Андрус

39

Якщо ви хочете досягти цього, використовуючи стандартні команди MS-DOS у пакетному файлі, ви можете використовувати:

FOR /F "TOKENS=1 eol=/ DELIMS=/ " %%A IN ('DATE/T') DO SET dd=%%A
FOR /F "TOKENS=1,2 eol=/ DELIMS=/ " %%A IN ('DATE/T') DO SET mm=%%B
FOR /F "TOKENS=1,2,3 eol=/ DELIMS=/ " %%A IN ('DATE/T') DO SET yyyy=%%C

Я впевнений, що це можна вдосконалити далі, але це дає дату в 3 змінних для Дня (ДД), Місяця (мм) та Року (рр. Р-р). Потім ви можете використовувати їх пізніше в пакетному сценарії, як потрібно.

SET todaysdate=%yyyy%%mm%%dd%
echo %dd%
echo %mm%
echo %yyyy%
echo %todaysdate%

Хоча я розумію, що на це питання було прийнято відповідь, цей альтернативний метод може бути оцінений багатьма, хто хоче досягти цього, не використовуючи консоль WMI, тому сподіваюся, що це додасть певного значення цьому питанню.


3
Я виявив, що мені потрібно це трохи змінити на вікні Windows 7. Токени потрібно було збільшити на один: ... ДЛЯ / F "TOKENS = 2,3,4 eol = / DELIMS = /" ...
Джо Джонстон,

1
те ж саме на сервері Win 2012 на Azure
Кирило Юнусов

34

Використовуйте date /Tдля пошуку формату в командному рядку.

Якщо формат дати Thu 17/03/2016використовується таким чином:

set datestr=%date:~10,4%-%date:~7,2%-%date:~4,2%
echo %datestr%

1
Це найближча відповідь на поставлене запитання. Простий одноразовий - все, що мені було потрібно, а не програма.
DCookie

2
Домовились. Деякі відповіді тут виглядають майже як "Встановити MS SQL Server, з'єднатися з клієнтом SQL та виконати команду SELECT CONVERT(VARCHAR(16), GETDATE(), 112)".
isapir

2
Час дати у форматі ISO-8601%date:~10,4%%date:~7,2%%date:~4,2%T%time:~0,2%%time:~3,2%%time:~6,2%
isapir

3
Причина того, що інші відповіді схожі на програму, полягає в тому, що ця відповідь, хоч і проста, не вдасться, якщо ваші регіональні налаштування Windows не налаштовані так, як очікує цей код (тобто цей код працюватиме не в кожній системі Windows)
Деніел Скотт

20

Ще два способи, які не залежать від налаштувань часу (обидва взяті з способу отримання даних / часу незалежними від локалізації ). І обидва також отримують день тижня, і жоден з них не вимагає дозволу адміністратора!

  1. MAKECAB - буде працювати в КОЖНІЙ системі Windows (швидко, але створює невеликий тимчасовий файл) (сценарій foxidrive):

    @echo off
    pushd "%temp%"
    makecab /D RptFileName=~.rpt /D InfFileName=~.inf /f nul >nul
    for /f "tokens=3-7" %%a in ('find /i "makecab"^<~.rpt') do (
        set "current-date=%%e-%%b-%%c"
        set "current-time=%%d"
        set "weekday=%%a"
    )
    del ~.*
    popd
    echo %weekday% %current-date% %current-time%
    pause
    
  2. ROBOCOPY - це не рідна команда для Windows XP та Windows Server 2003 , але її можна завантажити з сайту Microsoft . Але він вбудований у все від Windows Vista і вище:

    @echo off
    setlocal
    for /f "skip=8 tokens=2,3,4,5,6,7,8 delims=: " %%D in ('robocopy /l * \ \ /ns /nc /ndl /nfl /np /njh /XF * /XD *') do (
        set "dow=%%D"
        set "month=%%E"
        set "day=%%F"
        set "HH=%%G"
        set "MM=%%H"
        set "SS=%%I"
        set "year=%%J"
    )
    
    echo Day of the week: %dow%
    echo Day of the month : %day%
    echo Month : %month%
    echo hour : %HH%
    echo minutes : %MM%
    echo seconds : %SS%
    echo year : %year%
    endlocal
    

    І ще три способи, що використовують інші мови скриптів Windows. Вони дадуть вам більше гнучкості, наприклад, ви можете отримати тиждень року, час у мілісекундах тощо.

  3. JScript / BATCH гібрид (потрібно зберегти як .bat). JScript доступний у будь-якій системі від Windows NT і вище, як частина Windows Script Host ( хоча його можна відключити через реєстр, це рідкісний випадок ):

    @if (@X)==(@Y) @end /* ---Harmless hybrid line that begins a JScript comment
    
    @echo off
    cscript //E:JScript //nologo "%~f0"
    exit /b 0
    *------------------------------------------------------------------------------*/
    
    function GetCurrentDate() {
        // Today date time which will used to set as default date.
        var todayDate = new Date();
        todayDate = todayDate.getFullYear() + "-" +
                       ("0" + (todayDate.getMonth() + 1)).slice(-2) + "-" +
                       ("0" + todayDate.getDate()).slice(-2) + " " + ("0" + todayDate.getHours()).slice(-2) + ":" +
                       ("0" + todayDate.getMinutes()).slice(-2);
    
        return todayDate;
    }
    
    WScript.Echo(GetCurrentDate());
    
  4. Гібрид VBScript / BATCH ( Чи можна вставляти та виконувати VBScript у пакетному файлі без використання тимчасового файлу? ) Той самий випадок, що й jscript, але гібридизація не така ідеальна:

    :sub echo(str) :end sub
    echo off
    '>nul 2>&1|| copy /Y %windir%\System32\doskey.exe %windir%\System32\'.exe >nul
    '& echo current date:
    '& cscript /nologo /E:vbscript "%~f0"
    '& exit /b
    
    '0 = vbGeneralDate - Default. Returns date: mm/dd/yy and time if specified: hh:mm:ss PM/AM.
    '1 = vbLongDate - Returns date: weekday, monthname, year
    '2 = vbShortDate - Returns date: mm/dd/yy
    '3 = vbLongTime - Returns time: hh:mm:ss PM/AM
    '4 = vbShortTime - Return time: hh:mm
    
    WScript.echo  Replace(FormatDateTime(Date, 1), ", ", "-")
    
  5. PowerShell - може встановлюватися на кожній машині, у якій є .NET - завантаження з Microsoft ( v1 , v2 та v3 (лише для Windows 7 і вище)). Установлено за замовчуванням у всіх формах Windows 7 / Win2008 і вище:

    C:\> powershell get-date -format "{dd-MMM-yyyy HH:mm}"
    
  6. Самостійно складений jscript.net/batch (я ніколи не бачив машину Windows без .NET, тому думаю, що це досить портативний):

    @if (@X)==(@Y) @end /****** silent line that start jscript comment ******
    
    @echo off
    ::::::::::::::::::::::::::::::::::::
    :::       Compile the script    ::::
    ::::::::::::::::::::::::::::::::::::
    setlocal
    if exist "%~n0.exe" goto :skip_compilation
    
    set "frm=%SystemRoot%\Microsoft.NET\Framework\"
    :: searching the latest installed .net framework
    for /f "tokens=* delims=" %%v in ('dir /b /s /a:d /o:-n "%SystemRoot%\Microsoft.NET\Framework\v*"') do (
        if exist "%%v\jsc.exe" (
            rem :: the javascript.net compiler
            set "jsc=%%~dpsnfxv\jsc.exe"
            goto :break_loop
        )
    )
    echo jsc.exe not found && exit /b 0
    :break_loop
    
    
    call %jsc% /nologo /out:"%~n0.exe" "%~dpsfnx0"
    ::::::::::::::::::::::::::::::::::::
    :::       End of compilation    ::::
    ::::::::::::::::::::::::::::::::::::
    :skip_compilation
    
    "%~n0.exe"
    
    exit /b 0
    
    
    ****** End of JScript comment ******/
    import System;
    import System.IO;
    
    var dt=DateTime.Now;
    Console.WriteLine(dt.ToString("yyyy-MM-dd hh:mm:ss"));
    
  7. Logman Це не може отримати рік і день тижня. Він порівняно повільний, також створює тимчасовий файл і базується на часових марках, які логман ставить на свої файли журналів. Це, мабуть, ніколи не буде використовуватися кимось, включаючи мене, - але це ще один спосіб ...

    @echo off
    setlocal
    del /q /f %temp%\timestampfile_*
    
    Logman.exe stop ts-CPU 1>nul 2>&1
    Logman.exe delete ts-CPU 1>nul 2>&1
    
    Logman.exe create counter ts-CPU  -sc 2 -v mmddhhmm -max 250 -c "\Processor(_Total)\%% Processor Time" -o %temp%\timestampfile_ >nul
    Logman.exe start ts-CPU 1>nul 2>&1
    
    Logman.exe stop ts-CPU >nul 2>&1
    Logman.exe delete ts-CPU >nul 2>&1
    for /f "tokens=2 delims=_." %%t in  ('dir /b %temp%\timestampfile_*^&del /q/f %temp%\timestampfile_*') do set timestamp=%%t
    
    echo %timestamp%
    echo MM: %timestamp:~0,2%
    echo dd: %timestamp:~2,2%
    echo hh: %timestamp:~4,2%
    echo mm: %timestamp:~6,2%
    
    endlocal
    exit /b 0
    

Детальніше про функцію Get-Date .



8

Мені дуже сподобався метод Джої, але я думав, що трохи розширюся на ньому.

При такому підході ви можете запускати код кілька разів і не турбуватися про те, що старе значення "приклеюється", оскільки воно вже визначене.

Кожен раз, коли ви запускаєте цей пакетний файл, він виводить суміщене подання дати та часу, сумісне за ISO 8601.

FOR /F "skip=1" %%D IN ('WMIC OS GET LocalDateTime') DO (SET LIDATE=%%D & GOTO :GOT_LIDATE)
:GOT_LIDATE
SET DATETIME=%LIDATE:~0,4%-%LIDATE:~4,2%-%LIDATE:~6,2%T%LIDATE:~8,2%:%LIDATE:~10,2%:%LIDATE:~12,2%
ECHO %DATETIME%

У цій версії вам потрібно бути обережним, щоб не копіювати / вставляти один і той же код у кілька місць у файлі, оскільки це може спричинити повторювані мітки. Ви можете мати окрему мітку для кожної копії, або просто помістити цей код у свій власний пакетний файл і викликати його зі свого вихідного файлу, де це необхідно.


5

Просто використовуйте %date%змінну:

echo %date%

5
Це поверне дату в будь-якому форматі, який зараз налаштовано короткою датою. Це рідко ISO-8601.
Джої

@Joey Погодився - я тут, тому що це недостатньо добре, щоб покластися.
SteveCinq

5

Відповідно до відповіді від @ProVi, просто змініть, щоб відповідати потрібному форматуванню

echo %DATE:~10,4%-%DATE:~7,2%-%DATE:~4,2% %TIME:~0,2%:%TIME:~3,2%:%TIME:~6,2%

повернеться

yyyy-MM-dd hh:mm:ss
2015-09-15 18:36:11

EDIT Відповідно до коментаря @Jeb, хто правильний, вказаний вище формат часу працюватиме лише у випадку, якщо ваша команда DATE / T повернеться

ddd dd/mm/yyyy
Thu 17/09/2015

Однак це легко редагувати відповідно до вашої мови, використовуючи індексацію кожного символу в рядку, що повертається відповідною змінною середовища DATE%, ви можете витягти потрібні частини рядка.

напр. Використання% DATE ~ 10,4% дозволить розширити змінну середовища DATE, а потім використовувати лише 4 символи, які починаються з 11-го (зсув 10) символу розширеного результату

Наприклад, якщо використовуються дати в стилі США, застосовується наступне

ddd mm/dd/yyyy
Thu 09/17/2015

echo %DATE:~10,4%-%DATE:~4,2%-%DATE:~7,2% %TIME:~0,2%:%TIME:~3,2%:%TIME:~6,2%
2015-09-17 18:36:11

Це лише рішення для деяких людей, оскільки це працює лише в деяких місцях світу, залежно від налаштувань формату дати / часу
jeb

3

Я встановлюю змінну середовища на значення в числовому форматі, бажаному, роблячи це:

FOR /F "tokens=1,2,3,4 delims=/ " %a IN ('echo %date%') DO set DateRun=%d-%b-%c

2

Перевірте це ..

for /f "tokens=2 delims==" %%a in ('wmic OS Get localdatetime /value') do set "dt=%%a"
set "YY=%dt:~2,2%" & set "YYYY=%dt:~0,4%" & set "MM=%dt:~4,2%" & set "DD=%dt:~6,2%"
set "HH=%dt:~8,2%" & set "Min=%dt:~10,2%" & set "Sec=%dt:~12,2%" & set "MS=%dt:~15,3%"
set "datestamp=%YYYY%%MM%%DD%" & set "timestamp=%HH%%Min%%Sec%" & set "fullstamp=%YYYY%-%MM%-%DD%_%HH%-%Min%-%Sec%-%MS%"
echo datestamp: "%datestamp%"
echo timestamp: "%timestamp%"
echo fullstamp: "%fullstamp%"
pause

2

Якщо у вас встановлений Python, ви можете це зробити

python -c "import datetime;print(datetime.date.today().strftime('%Y-%m-%d'))"

Ви можете легко адаптувати рядок формату під свої потреби.


2
Яким чином сказати "Використовувати пітон" відповідь на питання?
Росс Прессер

3
так само, як використання MAKECAB, ROBOCOPY, VBSCRIPT, POWERSHELL Logman та інших пропозицій, які ви можете зателефонувати в командному рядку?
CodeKid

Це можна спростити python -c "import datetime;print(datetime.date.today())", оскільки __str__метод dateкласу просто викликає isoformat().
onewhaleid

2

Можна використовувати PowerShell і перенаправити його вихід на змінну середовища, використовуючи цикл.

З командного рядка ( cmd):

for /f "tokens=*" %a in ('powershell get-date -format "{yyyy-MM-dd+HH:mm}"') do set td=%a

echo %td%
2016-25-02+17:25

У пакетному файлі ви можете втекти %aяк %%a:

for /f "tokens=*" %%a in ('powershell get-date -format "{yyyy-MM-dd+HH:mm}"') do set td=%%a

1
Якщо маска має бути такою, FOR /F "tokens=*" %%a IN ('powershell get-date -format "{yyyy\-MM\-dd\THH\:mm\:ss}"') DO SET date=%%a то використовуйте верхню частину ММ на місяць та зворотну косу рису, щоб уникнути буквальних символів.
Хто

1

Зважаючи на формат дати та часу - це інформація, що залежить від місця розташування, для їх отримання з змінних% date% та% time% знадобиться додаткове зусилля для розбору рядка з перетворенням формату на увагу. Доброю ідеєю є використання деяких API для отримання структури даних та розбору за вашим бажанням. WMIC - хороший вибір. Нижче наведено приклад використання Win32_LocalTime . Ви також можете використовувати Win32_CurrentTime або Win32_UTCTime .

@echo off  
SETLOCAL ENABLEDELAYEDEXPANSION  
for /f %%x in ('wmic path Win32_LocalTime get /format:list ^| findstr "="') do set %%x  
set yyyy=0000%Year%  
set mmmm=0000%Month%  
set dd=00%Day%  
set hh=00%Hour%  
set mm=00%Minute%  
set ss=00%Second%  
set ts=!yyyy:~-4!-!mmmm:~-2!-!dd:~-2!_!hh:~-2!:!mm:~-2!:!ss:~-2!  
echo %ts%  
ENDLOCAL  

Результат:
2018-04-25_10: 03: 11


1

Це розширення відповіді Джої, щоб включити час і прокладати частини 0.

Наприклад, результат буде 2019-06-01_17-25-36. Також зауважте, що це час UTC.

  for /f %%x in ('wmic path win32_utctime get /format:list ^| findstr "="') do set %%x

  set Month=0%Month%
  set Month=%Month:~-2%
  set Day=0%Day%
  set Day=%Day:~-2%
  set Hour=0%Hour%
  set Hour=%Hour:~-2%
  set Minute=0%Minute%
  set Minute=%Minute:~-2%
  set Second=0%Second%
  set Second=%Second:~-2%

  set TimeStamp=%Year%-%Month%-%Day%_%Hour%-%Minute%-%Second%


0

Я використовую наступне:

set iso_date=%date:~6,4%-%date:~3,2%-%date:~0,2%

Або в поєднанні з назвою лог-файлу "MyLogFileName":

set log_file=%date:~6,4%-%date:~3,2%-%date:~0,2%-MyLogFileName

2
Але де ваша відповідь відрізняється чи краща, ніж інші 16? І вже є досить натяків, що це рішення працює лише для вашої локалізації
jeb

0

Якщо повноваження доступні, ви можете використовувати коди нижче:

# get date
$BuildDate=(get-date -format "yyMMdd")
echo BuildDate=$BuildDate

# get time
$BuildTime=(get-date -format "hhmmss")
echo BuildTime=$BuildTime

Ось результат:

BuildDate=200518
BuildTime=115919

-2

Якщо ви не заперечуєте проти одноразової інвестиції від 10 до 30 хвилин, щоб отримати надійне рішення (це не залежить від параметрів регіону Windows), будь ласка, читайте далі.

Давайте звільнимо свій розум. Ви хочете спростити сценарії, щоб вони виглядали так? (Припустимо, ви хочете встановити змінну LOG_DATETIME)

FOR /F "tokens=* USEBACKQ" %%F IN (`FormatNow "yyyy-MM-dd"`) DO (
  Set LOG_DATETIME=%%F
)

echo I am going to write log to Testing_%LOG_DATETIME%.log

Ти можеш. Просто побудуйте FormatNow.exe за допомогою C # .NET і додайте його у свій PATH.

Примітки:

  1. Ви можете використовувати будь-яке видання Visual Studio, наприклад Visual Studio Express, для створення FormatNow.exe.
  2. У Visual Studio виберіть проект C # "Консольний додаток", а не проект "Windows Forms Application".
  3. Здоровий глузд: для вбудованого FormatNow.exe потрібен .NET Framework для запуску.
  4. Здоровий глузд: після додавання FormatNow.exe до змінної PATH вам потрібно перезапустити CMD, щоб набути чинності. Це також стосується будь-яких змін змінних середовища.

Переваги:

  1. Це не повільно (закінчується протягом 0,2 секунди).
  2. Підтримується багато форматів https://msdn.microsoft.com/en-us/library/8kb3ddd4(v=vs.110).aspx, наприклад FormatNow "ddd", щоб отримати лише день тижня, FormatNow "yyyy" отримати лише рік
  3. Це не залежить від параметрів регіону Windows, тому його вихід набагато надійніший. З іншого боку,% date% не надає послідовного формату на різних комп'ютерах і не є надійним.
  4. Вам не потрібно створювати стільки змінних CMD та забруднювати область змінних імен.
  5. Буде потрібно 3 рядки в пакетному сценарії, щоб викликати програму та отримати результати. Він повинен бути досить коротким.

Вихідний код FormatNow.exe, який я створив за допомогою Visual Studio 2010 (я вважаю за краще створити його сам, щоб уникнути ризику завантаження невідомої, можливо, шкідливої ​​програми). Просто скопіюйте та вставте коди нижче, складіть програму один раз, і тоді у вас є надійний формат формат дати для всіх майбутніх цілей.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;

namespace FormatNow
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                if (args.Length < 1)
                {
                    throw new ArgumentException("Missing format");
                }
                string format = args[0];
                Console.Write(DateTime.Now.ToString(format, CultureInfo.InvariantCulture.DateTimeFormat));
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

    }
}

Взагалі, працюючи зі складною логікою, ми можемо спростити її, побудувавши дуже невелику програму і викликавши програму для отримання виводу назад до змінної пакетного сценарію. Ми не студенти, і ми не беремо іспитів, щоб вимагати, щоб ми дотримувались правила єдиного сценарію для вирішення проблем. У реальному робочому середовищі дозволений будь-який (законний) метод. Чому ми все-таки повинні дотримуватися слабких можливостей пакетного сценарію Windows, який потребує вирішення багатьох простих завдань? Чому ми повинні використовувати неправильний інструмент для роботи?

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.