INT 21h AH=2Ch returns the time of day in four byte registers, all binary: the hour in CH, the minute in CL, the second in DH and hundredths of a second in DL. DOS does not run a clock of its own for this; it converts the BIOS tick count, the number of timer interrupts since midnight, which goes up 18.2 times a second.
MOV AH, 2Ch ; DOS: get the timeINT 21h ; CH = hour, CL = minute, DH = second, DL = 1/100 sPUSH DXPUSH CXMOV AL, CHCALL P2D1 ; the hourMOV DL, ":"MOV AH, 02h ; DOS: print the character in DLINT 21hPOP CXMOV AL, CLCALL P2D1 ; the minuteMOV DL, ":"MOV AH, 02h ; DOS: print the character in DLINT 21hPOP DXPUSH DXMOV AL, DHCALL P2D1 ; the secondMOV DL, "."MOV AH, 02h ; DOS: print the character in DLINT 21hPOP DXMOV AL, DLCALL P2D1 ; the hundredthsP2D1 PROC NEAR ; print AL (0-99) as two digitsAAM ; AH = AL / 10, AL = AL mod 10ADD AX, 3030h ; both digits to charactersPUSH AXMOV DL, AH ; the tensMOV AH, 02hINT 21hPOP DX ; DL = the unitsMOV AH, 02hINT 21hRETP2D1 ENDP
The hundredths are not exact to 1/100 s. The tick count changes every 55 ms, so DL moves in steps of 5 or 6, and two calls within one tick return the same time. Still, the second in DH is good enough to wait for, as here:
MOV AH, 2Ch ; DOS: get the timeINT 21hMOV BL, DH ; the current secondWAIT1:MOV AH, 2ChINT 21hCMP DH, BLJE WAIT1 ; until the next second beginsMOV DX, OFFSET MSG1MOV AH, 09h ; DOS: print the string at DS:DXINT 21hMSG1 DB "a new second has begun", 13, 10, "$"
To time something, read the time before and after, turn both into hundredths since midnight (((hours × 60 + minutes) × 60 + seconds) × 100 + hundredths, which needs 32 bits) and subtract. For intervals of less than a tick the BIOS tick count is no help either; the timer chip itself has to be read.
Pitfalls
At midnight the time wraps to 00:00:00.00 and the difference of two readings turns negative: add 24 hours when it does. The BIOS signals midnight with a flag DOS uses to advance its date, so read the time through DOS rather than with INT 1Ah AH=00h when the date matters. The real-time clock of an AT (INT 1Ah AH=02h) is a separate clock, in BCD, which DOS reads only at boot. DOSBox-X spends a little emulated time in each call on purpose: some games measure their speed by calling it in a loop.