Playing with W32tm

Microsoft Windows
Post Reply
User avatar
MigrationUser
Posts: 336
Joined: 2021-Jul-12, 1:37 pm
Contact:

Playing with W32tm

Post by MigrationUser »

12 Jan 2013 16:56
npocmaka

As the w32tm is here since Windows NT I have wondered if it could be used for something ...useful.

I thought the most promising options would be w32tm /ntte and w32tm /ntpte - and how possibly they can be used for time calculations.
/ntte uses as measurement 1/10^(-7) seconds and start counting from 1601.Which means this works with reeealy big numbers (can overflow even long).

here's how it can display the current time:

Code: Select all

rem (" w32tm ")/*
@echo off

for /f "eol=B " %%B in ('WMIC Path Win32_TimeZone Get bias /Format:table') do (
	set /a "offset=%%B/60"
	goto :endfor
)
:endfor

for /f %%S in ('call Cscript //nologo  //E:jscript %0 %offset%') do  (
	set ntte_time=%%S
)
w32tm /ntte %ntte_time%0000

goto :eof
*/
WScript.Echo(((new Date()).getTime()-(new Date(1601,0,1,WScript.Arguments.Item(0))).getTime()));
function rem (){}
As the main part of the logic is exposed in the jscript because of the big numbers it turns out that there's no point to use this in batch script.

w32tm /ntpte - I still have no clear idea how this works:

Code: Select all

C:\>w32tm /ntpte 1
0x014FCFD27DE04000 - 109401 04:20:16.0000000 - 14.7.1900 г. 06:20 ч.

C:\>w32tm /ntpte 2
0x01506868FDE04000 - 109595 08:40:32.0000000 - 24.1.1901 г. 10:40 ч.

C:\>w32tm /ntpte 4294967296
0x014F373BFDE0D897 - 109207 00:00:00.0039063 - 1.1.1900 г. 02:00 ч.

C:\>w32tm /ntpte 4294967295
0x01E7CDBBFD47A980 - 158917 06:28:15.0000000 - 7.2.2036 г. 08:28 ч.
Looks like it uses 1/2^32 (4294967296) slices and start from 1900 and ends somewhere at 2036 - but these are too big intervals - but still I didn't succeeded to hit the current time - probably it's not possible because of the long periods that this uses.Don't know how this can be used for something - probably there's something that I'm missing here(what are these hex numbers?).

/stripchart option can be used to emulate sleep command in a similar way as ping:

Code: Select all

w32tm /stripchart /computer:localhost /period:1 /dataonly /samples:N  >nul 2>&1
As we already have ping does not look very useful too...

For now I can only say I'm disappointed.

Last edited by npocmaka (20 Jan 2013 20:35)

----------------------------

#2 14 Jan 2013 09:51
npocmaka

a little bit more about /ntpte - each slice is calculate somehow on 256 power and modulus base - and is approximately 1 second (and can work with bigger numbers than 4294967296 - but after that the dates start to repeat the dates):

Code: Select all

C:\Program Files\Microsoft SDKs\Windows\v7.1>w32tm /ntpte 0
0x014F373BFDE04000 - 109207 00:00:00.0000000 - 1/1/1900 2:00:00 AM

C:\Program Files\Microsoft SDKs\Windows\v7.1>w32tm /ntpte 256
0x014F37D494604000 - 109207 18:12:16.0000000 - 1/1/1900 8:12:16 PM

C:\Program Files\Microsoft SDKs\Windows\v7.1>w32tm /ntpte 65536
0x014F373C9676C000 - 109207 00:04:16.0000000 - 1/1/1900 2:04:16 AM

C:\Program Files\Microsoft SDKs\Windows\v7.1>w32tm /ntpte 16777216
0x014F373BFE78D680 - 109207 00:00:01.0000000 - 1/1/1900 2:00:01 AM

C:\Program Files\Microsoft SDKs\Windows\v7.1>w32tm /ntpte 4294967296
0x014F373BFDE0D897 - 109207 00:00:00.0039063 - 1/1/1900 2:00:00 AM
The slices are really close to 1 sec (jscript):

Code: Select all

//NTP epoch
var NTPTE_start=new Date(1900,0,1,2);
var NTPTE_start_ms=NTPepoch.getTime();

var current_NTP=currentMS-NTP_MS;

var NTPTE_end=new Date(2036,6,2,6,28,16)
var NTPTE_end_ms=NTPTE_end.getTime();

var NTPTE_whole=NTPEpochEnd - NTPepoch;

WScript.Echo("whole NTP epoch in milliseconds divided by 4294967296: " + wholeNTEpoch/4294967296);
But still don't know how to get the current date :-) .

----------------------------

#3 19 Jan 2013 23:23
npocmaka

I've received some answers on stackoverflow . Please do not hesitate and upvote the MBu's answer :-) .

Here's in brief :

1.) w32tm /ntpte and /ntte works easy with hex numbers if they start with 0x
2.) w32tm /ntpte works with the seconds passed since 1900 but uses byte reversed numbers (the number in hex format with reversed coupled numbers).This means unsigned integer - which is still not convenient for work because cannot be hold in cmd numbers.

3.) Both commands returns the date in ANSI format - the days passed since 1601 y.
4.) The hex value printed by w32tm /ntpte can be directly passed as a parameter to w32tm /ntte
5.) The timetapms returned by /stripchart (with /packetinfo switch which is available only in Vista and above) switch can be passed to /ntpte after byte reversing

here's an example:

Code: Select all

@echo off
rem -- printing local time with w32tm

setlocal
for /f "tokens=3,4 delims=^( "  %%T in ('w32tm /stripchart /computer:localhost  /samples:1 /packetinfo /period:1 ^| find "Transmit Timestamp:"') do (
	set HEXx64_Time_Stamp=%%T
	set ANSI_Current_Date=%%U
)

call :hexByteRevert %HEXx64_Time_Stamp% test_x46
w32tm /ntpte %test_x46%

goto :eof

:hexByteRevert [%1 - hex value , %2 - variable to store result in]
setlocal ENABLEDELAYEDEXPANSION
set hex=%~1
set res=%~2
set "temp="
for /L %%L in (2,2,16) do (
	 set temp=!hex:~%%L,2!!temp!
)
endlocal & call set %res%=0x%temp%
goto :eof
Still not very useful but at least I know how works :-)

Last edited by npocmaka (25 Jan 2013 10:38)

----------------------------

#4 09 May 2013 09:35
npocmaka

#5 06 Sep 2013 09:57
npocmaka


Getting day of the week with w32tm.

Unfortunately will not work on XP because rely on new capabilities of /stripchart switch.
The idea is that with w32tm /stripchart /computer:localhost /samples:1 /period:1 /dataonly /packetinfo I receive the ansi date - days passed since 1.1.1601 (as far as I remember it was Monday on that day) and i can get modulus of 7 of them

Code: Select all

@echo off
setlocal
	rem :: getting ansi date ( days passed from 1st jan 1601 ) , timer server hour and current hour 
	FOR /F "skip=16 tokens=4,5 delims=:( " %%D in ('w32tm /stripchart /computer:localhost  /samples:1  /period:1 /dataonly /packetinfo') do (
	 set "ANSI_DATE=%%D" 
	 set  "TIMESERVER_HOURS=%%E" 
	 goto :end_for  )
	:end_for
	set  "LOCAL_HOURS=%TIME:~0,2%"
	if "%TIMESERVER_HOURS:~0,1%0" EQU "00" set TIMESERVER_HOURS=%TIMESERVER_HOURS:~1,1%
	if "%LOCAL_HOURS:~0,1%0" EQU "00" set LOCAL_HOURS=%LOCAL_HOURS:~1,1%
	set /a OFFSET=TIMESERVER_HOURS-LOCAL_HOURS

	rem :: day of the week will be the modulus of 7 of local ansi date +1 
	rem :: we need need +1 because Monday will be calculated as 0
	rem ::  1st jan 1601 was Monday
	
	rem :: if abs(offset)>12 we are in different days with the time server

	IF %OFFSET%0 GTR 120 set /a DOW=(ANSI_DATE+1)%%7+1 
	IF %OFFSET%0 LSS -120 set /a DOW=(ANSI_DATE-1)%%7+1
    IF %OFFSET%0 LEQ 120 IF %OFFSET%0 GEQ -120 set /a DOW=ANSI_DATE%%7+1 


	echo Day of the week: %DOW%
endlocal
As the local offset could harm the result I've tried to take it into account too.But I should test the script around midnight to be sure that it works smile

On XP i couldn't find a way to get the ansi date with pure batch script.

Last edited by npocmaka (06 Sep 2013 15:21)
Post Reply