回复 20楼 wmf2014
这个我也实作过了,但有限制的,好像是1970-2xxx,这个xxx记不起是什么,但不会是999这么大,我改用计算就是不爽这个限制,基本上计算并无限制,
公元到几万年都没问题。
另有一点, int 2ah/2ch这些日期函数,在dosbox或模拟器或freedos等系统不一定有作用,结果是让人气结,不如直接计算。
redate: ;本函数返回指定年、月份的天数,输入参数cx:年 dh:月,按int21h的2ah习惯给参数,天数从ax中返回 push bx push dx push si push di xor ax,ax mov al,dh mov di,ax mov bx,30 cmp di,2 jnz relp1 ;不是2月,按普通月份处理 mov bx,28 ;如是2月,则做闰年判断 xor dx,dx mov ax,cx mov si,400 div si or dx,dx jz relp2 ;能被400整除,是闰年 xor dx,dx mov ax,cx mov si,4 div si or dx,dx jnz relp1 ;不是闰年,按普通月份处理 mov ax,cx mov si,100 div si or dx,dx jnz relp2 ;不能被100整除,是闰年 relp1: cmp di,8 jb relp3 relp2: inc di ;闰年和大于7月份的月份处理 relp3: and di,1 mov ax,di add ax,bx pop di pop si pop dx pop bx ret
;程式功能:输入两个日期,计算两个日期相差天数 ;因用了invoke和local区域变量,须用masm6.x以后版本编译 ;编译方法: ml xxxx.asm ; .MODEL small,stdcall .data InputBuffer db 11,0,11 dup (0) FirstStr db 10,13,'Input First Date(dd/mm/yyyy):','$' SecondStr db 10,13,'Input Second Date(dd/mm/yyyy):','$' DayDiffStr db 10,13,'Difference:' DayDiffNum db 10 dup (20h) DaysStr db ' day(s)$' DaysStr_len equ $ - offset DaysStr UserTotaldate dd 0,0 InputCount dw 0 .stack 100h .code ;--------------------------------------------------------------------- ; ------ 主程式在后段,请由start: 开始阅读------------------ ;--------------------------------------------------------------------- ;输入月份,传回ax=该月天数,若输入不符(1-12之外),cf=1 GetmonthDay proc near GiveMonth:word ;(1-12) push bx mov bx,GiveMonth dec bx cmp bx,11 ja GetMdxErr mov ax,28 cmp bx,1 ;是否2月 jz GetMDok ;是 cmp bx,6 ;少于等于7月 jbe GetMD10 inc bx ;大于7月加1 GetMD10:mov ax,30 test bx,1 jnz GetMDok ;奇数不加ax=30 inc ax ;偶数加1,ax=31 GetMDok:clc ;ax=月份天数 jmp short GetMDxErrx GetMDxErr: stc GetMDxErrx: pop bx ret GetmonthDay endp ;------------------------------------------------------------------- GetTotalDay proc near xyear:word,xmonth:word,xday:word local TotalHi,TotalLo,LLyear:word ;区域变量(32bit总天数),闰月调整(0或1) xor ax,ax mov word ptr TotalLo,ax ;初始化 mov word ptr TotalHi,ax ;初始化 mov word ptr LLyear,ax ;初始化 mov ax,xyear ;取年份 call LeapYear ;输入AX=年份,输出AX=1(闰年),AX=0(非闰年) or ax,ax jz GetTDA mov word ptr LLyear,1 GetTDA:mov di,xyear ;取年份 GetTD0:cmp di,1000 ;和基准1000比较 ja GetTD3 ;大于 jz GetTD4 ;等于,则不处理输入年份和1000的相差 ; di = less then 1000 mov si,+1 ;预设加 mov ax,di ;取得输入年份 GetTD1:call LeapYear ;是否闰年 mov bx,365 ;一年多少天 or ax,ax ;是否闰年? jz GetTD2 ;不是 inc bx ;是闰年,365+1 GetTD2: add word ptr TotalLo,bx ;加总日期 adc word ptr TotalHi,0 ;带进位加 add di,si ;输入年份 加或减1 , 用以接近1000 jmp short GetTD0 GetTD3: ;大于1000到此 lea ax,[di-1] ;本年不计,取前一年值,若di=2017,lea ax,[di-1]后, ax=2016 mov si,-1; ;预设减,, 用以接近1000 jmp short GetTD1 ;回去计算闰年 GetTD4: ;得该年和1000/1/1相差年日数 ;取得第一输入年月日,且已计算 和1000/1/1相差年日数 mov dx,1 ;以下计算该年总天数 xor ax,ax xor si,si mov dx,1 ;由1月起 cmp xmonth,dx ;输入月份是否1月 jz GetTD7 ;是 GetTD5:cmp dx,xmonth jae GetTD7 invoke GetmonthDay, dx ;以月份(dx)查找该月天数 cmp dx,2 ;是否2月 jnz GetTD6 ;不是 add ax,LLyear ;若闰月调整 28->29 GetTD6:add si,ax ;累加 inc dx ;下一月 jmp short GetTD5 GetTD7:mov ax,si ;取加总 add ax,xday ;加上输入天数 ;得该年总天数 add word ptr TotalLo,ax ;加总日期 adc word ptr TotalHi,0 ;带进位加 mov dx,TotalHi mov ax,TotalLo ;总天数由dx:ax传回 ret GetTotalDay endp ;-------------------------------------------------------------------------- ;转值子程序,把输入的10进制文字转成16进制 ;输入:ds:si数字字符串起点,以0dh结束 ;输出:ax=转换后的16进制值,cf=1表示有非数字字符 GetValue: push bx push di xor bx,bx mov di,10 GetV10:lodsb ;指向起点 mov ah,0 ;清除 ;cmp al,0 ;0dh ;回车? cmp al,0 ;-----zero jz Getvx cmp al,'0' ;以下比较0-9,否则cf=1离开 jb Getvy cmp al,'9' ja Getvy sub al,'0' ;ascii -> 值 xchg bx,ax ;交换 mul di add bx,ax ;累加 jmp short GetV10 Getvx: mov ax,bx ;ascii转值后由ax转回 clc ;成功cf=0 jmp short Getvz Getvy: stc ;错误 cf=1 Getvz: pop di pop bx ret ;------------------------------------ ;以下程序送出dx:ax的32bit结果到di,也可改成印出 ;output DX:AX,dword (0-FFFFFFFFh / 0-4294967295) print_dec: xor cx,cx xchg bp,dx mov si,10 ;div by 10 mov bx,30h print_dec1: or bp,bp jz print_dec3 xchg bp,ax xor dx,dx div si xchg bp,ax div si or dl,bl push dx inc cx jmp short print_dec1 print_dec3: xor dx,dx div si or dl,bl push dx inc cx or ax,ax jnz print_dec3 print_dec4: pop ax stosb loop print_dec4 ret ;-------------------------------------------------------------- GetDate proc near BufferAdd:word local Uyear,Umonth,Uday,LimitDay,splitCount,LYear:word local UserInputAddress[4]:word mov word ptr splitCount,0 ; [/]数目初始化 mov word ptr LYear,0 ;闰年初始化 mov dx,BufferAdd mov di,dx mov ax,0C0Ah int 21h add di,2 ;指向字串符位置 xor cx,cx mov cl,[di-1] ;取实际输入数 mov bx,cx or cx,cx jnz okinput mov ax,0 ;没有输入 jmp short GetdataXX GetdataX: mov ax,-1 ;错误输入 GetdataXX: stc ret okinput: mov byte ptr [di+bx],0 ;0dH ->0 mov al,'/' ;分隔符 lea bx,UserInputAddress retry: repnz scasb jnz NotFound mov ss:[bx],di mov byte ptr [di-1],0 ;清除分隔符 inc splitCount ;加分隔符数目 add bx,2 ;下一地址 or cx,cx ;完了? jnz retry ;没 NotFound: cmp splitCount,2 ;只容许2个[/]分隔符 jnz GetdataX ;不符 mov si, UserInputAddress[2] ;取年 call GetValue ;取值 cmp ax,4000 ;以下比较限制1000-4000 ja GetdataX cmp ax,1000 jb GetdataX mov Uyear,ax ;存 mov si,UserInputAddress[0] ;取月 call GetValue ;传回AX(月) mov Umonth,ax ;存 invoke GetmonthDay,ax ;取该月天数限制 jc GetdataX ;不符(1-12) mov LimitDay,ax ;存天数限制 mov si,BufferAdd add si,2 ;指向日期 call GetValue ;取值 mov Uday,ax ;存输入日期 mov ax,Uyear ;取输入年份 Call LeapYear ;计算是否闰年子程序,传回1表示闰年,0表示非闰年 or ax,ax ;是闰年不? jz GetTD ;不是闰年 mov word ptr LYear,1 ;闰年 cmp Umonth,2 ;二月? jnz GetTD ; 不是二月 inc LimitDay ;闰年,2月份的限制+1 GetTD: mov ax,Uday ;使用者输入日期 cmp ax,LimitDay ;比较输入日期和该月份天数限制 ja GetdataX ;输入日期大于月份限制, 再输入 clc ;所有日期输入正常 mov ax,Uyear ;传回年 mov bx,Umonth ;传回月 mov cx,Uday ;传回日 mov dx,LYear ;闰年与否...0=不是,1=是 ret GetDate endp ;------------------------------------------------------------------- LeapYear: ;输入AX=年份,输出AX=1(闰年),AX=0(非闰年) push bx push dx push si mov si,ax mov bx,400 ;年份除以400余数等于零,为闰年 mov dx,0 div bx or dx,dx ;是否0 jz last ;余数为零,直接输出闰年 mov dx,0 mov bx,4 ;除以400余数不等于0,进行除以4余数是否等0的判断 mov ax,si div bx or dx,dx ;是否0 jz ok ;除以四余数等于0,跳往除以100余数是否等0的判断 over: ;除以四余数不等于0,则不为闰年,结束 mov ax,0 ;不是闰年 jmp nil ok: mov bx,100 ;除以100余数为零,则不为闰年,余数不为零,则为闰年 mov dx,0 mov ax,si div bx or dx,dx ;是否0 jz over last: mov ax,1 ;闰年 nil: pop si pop dx pop bx ret ;---------------------------------------------------------------------------- ;--------------------------主程式----------------------------------------- ;---------------------------------------------------------------------------- start: MOV AX,@DATA MOV DS,AX MOV ES,AX cld ;正向 ;-------------输入/测试开始------------------------------------------------ mov inputCount,0 ;初始化 TryInput: cmp inputCount,0 ;根据inputCount决定显示第1/第2字符串 lea dx,FirstStr jz Whoinput lea dx,SecondStr Whoinput: mov ah,9 int 21h lea si,InputBuffer ;输入缓冲,要求输入格式(dd/mm/yyyy) invoke GetDate,si ;读取输入子程序,传回ax(年),bx(月),cx(日),dx(闰年) jnc Nextin ;正常 or ax,ax ;没有输入 jz quit ;离开 jmp short TryInput ;输入错误 Nextin: invoke GetTotalDay,ax,bx,cx ;输入年,月,日....传回dx:ax=总天数 (由输入日期至1000/1/1) mov bx,inputCount shl bx,1 ; x 2 shl bx,1 ; x 4 mov word ptr UserTotaldate[bx],ax ;根据inputCount存入总天数 mov word ptr UserTotaldate[bx+2],dx inc inputCount ;next input ? cmp inputCount,2 jb TryInput ;second输入 ;-------------输入/测试完成------------------------------------------------ mov ax,word ptr UserTotaldate mov dx,word ptr UserTotaldate+2 ;取第1输入值入:dx:ax mov bx,word ptr UserTotaldate+4 mov cx,word ptr UserTotaldate+6 ;取第2输入值入:cx:bx cmp dx,cx ;比较高位 ja noChg ;大于 jb xxchg ;少于 ;-- 32高位相等 cmp ax,bx ;比较低位 jae noChg ;大于等于不交换 xxchg: xchg ax,bx ;少于则交换 xchg dx,cx noChg: sub ax,bx sbb dx,cx mov di,offset DayDiffNum Call print_dec ; 输出结果至字符串 mov si,offset DaysStr mov cx,DaysStr_len rep movsb mov dx,offset DayDiffStr ;印结果 mov ah,9 int 21h mov ah,7 ;暂停 int 21h quit: mov ax,4c00h ;离开 int 21h ;-------------------------------------------------------------------------- end start
[此贴子已经被作者于2016-7-3 11:25编辑过]