Время установлено неправильно после полуночи - PullRequest
2 голосов
/ 08 февраля 2020

Я использую следующее, чтобы установить дату / время для чего-то более удобочитаемого:

set day=%date:~4,2%
set mth=%date:~7,2%
set yr=%date:~10,4%
set hur=%time:~0,2%
set min=%time:~3,2%
set bdate=[%day%-%mth%-%yr%]-[%hur%-%min%]

это работает хорошо и выдает что-то вроде: [02-06-2020] - [22-59]

Как только после полуночи формат времени изменяется с ЧЧ: ММ: СС: МС на Ч: ММ: СС: МС и портит формат, и когда он включает : во времени, так как символы смещены на единицу, когда я делаю файл журнала с этим, это неправильно.

Есть ли способ заставить его всегда иметь один формат?

Ответы [ 4 ]

1 голос
/ 08 февраля 2020

Проблема заключается в том, что вы используете значения переменных %DATE% и %TIME%, которые содержат строки, которые не согласованы для разных локалей, P C или пользователей.

Лучший Совет состоит в том, чтобы получить информацию, используя альтернативный метод, например:

@For /F "Tokens=1-5Delims=/: " %%G In (
    '""%__AppDir__%Robocopy.exe" \: . /NJH /L|"%__AppDir__%find.exe" " 123""'
)Do @Set "bdate=[%%I-%%H-%%G]-[%%J-%%K]"

Этот метод включает в себя создание сообщения об ошибке из встроенной утилиты . Мы делаем это, запрашивая его скопировать из целевого каталога с именем : в root текущего диска, \. Возвращается ошибка, поскольку Windows не допускает имена каталогов, содержащие символ :. Это сообщение об ошибке, независимо от локали, P C или пользователя, всегда выводит строку, начинающуюся со строк даты и времени в известном формате, yyyy/MM/dd hh:mm:ss.

Примеры:

2020/02/08 01:25:04 ERROR 123 (0x0000007B) Accessing Source Directory C:\:\
The filename, directory name, or volume label syntax is incorrect.

2020/02/08 01:25:04 ОШИБКА 123 (0x0000007B) Доступ к исходной папке C:\:\
‘Ё*в*ЄбЁзҐбЄ*п ®иЁЎЄ* ў Ё¬Ґ*Ё д*©«*, Ё¬Ґ*Ё Ї*ЇЄЁ Ё«Ё ¬ҐвЄҐ ⮬*.

2020/02/08 01:25:04 ERREUR 123 (0x0000007B) Copie du fichier C:\:\
La syntaxe du nom de fichier, de répertoire ou de volume est incorrecte.

2020/02/08 01:25:04 FEHLER 123 (0x0000007B) Zugriff auf Zielverzeichnis C:\:\
Die Syntax für den Dateinamen, Verzeichnisnamen oder die Datenträgerbezeichnungist falsch.

Мы запускаем нашу команду Robocopy внутри , чтобы мы могли захватывать требуемые строки в соответствии с их известным положением строки, форматом и символами разделителя. Мы также должны учитывать тот факт, что вывод состоит из более чем одной строки. Чтобы выбрать строку, я использовал встроенную утилиту и выбрал соответствие только строкам, содержащим строку 123, так как она не может появляться в других местах в выводе. Затем я разделю строку, используя известные символы-разделители в качестве разделителей, и выбираю, сколько компонентов токенов, разделенных разделителями, вернуть. Я выбираю форвард sla sh, /, , который разделяет отдельные компоненты даты , двоеточие. :, , который разделяет отдельные компоненты времени , и пробел, , , который отделяет дату и время от остальной части строки и друг от друга . Для вашего пользовательского случая вы хотели только пять компонентов токена:

    ↓  ↓  ↓  ↓  ↓    delims
2020<strong>/</strong>02<strong>/</strong>08 01<strong>:</strong>25<strong>:</strong>04
↑    ↑  ↑  ↑  ↑
 1    2  3  4  5     tokens
 %G  %H %I %J %K

Последнее, что я делаю, это собираю каждый из компонентов вместе в требуемом порядке и формате, сохраняя его как строковое значение в переменной с именем bdate. Вы должны иметь возможность использовать это значение в другом месте скрипта, например %bdate%, или !bdate!, если включено отложенное расширение .

Чтобы получить больше информации о том, как использовать , откройте окно командной строки и введите for /?.

1 голос
/ 08 февраля 2020

Использование динамических c переменных среды DATE и TIME со строковыми подстановками, как очень подробно объяснил мой ответ на вопрос Что означает% date: ~ -4,4 %% date: ~ -10,2 %% дата: ~ -7,2% _% время: ~ 0,2 %% время: ~ 3,2% значит? очень быстро, но имеет тот недостаток, что формат дата и строка времени зависят от региона (страны), настроенного для учетной записи, используемой для запуска пакетного файла.

Дата может быть без или с сокращенным днем ​​недели в начале и без или с запятой, добавленной после сокращенного дня недели. Строка даты может иметь формат год / месяц / день или месяц / день / год или день / месяц / год с / или . или - или в качестве разделителя. См. Также статью в Википедии о формате даты по стране .

Время может быть в формате 12 или 24 часа. Час может быть без или с опережением 0 при значении меньше 10.

Не было опубликовано, что выводится при работе echo %DATE% %TIME% до десяти часов утра и в три часа днем, чтобы узнать местный формат даты / времени.

Похоже, можно использовать следующий код с : в качестве разделителя в строке времени:

if "%TIME:~1,1%" == ":" (
    set "bdate=[%DATE:~-10,2%-%DATE:~-7,2%-%DATE:~-4%]-[0%TIME:~0,1%-%TIME:~2,2%]"
) else (
    set "bdate=[%DATE:~-10,2%-%DATE:~-7,2%-%DATE:~-4%]-[%TIME:~0,2%-%TIME:~3,2%]"
)

Если второй символ в строке времени - это двоеточие, условие истинно, и первое выражение используется с добавлением 0 слева к одиночному ди git часу, в противном случае блок ELSE используется с двумя ди git час.

Другое решение с разделителем в строке времени, являющемся либо двоеточием, либо точкой, либо пробелом, будет:

for /F "tokens=1,2 delims=:. " %%I in ("%TIME%") do set "Hour=0%%I" & set "Minute=%%J"
set "bdate=[%DATE:~-10,2%-%DATE:~-7,2%-%DATE:~-4%]-[%Hour:~-2%-%Minute%]"

Оставшийся час до : или . или присваивается переменной окружения Hour с начальным нулем. Переменная Minute присваивается минутное право на : или . или . Строка даты / времени строится с использованием только двух последних цифр Hour, чтобы наконец-то всегда был час с двумя цифрами в строке даты / времени, назначенной переменной среды bdate.


Много лучше было бы получить текущую дату и время независимо от региона (страны) и переформатировать их в требуемый формат, используя подстановки строк.

Независимую от региона строку даты / времени можно получить с помощью Windows Команда инструментария управления линейный инструмент WMI C.

Командная строка

wmic OS GET LocalDateTime /VALUE

выводит кодировку UTF-16 Little Endian, например:

 
 
LocalDateTime=20200208124514.468000+060
 
 

Есть две пустые строки, затем строка с текущей локальной датой / временем в формате ггггMMddHHmmss.microsecond ± UT C смещение в минутах и еще две пустые строки.

Эти данные могут использоваться с кодом партии, подобным этому:

@echo off
for /F "tokens=2 delims==." %%I in ('%SystemRoot%\System32\wbem\wmic.exe OS GET LocalDateTime /VALUE') do set "DateTime=%%I"
set "bdate=[%DateTime:~6,2%-%DateTime:~4,2%-%DateTime:~0,4%]-[%DateTime:~8,2%-%DateTime:~10,2%]"

Здесь интерес представляет только строка даты / времени между знаком равенства и десятичной точкой, которая является причиной использования for /F options tokens=2 delims==. чтобы получить только 20200208124514 для l oop переменную I, значение которой присваивается рядом с переменной окружения DateTime.

Переменная среды DateTime переформатируется использование подстановок строк для получения строки даты / времени в формате [dd-MM-yyyy]-[HH-mm], в результате чего переменная окружения bdate определяется с помощью [08-02-2020]-[12-45].

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

Преимущество использования WMI C для получения локальной даты / времени заключается в ее независимости от Windows настроек региона и рабочих даже на Windows XP. Недостатком является то, что выполнение команды занимает довольно много времени (от 1 до 2 секунд) по сравнению с использованием переменных окружения DATE и TIME , доступ к которым осуществляется за несколько микросекунд.

Команда FOR имеет проблемы с синтаксическим анализом вывода Unicode правильно. Он интерпретирует последовательность байтов 0D 00 0A 00 0D 00 0A 00 в конце вывода WMI C из-за двух пустых строк как 0D 0D 0A, то есть как два возврата каретки и один перевод строки. Это приводит к интерпретации двух последних пустых строк в конце вывода WMI C в виде одной строки с одиночным возвратом каретки в виде строки.

Это очень часто проблема, потому что результат set "EnvironmentVariable=%%I" означает %%I с расширением до простого возврата каретки и удаления переменной среды, уже определенной ранее с правильным значением.

Существует несколько решений для устранения этой ошибки синтаксического анализа Unicode команды ДЛЯ . Можно добавить & goto Label для выхода из l oop с переходом на :Label ниже FOR l oop, как только значение будет присвоено переменной среды, чтобы избежать этой проблемы вообще.

Другое решение - использовать if not defined DateTime set "DateTime=%%I" с явным set "DateTime=" над командной строкой FOR , чтобы команда SET выполнялась только один раз.

Еще одно решение используется в этом коде. Имя свойства и его значение выводятся в одной строке из-за использования WMI C option /VALUE. Команда FOR запускает команду SET из-за tokens=2 только тогда, когда она может разбить текущую строку как минимум на две подстроки (токены), используя знак равенства и точку в качестве разделителей из-за delims==.. Но неверный анализируемый конец вывода WMI C предназначен для FOR строки, содержащей только возврат каретки и, следовательно, не имеет второго токена. По этой причине неправильно проанализированные пустые строки здесь также игнорируются командой FOR .

См. Как исправить неправильное поведение при перезаписи переменных при разборе вывода? и cmd каким-то образом пишет китайский текст в качестве вывода для получения подробной информации о проблеме синтаксического анализа FOR в кодированном выводе UTF-16 LE.


Другое решение для получения текущей даты и региона времени независимо использует ROBOCOPY , который доступен с Windows Vista и Windows Server 2003 в системном каталоге Windows, но по умолчанию недоступен на Windows XP. robocopy.exe из Windows Server 2003 можно скопировать в %SystemRoot%\System32 из Windows XP, чтобы использовать этот исполняемый файл также на Windows XP, но он не доступен по умолчанию на Windows XP.

ROBOCOPY выполняется с недопустимой строкой каталога источника "C:\|" и допустимой строкой каталога назначения . (может быть и другим допустимым) и аргументом /NJH для подавления вывода информации заголовка.

robocopy "C:\|" . /NJH

Это выполнение выдает сообщение об ошибке:

 
2020/02/08 12:45:14 ERROR 123 (0x0000007B) Accessing Source Directory C:\|\
The filename, directory name, or volume label syntax is incorrect.

Формат текущей даты / времени в начале второй строки после пустой строки не зависит от региона.

This вывод может быть обработан с помощью:

set "bdate="
for /F "tokens=1-5 delims=/: " %%I in ('%SystemRoot%\System32\robocopy.exe "%SystemDrive%\|" . /NJH') do if not defined bdate set "bdate=[%%K-%%J-%%I]-[%%L-%%M]"

FOR запускается в этом случае еще один командный процесс в фоновом режиме с %ComSpec% /c и командной строкой между двумя ', добавляемыми в качестве дополнительных аргументов в результате чего Windows устанавливается в C:\Windows при выполнении:

C:\Windows\System32\cmd.exe /c C:\Windows\System32\robocopy.exe "C:\|" . /NJH

Первые пять строк sla sh или двоеточия или разделенных пробелами первой непустой строки t Вывод сообщения об ошибке для обработки STDOUT фонового командного процесса, захваченного FOR , присваивается

  • I ... year
  • J ... месяц
  • K ... день
  • L ... час
  • M ... минута

Пять строк данных объединяются со строкой даты / времени в требуемом формате.

Но FOR будет запускать команду SET один раз снова для второй строки сообщения об ошибке. По этой причине переменная окружения bdate явно не определена перед запуском FOR . Переменная среды bdate определяется сначала со строкой даты / времени и больше не изменяется при FOR , обрабатывающей вторую непустую строку из-за дополнительного условия IF , чтобы избежать перезаписи интересующая строка даты / времени с нежелательной строкой.

Преимущество решения ROBOCOPY по сравнению с решением WMI C заключается в гораздо более быстром времени выполнения.


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

  • echo /?
  • for /?
  • if /?
  • robocopy /?
  • set /?
  • wmic /?
  • wmic os /?
  • wmic os get /?
  • wmic os get localdatetime /?

PS: существует множество других решений для получения текущей даты / времени в заданном c Формат не зависит от страны, настроенной для используемой учетной записи. Все эти альтернативные решения можно найти в ответах:

Как получить текущую дату / время в командной строке Windows в подходящем формате для использования в имени файла / папки?

0 голосов
/ 08 февраля 2020
  • Если используется опция wmic.exe, я хотел бы предложить этот код для настройки вашей переменной и формата вывода ...
@echo off && setlocal enabledelayedexpansion 

for /f "tokens=2delims==." %%i in ('
%__APPDIR__%\wbem\wmic OS Get LocalDateTime /value^|%__APPDIR__%findstr [0-9]')do set "dt=%%~i"

set "day=!dt:~6,2!"
set "mth=!dt:~4,2!"
set "yr=!dt:~0,4!"
set "hur=!dt:~8,2!"
set "min=!dt:~10,2!"

echo/[!day!-!mth!-!yr!]-[!hur!-!min!]

endlocal && goto :EOF

  • Выходы:
[08-02-2020]-[01-00]

Obs.: Рассмотрим вариант ответа @ mofi

0 голосов
/ 08 февраля 2020
set "day=%date:~4,2%"
set "mth=%date:~7,2%"
set "yr=%date:~10,4%"
set "_time=0%time%"
set "hur=%_time:~-11,2%"
set "min=%_time:~-8,2%"
set bdate=[%day%-%mth%-%yr%]-[%hur%-%min%]

Вы можете заполнить time с помощью 0, а затем выполнить подстановку с правой стороны, используя отрицательные числа в качестве начальной позиции строки. 1:00 станет 01-00, чтобы соответствовать шаблону HH-MM.

...