Excel VBA时间问题

感谢您的期待,

我有一个与下面的VBA代码的问题。 可能是简单的事情。

如果我在23:30input时间,它会自动更改为23:29

如果我input2330,它会更改为23:30。

所以为什么我23:30进入23:29? 它应该保持在23:30

谢谢

Private Sub Worksheet_Change(ByVal Target As Excel.Range) Dim xStr As String Dim xVal As String Set rng1 = Range("J:J") Set rng2 = Range("P:P") Set rng3 = Range("S:S") On Error GoTo EndMacro If Application.Intersect(Target, Union(rng1, rng2, rng3)) Is Nothing Then Exit Sub If Target.Count > 1 Then Exit Sub If Target.Value = "" Then Exit Sub If Target.Row < 5 Then Exit Sub Application.EnableEvents = False With Target If Not .HasFormula Then Target.Value = Replace(Target.Value, ";", ":") Target.Value = Left(Target.Value, 5) xVal = .Value Select Case Len(xVal) Case 1 ' eg, 1 = 00:01 AM xStr = "00:0" & xVal Case 2 ' eg, 12 = 00:12 AM xStr = "00:" & xVal Case 3 ' eg, 735 = 07:35 AM xStr = "0" & Left(xVal, 1) & ":" & Right(xVal, 2) Case 4 ' eg, 1234 = 12:34 xStr = Left(xVal, 2) & ":" & Right(xVal, 2) Case 5 ' eg, 12:45 = 12:45 xStr = Left(xVal, 2) & Mid(xVal, 2, 1) & Right(xVal, 2) Case Else Err.Raise 0 End Select .Value = Format(TimeValue(xStr), "hh:mm") End If End With Application.EnableEvents = True Exit Sub EndMacro: Application.EnableEvents = True End Sub 

这是因为Excel将时间字段视为一天中的一小部分。

例如:

  • 24小时= 1
  • 12小时= 0.5
  • 6小时= 0.25

在你的情况下:23h30 = 0,979166666 …

但你只能得到前5个字符: Left(Target.Value, 5) ' "0.979"

并将此新值(0.979)作为当前值传递给单元格Target.Value = Left(Target.Value, 5)

所以在xStr = Left(xVal, 2) & Mid(xVal, 2, 1) & Right(xVal, 2) ,你的代码实际上在做的是:

Left(0.979, 2) ' -> "0."

Mid(xVal, 2, 1) ' -> "."

Right(xVal, 2) ' -> "79"

所以当你join时,结果如下:

"0." & "." & "79" = "0..79"

"0..79"不是该单元的有效值。 然后发生错误,函数结束保持0.979 : 23:29的值。

我的build议,如果它已经小于一个,不要改变单元格的值。 因为这表示已经是时候了。

  1. 删除行: Target.Value = Left(Target.Value, 5)
  2. 直接指定xval的值: xVal = Left(Target.Value, 5)
  3. 改变“情况5”的情况如下: xStr = Format(Target.Value, "hh:mm")

完整的代码如下所示:

 Private Sub Worksheet_Change(ByVal Target As Excel.Range) Dim xStr As String Dim xVal As String Set rng1 = Range("J:J") Set rng2 = Range("P:P") Set rng3 = Range("S:S") On Error GoTo EndMacro If Application.Intersect(Target, Union(rng1, rng2, rng3)) Is Nothing Then Exit Sub If Target.Count > 1 Then Exit Sub If Target.Value = "" Then Exit Sub If Target.Row < 5 Then Exit Sub Application.EnableEvents = False With Target If Not .HasFormula Then Target.Value = Replace(Target.Value, ";", ":") xVal = Left(Target.Value, 5) ' CHANGED! Select Case Len(xVal) Case 1 ' eg, 1 = 00:01 AM xStr = "00:0" & xVal Case 2 ' eg, 12 = 00:12 AM xStr = "00:" & xVal Case 3 ' eg, 735 = 07:35 AM xStr = "0" & Left(xVal, 1) & ":" & Right(xVal, 2) Case 4 ' eg, 1234 = 12:34 xStr = Left(xVal, 2) & ":" & Right(xVal, 2) Case 5 ' eg, 12:45 = 12:45 xStr = Format(Target.Value, "hh:mm") ' CHANGED! Case Else Err.Raise 0 End Select .Value = Format(TimeValue(xStr), "hh:mm") ' CHANGED! End If End With Application.EnableEvents = True Exit Sub EndMacro: Application.EnableEvents = True End Sub 

看起来你正在尝试用错误的方式来做date,因为通常和推荐的格式化date的方法是使用Format语句。

然而,如果你想把date/时间作为string来处理,你需要对代码做一些修改,testing之后的3行:

  If Not .HasFormula Then .Value = Replace(.Text, ";", ":") ' <-- use .Text .Value = Left(.Text, 5) ' <-- xVal = .Text ' <-- 

或者更好的是,直接分配xVal:

  If Not .HasFormula Then xVal = Left(Replace(.Text, ";", ":"), 5) ' <-- 

另一方面,你用.Value得到的是一个编码的date,通常编码为一个数字,然后你截断date到最左边的5个数字,这自然会导致一些不精确。