注册 登录
编程论坛 VFP论坛

请教下各位大大:有没有体育项目秒表时间的加减算法?

shonken 发布于 2022-07-07 20:30, 3750 次点击
近期想设计个体育项目时间成绩的小工具,秒表成绩一般为:时:分:秒.999,根据运动员的表现增减时间,这个增减可能是毫秒,也可能是秒或其他

示例:0:10:10.123    +  1.123             = 0:10:11.246
          0:10:10.123    +  1:1.123        = 0:11:11.246
          0:10:10.123    +  1:1:1.123   = 1:11:11.246

          1:10:10.123    -  1.124             = 1:10:09.998
          1:10:10.123    -  11:1.124      = 1:09:59.998

计划做成函数应该是:函数名(当前成绩,"+1.123"),函数名(当前成绩,"-  1.124")

不知各位有什么好办法实现这个时间的运算?
36 回复
#2
sdta2022-07-07 21:00
         1:10:10.123    -  1.124             = 1:10:09.998
          1:10:10.123    -  11:1.124      = 1:09:59.998
上面两个结果看不明白

[此贴子已经被作者于2022-7-7 21:11编辑过]

#3
sdta2022-07-07 21:20
CLEAR
t1 = "0:10:10.123"
t2 = "+1:1.123"
?ALINES(a1, t1, 5, ":", ".")
LIST MEMORY LIKE a1
?ALINES(a2, t2, 5, "+", ":", ".")
LIST MEMORY LIKE a2
#4
shonken2022-07-07 21:28
以下是引用sdta在2022-7-7 21:00:28的发言:

         1:10:10.123    -  1.124             = 1:10:09.998
          1:10:10.123    -  11:1.124      = 1:09:59.998
上面两个结果看不明白

设想这样也不知是否正确,即毫秒十进制,秒和分是60进制,小时是24进制
#5
sdta2022-07-07 21:38
1秒=1000毫秒
#6
my23182022-07-07 21:40
内部运算时全部用几点几秒表示,输出输入结果用几小时:几分:几.几秒表示,写一个输出转换函数和一个输入转换函数,这两个函数比较简单,自己写一下就好了。
#7
csyx2022-07-07 22:53
你只需要从传入参数中分解出时、分、秒、毫秒的值,加减运算交给vfp去处理,例如:
datetime(1900,1,2,3,4,5)    结果是 1900-01-02 3:04:05
datetime(1900,1,2,3,4,5)+6  结果是 1900-01-02 3:04:11
ttoc(datetime(1900,1,2,3,4,5)+6, 2)  结果是 3:04:11
你对毫秒进行些处理即可
#8
shonken2022-07-08 09:30
以下是引用csyx在2022-7-7 22:53:52的发言:

你只需要从传入参数中分解出时、分、秒、毫秒的值,加减运算交给vfp去处理,例如:
datetime(1900,1,2,3,4,5)    结果是 1900-01-02 3:04:05
datetime(1900,1,2,3,4,5)+6  结果是 1900-01-02 3:04:11
ttoc(datetime(1900,1,2,3,4,5)+6, 2)  结果是 3:04:11
你对毫秒进行些处理即可


我也是想通过日期时间来处理,谢谢你提供具体方法
#9
mywisdom882022-07-08 10:19
楼主是想这样
HH:MM:SS.SSS的格式显示,加减也是按照HH:MM:SS.SSS的格式

你先这样,标准化你的参数,其他的,就容易了
HMSX = "1:2.1234"

*!* 取HHMMSS.SSS的.后面的前面3位
SSS = SUBSTR(IIF(RAT(".",HMSX)>0,SUBSTR(HMSX,RAT(".",HMSX)+1),"000"),1,3)

*!* 分别取HHMMSS中的SS,MM,HH
HMS = IIF(RAT(".",HMSX)=0,HMSX,SUBSTR(HMSX,1,RAT(".",HMSX)-1))
HMS = CHRTRAN(HMS,".","") && 防止HMS中还有"点"
SS = PADL(SUBSTR(IIF(RAT(":",HMS)>0,SUBSTR(HMS,RAT(":",HMS)+1),HMS),1,2),2,"0")
HM = IIF(RAT(":",HMS)=0,"00",SUBSTR(HMS,1,RAT(":",HMS)-1))
MM = PADL(SUBSTR(IIF(RAT(":",HM)>0,SUBSTR(HM,RAT(":",HM)+1),HM),1,2),2,"0")
HH = PADL(SUBSTR(IIF(RAT(":",HM)=0,"00",SUBSTR(HM,1,RAT(":",HM)-1)),1,2),2,"0")

?"前=",HMSX
?"后="+HH+";"+MM+";"+SS+"."+SSS
#10
mywisdom882022-07-08 10:34
经过上面标准化你参数后,你就可以,这样写个函数
函数名("当前成绩","+/-","修改数值")
#11
吹水佬2022-07-08 10:54
看似是时间加减运算,要求精确到1/1000秒(毫秒),结果用时间格式显示。
#12
shonken2022-07-08 12:39
以下是引用mywisdom88在2022-7-8 10:19:33的发言:

楼主是想这样
HH:MM:SS.SSS的格式显示,加减也是按照HH:MM:SS.SSS的格式

你先这样,标准化你的参数,其他的,就容易了
HMSX = "1:2.1234"

*!* 取HHMMSS.SSS的.后面的前面3位
SSS = SUBSTR(IIF(RAT(".",HMSX)>0,SUBSTR(HMSX,RAT(".",HMSX)+1),"000"),1,3)

*!* 分别取HHMMSS中的SS,MM,HH
HMS = IIF(RAT(".",HMSX)=0,HMSX,SUBSTR(HMSX,1,RAT(".",HMSX)-1))
HMS = CHRTRAN(HMS,".","") && 防止HMS中还有"点"
SS = PADL(SUBSTR(IIF(RAT(":",HMS)>0,SUBSTR(HMS,RAT(":",HMS)+1),HMS),1,2),2,"0")
HM = IIF(RAT(":",HMS)=0,"00",SUBSTR(HMS,1,RAT(":",HMS)-1))
MM = PADL(SUBSTR(IIF(RAT(":",HM)>0,SUBSTR(HM,RAT(":",HM)+1),HM),1,2),2,"0")
HH = PADL(SUBSTR(IIF(RAT(":",HM)=0,"00",SUBSTR(HM,1,RAT(":",HM)-1)),1,2),2,"0")

?"前=",HMSX
?"后="+HH+";"+MM+";"+SS+"."+SSS

是的是的,标准化字符串好重要,就怕用户乱输入,谢谢你提供代码
#13
shonken2022-07-08 12:40
以下是引用吹水佬在2022-7-8 10:54:08的发言:

看似是时间加减运算,要求精确到1/1000秒(毫秒),结果用时间格式显示。

是的,吹版
#14
csyx2022-07-08 12:44
录入不用要求太标准

程序代码:
*-- 测试样例
? 秒表('0:10:10.123', '1.123')
? 秒表('0:10:10.123', '+1.123')
? 秒表('10:10.123', 1.123)
? 秒表('1:10:10.123', -1.124)
? 秒表('1:10:10.123', '-11:1.124')     && 0:59:08.999 与你要的结果不同
? 秒表('0:59:08.999', '+11:1.124') == '1:10:10.123'
*-- end of 测试样例

*-- 秒表运算函数
Function 秒表(v1, v2)
    Local oo
    oo = NewObject('秒表')
    oo.值 = v1
    Return oo.加减(v2)
Endfunc
*-- 秒表类
Define Class 秒表 As Custom
    时 = 0
    分 = 0
    秒 = 0
    毫 = 0
    值 = ''

    Procedure 值_Assign
        Lparameters tcTime
        Local tm, ms

        tm = Ltrim(Alltrim(GetWordNum(tcTime, 1, '.')), '-')
        ms = GetWordNum(tcTime, 2, '.')
        Do Case
        Case Occurs(':', tm) = 0
            tm = '0:0:' + tm
        Case Occurs(':', tm) = 1
            tm = '0:' + tm
        Otherwise
            *-- 啥也不干
        Endcase
        This.时 = Cast(GetWordNum(tm, 1, ':') As I)
        This.分 = Cast(GetWordNum(tm, 2, ':') As I)
        This.秒 = Cast(GetWordNum(tm, 3, ':') As I)
        This.毫 = Cast(ms As I)
    EndProc

    Procedure 加减
        Lparameters tv增量
        Local oo, ss, tt, ms

        tv增量 = Iif(Vartype(tv增量) == 'N', Transform(tv增量), Alltrim(tv增量))
        oo = NewObject('秒表')
        oo.值 = tv增量
        ss = oo.时 * 3600 + oo.分 * 60 + oo.秒
        If Left(tv增量, 1) == '-'
            tt = Datetime(2000,1,1, This.时, This.分, This.秒) - ss
            ms = This.毫 - oo.毫
            If ms < 0
                tt = tt - 1
                ms = ms + 1000
            Endif
        Else
            tt = Datetime(2000,1,1, This.时, This.分, This.秒) + ss
            ms = This.毫 + oo.毫
            If ms > 999
                tt = tt + 1
                ms = ms - 1000
            EndIf
        EndIf
        Return Ttoc(tt, 2) + '.' + Padl(ms, 3, '0')
    EndProc
EndDefine


[此贴子已经被作者于2022-7-8 12:47编辑过]

#15
shonken2022-07-08 12:46
平常输入除了完整格式HH:MM:SS.SSS外,为加快输入效率,设定如:+1.123、+1.11.123、-11:1.123、-0.123 。这样的输入格式?

[此贴子已经被作者于2022-7-8 13:26编辑过]

#16
shonken2022-07-08 13:07
太感谢了,稍变动下就可以实际应用了,谢谢你

以下是引用csyx在2022-7-8 12:44:04的发言:

录入不用要求太标准

*-- 测试样例
? 秒表('0:10:10.123', '1.123')
? 秒表('0:10:10.123', '+1.123')
? 秒表('10:10.123', 1.123)
? 秒表('1:10:10.123', -1.124)
? 秒表('1:10:10.123', '-11:1.124')     && 0:59:08.999 与你要的结果不同
? 秒表('0:59:08.999', '+11:1.124') == '1:10:10.123'
*-- end of 测试样例

*-- 秒表运算函数
Function 秒表(v1, v2)
    Local oo
    oo = NewObject('秒表')
    oo.值 = v1
    Return oo.加减(v2)
Endfunc
*-- 秒表类
Define Class 秒表 As Custom
    时 = 0
    分 = 0
    秒 = 0
    毫 = 0
    值 = ''

    Procedure 值_Assign
        Lparameters tcTime
        Local tm, ms

        tm = Ltrim(Alltrim(GetWordNum(tcTime, 1, '.')), '-')
        ms = GetWordNum(tcTime, 2, '.')
        Do Case
        Case Occurs(':', tm) = 0
            tm = '0:0:' + tm
        Case Occurs(':', tm) = 1
            tm = '0:' + tm
        Otherwise
            *-- 啥也不干
        Endcase
        This.时 = Cast(GetWordNum(tm, 1, ':') As I)
        This.分 = Cast(GetWordNum(tm, 2, ':') As I)
        This.秒 = Cast(GetWordNum(tm, 3, ':') As I)
        This.毫 = Cast(ms As I)
    EndProc

    Procedure 加减
        Lparameters tv增量
        Local oo, ss, tt, ms

        tv增量 = Iif(Vartype(tv增量) == 'N', Transform(tv增量), Alltrim(tv增量))
        oo = NewObject('秒表')
        oo.值 = tv增量
        ss = oo.时 * 3600 + oo.分 * 60 + oo.秒
        If Left(tv增量, 1) == '-'
            tt = Datetime(2000,1,1, This.时, This.分, This.秒) - ss
            ms = This.毫 - oo.毫
            If ms < 0
                tt = tt - 1
                ms = ms + 1000
            Endif
        Else
            tt = Datetime(2000,1,1, This.时, This.分, This.秒) + ss
            ms = This.毫 + oo.毫
            If ms > 999
                tt = tt + 1
                ms = ms - 1000
            EndIf
        EndIf
        Return Ttoc(tt, 2) + '.' + Padl(ms, 3, '0')
    EndProc
EndDefine

#17
csyx2022-07-08 14:01
正式应用确实还有很多需要考虑的问题,光是容错就够折腾的,例如:
1. 录入数据包含全角字符
2. 时间分隔符(冒号)多于 2
3. 加减数大于被操作数:秒表('12.345', -13.678)
4. 1:67:89
...
当然也不能用于巴黎达喀尔拉力赛这种距离上万时间半月的比赛,时间差大于24小时的都没考虑


[此贴子已经被作者于2022-7-8 14:03编辑过]

#18
shonken2022-07-08 14:42
这正是我需要考虑的,有些比赛是跨天的
当时跨天玩100KM没怎么累,就是犯困.....

以下是引用csyx在2022-7-8 14:01:34的发言:

正式应用确实还有很多需要考虑的问题,光是容错就够折腾的,例如:
1. 录入数据包含全角字符
2. 时间分隔符(冒号)多于 2
3. 加减数大于被操作数:秒表('12.345', -13.678)
4. 1:67:89
...
当然也不能用于巴黎达喀尔拉力赛这种距离上万时间半月的比赛,时间差大于24小时的都没考虑

#19
吹水佬2022-07-08 14:58
不知有无理解错,觉得先要定义这个“时间”的含义
如果是时点,如“+”时间是时点之后,“-”时间是时点之前。
如:3时+20时==>23时;3时+21时==>0时;3时-3时==>0时;3时-4时==>23时
如果是时间累计是时差累计
如:3个小时+21个小时==24个小时;3个小时-4个小时==-1个小时
#20
shonken2022-07-08 15:22
吹版,跟csyx说的差不多,平时应用类似这样
*-- 测试样例
? 秒表('0:10:10.123', '1.123')
? 秒表('0:10:10.123', '+1.123')
? 秒表('10:10.123', 1.123)
? 秒表('1:10:10.123', -1.124)
? 秒表('1:10:10.123', '-11:1.124')     && 0:59:08.999 与你要的结果不同
? 秒表('0:59:08.999', '+11:1.124') == '1:10:10.123


以下是引用吹水佬在2022-7-8 14:58:09的发言:

不知有无理解错,觉得先要定义这个“时间”的含义
如果是时点,如“+”时间是时点之后,“-”时间是时点之前。
如:3时+20时==>23时;3时+21时==>0时;3时-3时==>0时;3时-4时==>23时
如果是时间累计是时差累计
如:3个小时+21个小时==24个小时;3个小时-4个小时==-1个小时

#21
吹水佬2022-07-08 15:53
以下是引用shonken在2022-7-8 15:22:10的发言:

吹版,跟csyx说的差不多,平时应用类似这样
*-- 测试样例
? 秒表('0:10:10.123', '1.123')
? 秒表('0:10:10.123', '+1.123')
? 秒表('10:10.123', 1.123)
? 秒表('1:10:10.123', -1.124)
? 秒表('1:10:10.123', '-11:1.124')     && 0:59:08.999 与你要的结果不同
? 秒表('0:59:08.999', '+11:1.124') == '1:10:10.123

结果看似时点数
试试:
? 秒表('3:00:00', '-4:00:00')
? 秒表('3:00:00', '+21:00:00')
是你想要的结果吗?
#22
shonken2022-07-08 16:34
*-- 测试样例
? 秒表('0:10:10.123', '1.123')=>00:10:11.246

? 秒表('0:10:10.123', '+1.123')=>00:10:11.246

? 秒表('10:10.123', 1.123)=>00:10:11.246

? 秒表('1:10:10.123', -1.124)=>01:10:08.999

? 秒表('1:10:10.123', '-11:1.124') =>00:59:08.999

? 秒表('0:59:08.999', '+11:1.124') =>1:10:10.123

不单单是小时数的增减,天、时、分、秒、毫秒都要加减运算

以下是引用吹水佬在2022-7-8 15:53:12的发言:


结果看似时点数
试试:
? 秒表('3:00:00', '-4:00:00')
? 秒表('3:00:00', '+21:00:00')
是你想要的结果吗?



[此贴子已经被作者于2022-7-8 16:40编辑过]

#23
吹水佬2022-07-08 16:54
以下是引用shonken在2022-7-8 16:34:06的发言:
不单单是小时数的增减,天、时、分、秒、毫秒都要加减运算

所以,不只是time的问题,是datetime的问题吧?
in/out格式"hh:mm:ss"可能达不到要求
最好将问题要求详细点说说,对日期、时间有什么限制,例举最好能涉及问题所在。


[此贴子已经被作者于2022-7-8 16:55编辑过]

#24
a575985872022-07-08 21:50
抛砖引玉请大侠指导:
程序代码:
cc10 = ThisForm.Text1.Value && 时:分:秒.微秒 格式
cc10 ="01:01:01.123"

*?OCCURS(":",cc10)
cc11 = REPLICATE ("0:",2-OCCURS(":",cc10))-cc10

?cc11
*ALINES(sj1, cc11, 5, ":", ".")
ALINES(sj1, cc11, 5, ".")
?sj1[1]
?sj1[2]
sj101 = CTOT(sj1[1])-CTOT("0:0:0")
sj102 = INT(val(sj1[2]))

?"秒",sj101,"微秒", sj102

?"================"

cc20 = ThisForm.Text2.Value && 时:分:秒.微秒 格式

cc20 =  "01.223"
*?OCCURS(":",cc10)
cc21 = REPLICATE ("0:",2-OCCURS(":",cc20))-cc20

?cc21
*ALINES(sj1, cc11, 5, ":", ".")
ALINES(sj2, cc21, 5, ".")
?sj2[1]
?sj2[2]
sj201 = CTOT(sj2[1])-CTOT("0:0:0")
sj202 = INT(val(sj2[2]))

?"秒",sj201,"微秒", sj202

?"================增加"&&同理可做减少代码
IF sj102+sj202>=1000
    sj31 =sj101 +sj201+1
    sj32 = sj202+sj102 -1000

ELSE
    sj31 =sj101 +sj201
    sj32 = sj202+sj102
ENDIF
?"成绩:",sj31,"秒",sj32,"微秒"

sj41=CTOT("0:0:0")+sj31
?HOUR(sj41)
?MINUTE(sj41)
?SEC(sj41)
?sj32

?"成绩显示:",STR(HOUR(sj41),2,0)+":"+STR(MINUTE(sj41),2,0)+":"+STR(SEC(sj41),2,0)+"."+STR(sj32,3,0)
#25
mywisdom882022-07-09 01:25
楼主的问题,处理后的结果,可以大于24小时,但不能小于0
#26
a575985872022-07-09 06:27
回复 25楼 mywisdom88
这个是体育测试,应该不会大于24小时吧? 第二步的加或减应该是对成绩的校正
#27
shonken2022-07-09 10:06
mywisdom88版主理解正确,体育项目一般都是以增加时间为主,一些长时间的项目会跨天,如我上面说的100KM越野,清早5点出发,好多人完赛都要隔天的中午了,跨度十几小时至三十小时不等。也有些体育项目会轻微的减少时间作为奖励,一般是减少分、秒、毫秒。

以下是引用mywisdom88在2022-7-9 01:25:06的发言:

楼主的问题,处理后的结果,可以大于24小时,但不能小于0

#28
shonken2022-07-09 10:14
谢谢你的思路

以下是引用a57598587在2022-7-8 21:50:01的发言:

抛砖引玉请大侠指导:
cc10 = ThisForm.Text1.Value && 时:分:秒.微秒 格式
cc10 ="01:01:01.123"

*?OCCURS(":",cc10)
cc11 = REPLICATE ("0:",2-OCCURS(":",cc10))-cc10

?cc11
*ALINES(sj1, cc11, 5, ":", ".")
ALINES(sj1, cc11, 5, ".")
?sj1[1]
?sj1[2]
sj101 = CTOT(sj1[1])-CTOT("0:0:0")
sj102 = INT(val(sj1[2]))

?"秒",sj101,"微秒", sj102

?"================"

cc20 = ThisForm.Text2.Value && 时:分:秒.微秒 格式

cc20 =  "01.223"
*?OCCURS(":",cc10)
cc21 = REPLICATE ("0:",2-OCCURS(":",cc20))-cc20

?cc21
*ALINES(sj1, cc11, 5, ":", ".")
ALINES(sj2, cc21, 5, ".")
?sj2[1]
?sj2[2]
sj201 = CTOT(sj2[1])-CTOT("0:0:0")
sj202 = INT(val(sj2[2]))

?"秒",sj201,"微秒", sj202

?"================增加"&&同理可做减少代码
IF sj102+sj202>=1000
    sj31 =sj101 +sj201+1
    sj32 = sj202+sj102 -1000

ELSE
    sj31 =sj101 +sj201
    sj32 = sj202+sj102
ENDIF
?"成绩:",sj31,"秒",sj32,"微秒"

sj41=CTOT("0:0:0")+sj31
?HOUR(sj41)
?MINUTE(sj41)
?SEC(sj41)
?sj32

?"成绩显示:",STR(HOUR(sj41),2,0)+":"+STR(MINUTE(sj41),2,0)+":"+STR(SEC(sj41),2,0)+"."+STR(sj32,3,0)

#29
吹水佬2022-07-09 11:10
程序代码:

DECLARE long time      IN msvcrt as apiTime
DECLARE long localtime IN msvcrt as apiLocaltime long@
nt = apiTime()
? addDatetime(nt, 0)                    && 当前日期时间
? addDatetime(nt, 3600*24+3600+60+1)    && 加1日1小时1分1秒
? addDatetime(nt, -3600*24-3600-60-1)   && 减1日1小时1分1秒
CLEAR ALL
RETURN

FUNCTION addDatetime(nt, num)
    nt = nt + num
    ptm = apiLocaltime(@nt)
    RETURN PADL(CTOBIN(SYS(2600,ptm+20,4),"4RS")+1900, 4, "0")+"-"+;
           PADL(CTOBIN(SYS(2600,ptm+16,4),"4RS")+1,    2, "0")+"-"+;
           PADL(CTOBIN(SYS(2600,ptm+12,4),"4RS"),      2, "0")+" "+;
           PADL(CTOBIN(SYS(2600,ptm+8, 4),"4RS"),      2, "0")+":"+;
           PADL(CTOBIN(SYS(2600,ptm+4, 4),"4RS"),      2, "0")+":"+;
           PADL(CTOBIN(SYS(2600,ptm,   4),"4RS"),      2, "0")
ENDFUNC
#30
shonken2022-07-09 12:27
交功课,主要借鉴csyx的代码为主,加上些实际应用,没用类的方式

程序代码:

Clear
? x_秒表加减('0:10:10.123', '1.123')
? x_秒表加减('0:10:10.123', '+1.123')
? x_秒表加减('10:10.123', 1.123)
? x_秒表加减('1:10:10.123', -1.124)
? x_秒表加减('1:10:10.123', '-11:1.124')
? x_秒表加减('2022-07-09T23:59:08.999', '+11:1.124')
? x_秒表加减('2000-01-01T00:10:11.123','1.123')
? x_秒表加减(x_秒表加减(x_秒表加减('0', 1.123), '+11:1.124'), '-1.124')
Function x_秒表加减
    Lparameters lcValue1,lcValue2
    lcValue2 = Iif(Vartype(lcValue2) == 'N', Transform(lcValue2), Alltrim(lcValue2))
    Local ArTime1,ArTime2,LnSs, LnTt, LnMs, LnY, LnM, LnD
    Dimension ArTime1[4],ArTime2[4]
    ArTime1=x_formatTime(lcValue1)&&格式化输入数据,并装入数组
    ArTime2=x_formatTime(lcValue2)
    If Vartype(ArTime1)="L" Or Vartype(ArTime2)="L"
        Return .F.
    Endif
    LnY = Year(Date())
    LnM = Month(Date())
    LnD = Day(Date())
    LnSs = ArTime2[1] * 3600 + ArTime2[2] * 60 + ArTime2[3]
    If Left(lcValue2, 1) == '-'
        LnTt = Datetime(LnY,LnM,LnD, ArTime1[1], ArTime1[2], ArTime1[3]) - LnSs
        LnMs = ArTime1[4] - ArTime2[4]
        If LnMs < 0
            LnTt = LnTt - 1
            LnMs = LnMs + 1000
        Endif
    Else
        LnTt = Datetime(LnY,LnM,LnD, ArTime1[1], ArTime1[2], ArTime1[3]) + LnSs
        LnMs = ArTime1[4] + ArTime2[4]
        If LnMs > 999
            LnTt = LnTt + 1
            LnMs = LnMs - 1000
        Endif
    Endif
    Return Ttoc(LnTt, 3) + '.' + Padl(LnMs, 3, '0')
Endfunc

Function x_formatTime
    Lparameters tcTime
    If Occurs("T",tcTime)>0
        If Ctod(Getwordnum(tcTime, 1, 'T'))<Date()
            Messagebox("日期数据不能小于当时日期",16+0,"停止")
            Return .F.
        Else
            tcTime = Getwordnum(tcTime, 2, 'T')
        Endif
    Endif
    If Occurs(".",tcTime)>1 Or Occurs(":",tcTime)>2 Or Occurs("-",tcTime)>1 Or Occurs("+",tcTime)>1 Or Occurs("+-",tcTime)>0 Or Occurs("-+",tcTime)>0
        Messagebox("输入数据格式错误",16+0,"停止")
        Return .F.
    Endif
    lcTm = Ltrim(Alltrim(Getwordnum(tcTime, 1, '.')), '-')
    lcTm = Ltrim(lcTm, '+')
    lcTm = Replicate ("0:",2-Occurs(":",lcTm))+lcTm
    lcMs = Getwordnum(tcTime, 2, '.')
    Publ ArTime
    Dimension ArTime[4]
    ArTime[1] = Cast(Getwordnum(LcTm, 1, ':') As I)
    ArTime[2] = Cast(Getwordnum(LcTm, 2, ':') As I)
    ArTime[3] = Cast(Getwordnum(LcTm, 3, ':') As I)
    ArTime[4] = Cast(LcMs As I)
    Return @ArTime
Endfunc


[此贴子已经被作者于2022-7-9 15:06编辑过]

#31
吹水佬2022-07-09 14:33
回复 30楼 shonken
校对了一下好象有点问题
试试:
? x_秒表加减('2022-07-09T23:59:08.999', '+11:1.124')  && 输出 2022-07-10T01:49:10.123
或简化点:
? x_秒表加减('2022-07-09T23:59:00', '+1:00')  && 输出 2022-07-10T00:09:00.000
#32
shonken2022-07-09 15:06
谢谢校对
    LnSs = ArTime2[1] * 3600 + ArTime2[2] * 60 + ArTime2[3]
这句60,写成600

以下是引用吹水佬在2022-7-9 14:33:27的发言:

校对了一下好象有点问题
试试:
? x_秒表加减('2022-07-09T23:59:08.999', '+11:1.124')  && 输出 2022-07-10T01:49:10.123
或简化点:
? x_秒表加减('2022-07-09T23:59:00', '+1:00')  && 输出 2022-07-10T00:09:00.000

#33
mywisdom882022-07-10 00:43
土方法,硬拼

CLEAR
c当前 = "32:20:9.419"
c加减 = "-1:8.412"
?c当前
?c加减
?秒表(c当前,c加减)

FUNCTION 秒表(c当前成绩,c加减成绩)
LOCAL c加减,c变动成绩
c当前成绩 = 标准格式(c当前成绩)

IF  OCCURS(".",c加减成绩) > 1
    MESSAGEBOX("加减成绩格式错误,最少包含2个“.”以上!",48,"提示")
    RETURN c当前成绩
ELSE
  
   c加减 = SUBSTR(c加减成绩,1,1)
   
   IF c加减 = "-" && 第一个字符是 -
      c变动成绩 = SUBSTR(c加减成绩,2)
      c变动成绩 = 标准格式(c变动成绩)
      RETURN 减少加时间(c当前成绩,c变动成绩)
   ELSE
      IF INLIST(c加减 , "+" ,":") && 第一个字符是 +或者:
         c变动成绩 = SUBSTR(c加减成绩,2)
      ELSE
         c变动成绩 = c加减成绩
      ENDIF
      c变动成绩 = 标准格式(c变动成绩)
      RETURN 增加时间(c当前成绩,c变动成绩)
   ENDIF
ENDIF   

ENDFUNC

FUNCTION 标准格式(HMSX)
*!* 标准格式 HH:MM:SS.SSS 格式
LOCAL FH,HH,MM,SS,SSS
IF INLIST(SUBSTR(HMSX,1,1),"+","-")
   FH = SUBSTR(HMSX,1,1)
   HMSX = SUBSTR(HMSX,2)
ELSE
   FH = ""
ENDIF      
*!* 取HHMMSS.SSS的.后面的前面3位   
SSS = PADL(SUBSTR(IIF(RAT(".",HMSX)>0,SUBSTR(HMSX,RAT(".",HMSX)+1),"000"),1,3),3,"0")

*!* 分别取HHMMSS中的SS,MM,HH
HMS = IIF(RAT(".",HMSX)=0,HMSX,SUBSTR(HMSX,1,RAT(".",HMSX)-1))
SS = PADL(SUBSTR(IIF(RAT(":",HMS)>0,SUBSTR(HMS,RAT(":",HMS)+1),HMS),1,2),2,"0")
HM = IIF(RAT(":",HMS)=0,"00",SUBSTR(HMS,1,RAT(":",HMS)-1))
MM = PADL(SUBSTR(IIF(RAT(":",HM)>0,SUBSTR(HM,RAT(":",HM)+1),HM),1,2),2,"0")
HH = PADL(SUBSTR(IIF(RAT(":",HM)=0,"00",SUBSTR(HM,1,RAT(":",HM)-1)),1,2),2,"0")

RETURN FH + HH + ":" + MM + ":" + SS + "." + SSS
ENDFUNC

FUNCTION 增加时间(c当前成绩,c变动成绩)
LOCAL HH,HH1,HH2,MM,MM1,MM2,SS,SS1,SS2,SSS,SSS1,SS2
HH1 = INT(VAL(SUBSTR(c当前成绩,1,2)))
MM1 = INT(VAL(SUBSTR(c当前成绩,4,2)))
SS1 = INT(VAL(SUBSTR(c当前成绩,7,2)))
SSS1 = INT(VAL(SUBSTR(c当前成绩,10,3)))

HH2 = INT(VAL(SUBSTR(c变动成绩,1,2)))
MM2 = INT(VAL(SUBSTR(c变动成绩,4,2)))
SS2 = INT(VAL(SUBSTR(c变动成绩,7,2)))
SSS2 = INT(VAL(SUBSTR(c变动成绩,10,3)))

SSS = SSS1 + SSS2
IF SSS >= 1000
   SSS = SSS - 1000
   SS1 = SS1 + 1
ENDIF
SS = SS1 + SS2
IF SS>=60
   SS = SS - 60
   MM1 = MM1 + 1
ENDIF
MM = MM1 + MM2
IF MM>=60
   MM = MM - 60
   HH1 = HH1 + 1
ENDIF   
HH = HH1 + HH2

RETURN PADL(HH,2,"0") + ":" + PADL(MM,2,"0") + ":" + PADL(SS,2,"0") + "." + PADL(SSS,3,"0")
ENDFUNC

FUNCTION 减少加时间(c当前成绩,c变动成绩)
LOCAL HH,HH1,HH2,MM,MM1,MM2,SS,SS1,SS2,SSS,SSS1,SS2
HH1 = INT(VAL(SUBSTR(c当前成绩,1,2)))
MM1 = INT(VAL(SUBSTR(c当前成绩,4,2)))
SS1 = INT(VAL(SUBSTR(c当前成绩,7,2)))
SSS1 = INT(VAL(SUBSTR(c当前成绩,10,3)))

HH2 = INT(VAL(SUBSTR(c变动成绩,1,2)))
MM2 = INT(VAL(SUBSTR(c变动成绩,4,2)))
SS2 = INT(VAL(SUBSTR(c变动成绩,7,2)))
SSS2 = INT(VAL(SUBSTR(c变动成绩,10,3)))

IF SSS1 >= SSS2
   SSS = SSS1 - SSS2
ELSE
   SSS = SSS1 - SSS2 + 1000
   SS1 = SS1 - 1
ENDIF
   
IF SS1 >= SS2
   SS = SS1 - SS2
ELSE
   SS = SS1 - SS2 + 60
   MM1 = MM1 - 1
ENDIF

IF MM1 >= MM2
   MM = MM1 - MM2
ELSE
   MM = MM1 - MM2 + 60
   HH1 = HH1 - 1
ENDIF

HH = HH1 - HH2
IF HH < 0
   MESSAGEBOX("减少变动成绩大于当前成绩,成绩不变!",48,"提示")
   RETURN c当前成绩
ELSE
RETURN PADL(HH,2,"0") + ":" + PADL(MM,2,"0") + ":" + PADL(SS,2,"0") + "." + PADL(SSS,3,"0")
ENDIF
ENDFUNC
#34
schtg2022-07-10 10:27
各位大侠,学习啦,谢谢!
#35
吹水佬2022-07-10 12:13
回复 33楼 mywisdom88
通常是转换成数值(秒)进行加减运算后再转换成显示格式

相关 windows API 有:

typedef struct _FILETIME {
    DWORD dwLowDateTime;
    DWORD dwHighDateTime;
} FILETIME, *PFILETIME, *LPFILETIME;
 
typedef struct _SYSTEMTIME {
    WORD wYear;
    WORD wMonth;
    WORD wDayOfWeek;
    WORD wDay;
    WORD wHour;
    WORD wMinute;
    WORD wSecond;
    WORD wMilliseconds;
} SYSTEMTIME, *LPSYSTEMTIME;

FILETIME和SYSTEMTIME都只是记录时间的结构。
GetLocalTime能够得到本地电脑设置时区的时间,得到的类型是SYSTEMTIME的类型。
常用转换函数:
LONG WINAPI CompareFileTime(const FILETIME *lpft1, const FILETIME *lpft2);
BOOL WINAPI FileTimeToSystemTime(const FILETIME *lpft, LPSYSTEMTIME lpst);
BOOL WINAPI SystemTimeToFileTime(const SYSTEMTIME *lpst, LPFILETIME lpft);
BOOL WINAPI FileTimeToLocalFileTime(const FILETIME *lpft, LPFILETIME lpftLocal);
BOOL WINAPI LocalFileTimeToFileTime(const FILETIME *lpftLocal, LPFILETIME lpft);

FILETIME 涉及到64位数值运算,可惜VFP不支持。
#36
吹水佬2022-07-10 14:50
以下是引用mywisdom88在2022-7-10 00:43:15的发言:

c当前 = "32:20:9.419"
c加减 = "-1:8.412"

格式固定规范可简化算法,如:h:m:s
c当前 = "32:20:9.419"
c加减 = "-0:1:8.412"
#37
吹水佬2022-07-11 16:34
以下是引用吹水佬在2022-7-10 12:13:52的发言:

FILETIME 涉及到64位数值运算,可惜VFP不支持。

简单写个模拟64位加减法,可以用来处理 FILETIME 的加减运算
程序代码:

    ** 模拟64位加法
FUNCTION add64(cInt64_a, cInt64_b)
    IF !(LEN(cInt64_a)==8 AND LEN(cInt64_b)==8)
        MESSAGEBOX("调用add64()无效的参数,要求是64位整数(8字节)")
        RETURN ""
    ENDIF
    LOCAL hi_a, lo_a, hi_b, lo_b, flag, hi_i, lo_i, hi_c, lo_c
    hi_a = CTOUINT(RIGHT(cInt64_a,4))
    lo_a = CTOUINT( LEFT(cInt64_a,4))
    hi_b = CTOUINT(RIGHT(cInt64_b,4))
    lo_b = CTOUINT( LEFT(cInt64_b,4))
    lo_i = lo_a + lo_b
    lo_i = CTOUINT(UINTTOC(lo_i,4))    && 取低32位部分,去除溢出部分
    flag = IIF(lo_i<lo_a, 1, 0)        && 检查是否发生了进位
    hi_i = hi_a + hi_b + flag
    RETURN UINTTOC(lo_i,4) + UINTTOC(hi_i,4)
ENDFUNC   

    ** 模拟64位减法
FUNCTION sub64(cInt64_a, cInt64_b)
    IF !(LEN(cInt64_a)==8 AND LEN(cInt64_b)==8)
        MESSAGEBOX("调用sub64()无效的参数,要求是64位整数(8字节)")
        RETURN ""
    ENDIF
    LOCAL hi_a, lo_a, hi_b, lo_b, flag, hi_i, lo_i, hi_c, lo_c
    hi_a = CTOUINT(RIGHT(cInt64_a,4))
    lo_a = CTOUINT( LEFT(cInt64_a,4))
    hi_b = CTOUINT(RIGHT(cInt64_b,4))
    lo_b = CTOUINT( LEFT(cInt64_b,4))
    lo_i = lo_a - lo_b
    flag = IIF(lo_i<0, 1, 0)            && 检查是否发生了借位
    IF flag == 1
        lo_i = 0xffffffff + lo_i + 1
    ENDIF
    hi_i = hi_a - hi_b - flag
    IF hi_i < 0
        MESSAGEBOX("调用sub64()无效的参数,要求被减数 >= 减数")
        RETURN ""
    ENDIF
    RETURN UINTTOC(lo_i,4) + UINTTOC(hi_i,4)
ENDFUNC   

    * 二进制字符转换为无符号整数
FUNCTION CTOUINT(cNum)
    LOCAL len,i,ret
    len = LEN(cNum)
    IF len == 0
        RETURN NULL
    ENDIF
    ret = ASC(SUBSTR(cNum,len,1))
    FOR i=len-1 TO 1 STEP -1
        ret = ret*0x100 + ASC(SUBSTR(cNum,i,1))
    ENDFOR
    RETURN ret
ENDFUNC

    ** 无符号整数转换成二进制字符
FUNCTION UINTTOC(uint, len)
    IF uint < 0
        MESSAGEBOX("调用 UINTTOC() 参数无效,要求数值 >= 0")
        RETURN ""
    ENDIF
    LOCAL ret
    ret = ""
    DO WHILE uint != 0
        ret  = ret + CHR(uint % 0x100)
        uint = INT(uint / 0x100)
    ENDDO
    RETURN PADR(ret, len, 0h00)
ENDFUNC


[此贴子已经被作者于2022-7-14 17:00编辑过]

1