【问题标题】:Can we convert such 20:72:84(hh:mm:ss) duration to 21:13:24 (hh:mm:ss) format Without Loop?我们可以在没有循环的情况下将这种 20:72:84(hh:mm:ss) 持续时间转换为 21:13:24 (hh:mm:ss) 格式吗?
【发布时间】:2023-08-18 10:11:01
【问题描述】:

是否可以在 VBScript 中将这种 20:72:84(hh:mm:ss) 持续时间转换为 21:13:24 (hh:mm:ss) 格式?

是的,显然我们可以循环通过它,但我想避免这种Loopy 技术。

代码

根据Siddharth 解决方案 - 我只是修改了代码以适应VBScript platform

Option Explicit


    Dim S
    S=Convert("23:61:61")
    MsgBox(s)


Function Convert(strTime) 'As String
    Dim timeArray() 
    Dim h , m , s 

    MsgBox("Hi")

    'On Error Resume Next

    timeArray = Split(strTime, ":")

    h = timeArray(0): m = timeArray(1): s = timeArray(2)

    REM If err then

        REM MsgBox(err)
        REM err.clear
        REM Exit Function
    REM End if

    Do Until s < 60
        s = s - 60
        m = m + 1
    Loop

    Do Until m < 60
        m = m - 60
        h = h + 1
    Loop

    Do Until h < 24
        h = h - 24
    Loop

    Convert = Format(h, "00") & ":" & Format(m, "00") & ":" & Format(s, "00")

    'on Error Goto 0
    'Exit Function
'Whoa:
    'Convert = "Error! CYDD!" '<~~ CYDD : Check Your Data Dude :)
End Function

EDIT1 我在Type mismatch 的行timeArray = Split(strTime, ":") 收到一个错误

谢谢,

【问题讨论】:

  • 问题是:你怎么能一开始就得到这样的值呢?
  • @Tukai,您之前的一些问题正好与此有关,这些答案发生了什么?
  • 我得到的那些没有正面的 cmets,他们提出的适合非动态的 excel 表。
  • @Tukai:根据你应该23:61:6124:61:61转换成什么?
  • 如果有奖,最疯狂的vbs问题,最不可能的样本数据集,那么你每次都是我的赢家。仅此一项就值得认可,因此根据我更好的判断,我将支持这个问题^_^

标签: excel vbscript wsh vba


【解决方案1】:
  1. 拆分数组
  2. 使用dateadd()将每个部分添加到空时间
  3. 使用 stringbuilder 将时间重建为格式良好的字符串

    ' This splits the string in an hours, minutes and seconds part.
    ' the hours will be in dArr(0), minutes in dArr(1) and seconds in dArr(2)
    dArr = split("20:72:84", ":")
    
    ' Add the hours to an empty date and return it to dt1 
    dt1 = dateadd("h", dArr(0), empty)
    
    ' Add the minutes to dt1. Note: Minutes are noted as "n" and not "m" because the
    ' "m" is reserved for months. To find out more about the dateadd() please look here:
    ' http://www.w3schools.com/vbscript/func_dateadd.asp
    ' When the minutes are bigger than they fit in the date, it automatically falls over to
    ' next hour.
    dt1 = dateadd("n", dArr(1), dt1)
    
    ' Also add the seconds (the third part of the array) to dt1, also the seconds
    ' automatically fall over when too large.
    dt1 = dateadd("s", dArr(2), dt1)
    
    ' Now that we created a date, we only have to format it properly. I find it the most easy
    ' way to do this is with a dotnet stringbuilder, because we can separate code and 
    ' format. The CreateObject creates the stringbuilder. We chain the AppendFormat
    ' and the ToString methods to it, so actually these are three statements in one.
    ' Mind the HH in the HH:mm:ss format string, hh means 12 hour notation, HH means 24
    ' hour notation.
    msgbox CreateObject("System.Text.StringBuilder").AppendFormat("{0:HH:mm:ss}", dt1).toString()
    

输出21:13:24

编辑:应 TS 要求的额外 cmets

【讨论】:

  • 这是我正在寻找的简短计算。但是你能解释一下“HOW”的计算吗?第2和第3行就足够了! :-)
  • 已添加说明,但如果您想了解某些工作原理,请在互联网上进行一些研究。在 google 中搜索 vbscript+dateadd 就足够了。尽量不要表现得像Help Vampire
  • +1,因为它是解决问题的明智解决方案,并且需要额外的解释。 (也许你想考虑 TimeSerial() 而不是 DateAdd())。
【解决方案2】:

这是你正在尝试的吗?

Option Explicit

Sub Sample()
    Debug.Print Convert("23:61:61")
    Debug.Print Convert("24:61:61")
    Debug.Print Convert("20:72:84")
    Debug.Print Convert("Hello World")
End Sub

Function Convert(strTime As String) As String
    Dim timeArray() As String
    Dim h As Long, m As Long, s As Long

    On Error GoTo Whoa

    timeArray = Split(strTime, ":")

    h = timeArray(0): m = timeArray(1): s = timeArray(2)

    Do Until s < 60
        s = s - 60
        m = m + 1
    Loop

    Do Until m < 60
        m = m - 60
        h = h + 1
    Loop

    Do Until h < 24
        h = h - 24
    Loop

    Convert = Format(h, "00") & ":" & Format(m, "00") & ":" & Format(s, "00")

    Exit Function
Whoa:
    Convert = "Error! CYDD!" '<~~ CYDD : Check Your Data Dude :)
End Function

快照

编辑(跟进)

我上面给出的代码是VBA-Excel因为它是你的标签之一

对于VB-Script,请使用此代码

MsgBox Convert("23:61:61")
MsgBox Convert("24:61:61")
MsgBox Convert("20:72:84")
MsgBox Convert("Hello World")

Function Convert(strTime)
    Dim timeArray
    Dim h, m, s, hh, mm, ss

    On Error Resume Next

    timeArray = Split(strTime, ":", -1, 1)

    h = timeArray(0): m = timeArray(1): s = timeArray(2)

    If Err Then
        Err.Clear
        Exit Function
    End If

    Do Until s < 60
        s = s - 60
        m = m + 1
    Loop

    Do Until m < 60
        m = m - 60
        h = h + 1
    Loop

    ' As per latest request
    'Do Until h < 24
        'h = h - 24
    'Loop

    If Len(Trim(h)) = 1 Then hh = "0" & h Else hh = h
    If Len(Trim(m)) = 1 Then mm = "0" & m Else mm = m
    If Len(Trim(s)) = 1 Then ss = "0" & s Else ss = s

    Convert = hh & ":" & mm & ":" & ss

    On Error GoTo 0
End Function

HTH

【讨论】:

  • 我没有得到上面代码中任何调用的任何输出!我认为code 中存在任何隐藏问题。
  • 这里的一个问题是我得到的输出为 00:02:01 输入 23:61:61 。这是不希望的。这些持续时间是资源工作时间计算。所以我需要让它们完好无损。应该是24:02:01
  • h &lt; 24 更改为h &lt; 25h = h - 24 更改为h = h - 25
  • 你能指导我这样做吗?
【解决方案3】:

这似乎很明显是一个“XY Problem”:OP 正在寻求一种解决方法来处理格式错误的数据,而不是首先弄清楚数据是如何变得格式错误的(并防止它发生)。

20:72:84 不是 any 标准的持续时间的逻辑表示,并且创建该字符串的任何内容都是错误的。

技术上,根据ISO-8601(被认为是“涵盖日期和时间相关数据交换的国际标准”),duration 应表示为PnYnMnDTnHnMnS

也就是说,我也会选择 HH:MM:SS... 但它应该 [显然?] 永远不会显示超过 59 秒或 59 分钟,超过我们的十进制(又名,Base 10)数字系统应该计算在内...0.8, 0.9, 0.10, 0.11...。 (大声笑,“零点十一”


固定持续时间

不管怎样,这是一个老问题,我们不知道你是如何得到这个奇怪的数字的,但正如其他人所建议的,我会使用 Split 来修复它,尽管我更喜欢压缩形式:

Function fixWonkyDuration(t As String) As String
    fixWonkyDuration = Format(((Split(t, ":")(0) * 60 + Split(t, ":")(1)) _
        * 60 + Split(t, ":")(2)) / 86400, "HH:mm:ss")
End Function

上面的函数将通过将每个部分转换为秒,求和,然后临时转换为Date,然后使用Format 来按预期显示它来修复“不稳定”的持续时间。

请务必注意,输入 输出都不是有效的 Excel DateTime (Date),因此两者都声明为 Strings。

示例用法:

MsgBox fixWonkyDuration("20:72:84")  'returns "21:13:24"

转换为秒(用于比较、计算等)

顺便说一下,当您有一个HH:MM:SS 格式的有效 持续时间,但想与它进行计算或比较时,最简单的方法是先在TimeValue 的帮助下将其转换为秒数,然后CDbl.

最快的方法:

Function DurationToSeconds(d As String) As Long
    DurationToSeconds = CDbl(TimeValue(d)) * 86400#
End Function

示例用法:

MsgBox DurationToSeconds("21:13:24")  'returns 76404

【讨论】:

    【解决方案4】:

    嗯,你可以分成 3 个变量:h、m 和 s。然后检查是否 s>60。如果是,m=m+s/60 和 s=s%60。 m 变量也一样:

    if(m>60) then
        h=h+m/60
        m=m%60
    

    然后,连接 h、m 和 s。

    【讨论】:

    • 感谢您的建议,但正在寻找任何直接的方法!
    • @pst 是的!我知道。寻找任何可以减少这么多代码行的内置函数。因此,对于我要处理 3500 行和 25 个此类持续时间列的实际案例,这样的分支和算术将花费时间!
    • @TukaiRakshit 计算机速度很快(除非有真正的测试用例,否则不要怀疑这一点),并且功能可以消除重复代码。
    • @pst 我可以看看你的代码 - 你建议我的方法吗?
    • @peter 我同意,但是让我们看看是否有人可以给我这样的一个方法!否则我会遵循这样的传统数学:-)
    【解决方案5】:

    文字过多,无法发表评论。

    当您在General 格式的任何单元格中输入20:72:33 时,它会显示一个序列号。例如。 0.883715278

    然后将单元格格式更改为Time。它为您提供了您想要查看的格式和数据。

    但是

    上述语句仅在您的秒数为 below 60 时有效。如果输入60, 61, 84、'100'等不起作用。

    所以也许您可以像您现在正在使用的所有干扰代码一样干扰它。 ;)

    这是最丑陋的。在seconds 上执行mod 60,然后将单元格格式更改为时间。或者就像使用 Alex 在他的答案中显示的那样。 它很干净,并且在数学上保证了你想要的输出。

    【讨论】:

    • @Tukai BTW Alex 的回答不需要你有loop
    • @Siddharth 请在这里给我链接,我需要阅读该参考资料!
    最近更新 更多