我编写了以下批处理程序以获取上次修改日期。问题是它给出的是时钟时间而不是 UTC 时间。我知道我有分钟的滞后,但使用批处理文件进行数字移位并不那么简单。是否有标志可以提供给 wmic 以获取 UTC 时间?这是批处理文件
@echo off
setlocal enableextensions disabledelayedexpansion
set file=%1
set WORKINGdir=%~dp0
rem wmic wants double backslash
set PATHfile=%WORKINGdir%%file%
set PATHfile=%PATHfile:\=\\%
for /f %%a in (
'wmic DataFile where "Name='%PATHfile%'" get lastmodified ^| find "+" '
) do set "val=%%a"
echo %val%
rem get first 14 digits (good until year 9999)
echo %val:~0,14%
endlocal
这给了我这个输出:
20161026144823.620815+120
20161026144823
答案1
纯批处理是可能的,尽管对于大量文件来说,速度可能会太慢。批处理例程源自 Richie Lawrence 批处理函数库。
:: Demo_DateAddSecs.cmd ::::::::::::::::::::::::::::::::::::::::::::
@Echo off&cls
Call :GetISODT DateTime
Echo %DateTime% is now
Call :DateAddSecs %DateTime% 7200 NewDT
Echo %NewDT% +7200 secs
Echo y___m_d_h_n_s_
Echo 20160101013000 Subtract 2h from new year 1:30
Call :DateAddSecs 20160101013000 -7200 NewDT
Echo %NewDT% -7200 secs
Echo y___m_d_h_n_s_
Echo 20160301013000 March first -12h this is a leap year
Call :DateAddSecs 20160301013000 -43200 NewDT
Echo %NewDT% -43200 secs
Echo y___m_d_h_n_s_
Pause
Goto :Eof
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:GetISODT Var
SetLocal
for /f "tokens=1-3 delims=.+-" %%A in (
'wmic os get LocalDateTime^|findstr ^^[0-9]'
) do Set _IsoDT=%%A
EndLocal&Set "%1=%_IsoDT%"&Goto :Eof
:: GetISODT.cmd :::::::::::::::::::::::::::::::::::::::::::::::::::::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:DateAddSecs %yyyymmddhhnnss% %secs2Add% DTreturnvar
:: Original functions DateToSecs and SecsToDate
:: By: Ritchie Lawrence, updated 2002-08-13. Version 1.1
:: Func: Converts DateTime to number of seconds elapsed since
:: 1st January 1970 00:00:00 adds the supplied seconds
:: and converts back to a valid Datetime
:: For a given calendar date and time of day. Tested with Win10pro.
:: Args:
:: %1 by val Datetime in the form yyyymmddhhnnss
:: %2 by val seconds integer to add/subtract 1 hour = 60*60 = 3600
:: %3 by ref the var name to receive the resulting Datetime
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
SetLocal EnableExtensions& Set DT=%1
Set yy=%DT:~0,4%&set mm=%DT:~4,2%&set dd=%DT:~6,2%
set hh=%DT:~8,2%&set nn=%DT:~10,2%&set ss=%DT:~12,2%
Set /a dd=100%dd%%%100,mm=100%mm%%%100
Set /a z=14-mm,z/=12,y=yy+4800-z,m=mm+12*z-3,j=153*m+2
Set /a j=j/5+dd+y*365+y/4-y/100+y/400-2472633
if 1%hh% LSS 20 set hh=0%hh%
Set /a hh=100%hh%%%100,nn=100%nn%%%100,ss=100%ss%%%100
Set /a j=j*86400+hh*3600+nn*60+ss
Endlocal&set /A secs=%j%+%2
:: SecsToDate %secs% yy mm dd hh nn ss
SetLocal EnableExtensions
Set /a i=%secs%,ss=i%%60,i/=60,nn=i%%60,i/=60,hh=i%%24,dd=i/24,i/=24
Set /a a=i+2472632,b=4*a+3,b/=146097,c=-b*146097,c/=4,c+=a
Set /a d=4*c+3,d/=1461,e=-1461*d,e/=4,e+=c,m=5*e+2,m/=153,dd=153*m+2
Set /a dd/=5,dd=-dd+e+1,mm=-m/10,mm*=12,mm+=m+3,yy=b*100+d-4800+m/10
(if %mm% LSS 10 set mm=0%mm%)&(if %dd% LSS 10 set dd=0%dd%)
(if %hh% LSS 10 set hh=0%hh%)&(if %nn% LSS 10 set nn=0%nn%)
if %ss% LSS 10 set ss=0%ss%
Endlocal&set "%3=%yy%%mm%%dd%%hh%%nn%%ss%"&Goto :Eof
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
给出此输出
> DemoDateAddSecs.cmd
20161027053749 is now
20161027073749 +7200 secs
y___m_d_h_n_s_
20160101013000 Subtract 2h from new year 1:30
20151231233000 -7200 secs
y___m_d_h_n_s_
20160301013000 March first -12h this is a leap year
20160229133000 -43200 secs
y___m_d_h_n_s_
高血压
答案2
确实,时间戳算法很麻烦。将小时调整为 UTC 可能会导致日期不同,这意味着您可能需要担心该月有多少天,并且可能需要担心闰年。
WMIC 没有任何内置功能可以将时间戳格式化为 UTC。批处理实际上也不支持处理日期/时间算法。
我写过名为 JREN.BAT 的实用程序可以轻松解决您的问题。它主要是为了允许使用正则表达式重命名文件/文件夹而编写的。但它具有可以解决此问题的额外功能。
JREN.BAT 是纯脚本(混合批处理/JScript),可在 XP 及以上版本的任何 Windows 机器上本地运行 - 无需第三方 exe 文件。从jren /?
命令提示符执行即可获得完整文档(或jren /??
分页帮助)
以下内容将提供与您的脚本相同的功能,但它将正确显示时间戳为 UTC。
@echo off
for /f "delims=" %%A in (
'jren "^.*" "ts({dt:'modified',tz:0})" /j /list /p "%~dp0" /fm %1'
) do set "ts=%%A"
echo %ts%
输出将采用 ISO 8601 格式,不带标点符号,将使用字符串语义按时间顺序正确排序。类似于20161006T155621.746+0000
。
您可以轻松地将 fmt: 选项添加到 ts() 调用中,以您认为合适的任何方式格式化时间戳。使用jren /?ts()
以获取有关处理时间戳的所有可用选项的完整帮助。
使用 JREN 提供带有 UTC 时间的完整目录列表非常简单。
以下列出了t
当前目录中以 开头的所有 .txt 文件的最后修改时间戳、文件大小和文件名。
D:\test>jren "^.*" "ts({dt:'modified',tz:0,fmt:'{iso-dt} {iso-tm}'})+size(' ')+' '+$0" /j /list /fm t*.txt
2015-06-22 19:11:22.134 74 temp1.txt
2015-06-22 19:11:22.259 0 temp2.txt
2015-06-22 19:11:22.384 0 temp3.txt
2016-09-07 15:20:08.146 10376 tempfile.txt
2016-10-06 15:56:21.746 14 test.txt
2015-06-22 19:11:23.600 342 text2.txt
2015-06-22 19:11:23.741 288 textfile1.txt
2015-06-22 19:11:23.866 144 textfile2.txt
2015-10-19 19:12:16.441 707 TL.txt
2016-01-13 17:35:17.505 1030 tl64.txt
2016-01-13 17:36:48.501 974 tl64_2.txt
2016-01-13 17:45:16.383 943 tl64_3.txt
2016-01-13 17:37:21.308 707 tl_1.txt
2016-01-13 17:37:30.356 707 tl_2.txt
2016-01-13 17:45:50.469 707 tl_3.txt
2015-06-22 19:11:24.006 42 tmp.txt
2015-06-22 19:11:24.427 541553 toc-z.txt
2015-08-31 20:59:25.202 17442083 tree.txt
2015-06-22 19:11:24.583 304 tsc_call_layout.txt
JREN 使用 WMI 来获取上次修改的时间戳,这非常慢。根据您的语言设置,您可能能够使用fsomodified
而不是modified
来使用 FileSystemObject 获取时间戳。这要快得多,但它不提供毫秒级的精度,并且只有当您的语言以 JScript 日期对象可以解释的方式格式化时间戳字符串时,它才有效。
D:\test>jren "^.*" "ts({dt:'fsomodified',tz:0,fmt:'{iso-dt} {hh}:{nn}:{ss}'})+size(' ')+' '+$0" /j /list /fm t*.txt
2015-06-22 19:11:22 74 temp1.txt
2015-06-22 19:11:22 0 temp2.txt
2015-06-22 19:11:22 0 temp3.txt
2016-09-07 15:20:08 10376 tempfile.txt
2016-10-06 15:56:21 14 test.txt
2015-06-22 19:11:23 342 text2.txt
2015-06-22 19:11:23 288 textfile1.txt
2015-06-22 19:11:23 144 textfile2.txt
2015-10-19 19:12:16 707 TL.txt
2016-01-13 18:35:17 1030 tl64.txt
2016-01-13 18:36:48 974 tl64_2.txt
2016-01-13 18:45:16 943 tl64_3.txt
2016-01-13 18:37:21 707 tl_1.txt
2016-01-13 18:37:30 707 tl_2.txt
2016-01-13 18:45:50 707 tl_3.txt
2015-06-22 19:11:24 42 tmp.txt
2015-06-22 19:11:24 541553 toc-z.txt
2015-08-31 20:59:25 17442083 tree.txt
2015-06-22 19:11:24 304 tsc_call_layout.txt