2017-06-02 33 views
3

我在調試這段代碼,但我不確定爲什麼這會返回false而不是true。爲什麼31> = 20在比較日期時在這裏返回False?

?Day(i)>salday(0) 
False 
?Day(i) 
31 
?salday(0) 
20 
?isnumeric(day(i)) 
True 
?isnumeric(salday(0)) 
True 

enter image description here

Option Explicit 
Option Compare Text 

Sub genOP() 

Dim wO As Worksheet 
Dim i As Long, j As Long 
Dim stDate, enDate, intVal, entR As Long, salDay, salAmt, stTime, enTime, dbMin, dbMax 
Dim stRow As Long 
Dim cet, curMn 


'On Error Resume Next 
Application.ScreenUpdating = False 

stDate = STG.Range("B2"): enDate = STG.Range("B4") 
intVal = Split(STG.Range("B3"), ","): entR = STG.Range("B5") 
salDay = Split(STG.Range("B6"), "-") 
salAmt = STG.Range("B7"): stTime = STG.Range("B8"): enTime = STG.Range("B9"): dbMin = STG.Range("B10"): dbMax = STG.Range("B11") 

Set wO = ThisWorkbook.Sheets.Add 
TEMP.Cells.Copy wO.Range("A1") 

stRow = 19 
curMn = Month(stDate) 

For i = CLng(stDate) To CLng(enDate) 

    If stRow > 19 Then 
     wO.Rows(stRow & ":" & stRow).Copy 
     wO.Rows(stRow + 1 & ":" & stRow + 1).Insert Shift:=xlDown 
     Application.CutCopyMode = False 
    End If 

    cet = Trim(DESC.Range("A" & WorksheetFunction.RandBetween(2, DESC.UsedRange.Rows.Count))) 

    If STG.Range("B14") = "ON" Then 
     cet = cet & "Transaction amount " & Chr(34) & "&TEXT(H" & stRow & "," & Chr(34) & "#,##0.00" & Chr(34) & ")&" & Chr(34) & " GEL," 
    End If 
    If STG.Range("B13") = "ON" Then 
     cet = cet & Chr(34) & "&TEXT(B" & stRow & "-1," & Chr(34) & "dd mmm yyyy" & Chr(34) & ")&" & Chr(34) 
    End If 
    If STG.Range("B12") = "ON" Then 
     cet = cet & " " & Format(stTime + Rnd * (enTime - stTime), "HH:MM AM/PM") 
    End If 

    If curMn = Month(i) And (Day(i) >= salDay(0) And Day(i) <= salDay(1)) Then 'Salary Day 
     cet = Trim(DESC.Range("A" & WorksheetFunction.RandBetween(2, DESC.UsedRange.Rows.Count))) 
     wO.Range("B" & stRow) = Format(i, "DD-MM-YYYY") 
     wO.Range("I" & stRow) = salAmt 
     wO.Range("L" & stRow) = MonthName(Month(i)) & "- Salome Baazov - " & "Geo" & " Ltd " 
     curMn = WorksheetFunction.EDate(i, 1) 
    Else 
     wO.Range("B" & stRow) = Format(i, "DD-MM-YYYY") 
     wO.Range("H" & stRow) = WorksheetFunction.RandBetween(dbMin, dbMax) + (WorksheetFunction.RandBetween(0, 1) * 0.5) 
     wO.Range("L" & stRow) = "=" & Chr(34) & cet & Chr(34) 
    End If 

    stRow = stRow + 1 
    i = i + intVal(WorksheetFunction.RandBetween(LBound(intVal), UBound(intVal))) - 1 
Next i 

wO.Rows(stRow).EntireRow.Delete 
wO.Range("I" & stRow).Formula = "=SUM(I19:I" & stRow - 1 & ")" 
wO.Range("H" & stRow).Formula = "=SUM(H19:H" & stRow - 1 & ")" 

wO.Activate 
Application.ScreenUpdating = True 
STG.Range("B5") = stRow - 1 
MsgBox "Process Completed" 

End Sub 
+0

Protip:使用日期時,使用Date類型和'VBA.DateTime'模塊中的函數。 –

+0

這裏有一些隱含的鍵入問題。 'Dim a,b,c,d As Foo'將'a','b'和'c'聲明爲隱式'Variant',將'd'聲明爲'Foo'。這導致各種隱式類型轉換髮生在你後面;-) –

+0

@ Mat'sMug是的我明白他們是Variant類型,但爲什麼它會爲'Day(i)'增加一個前導空間給我i好 ?僅僅是因爲類型聲明? – newguy

回答

6

因爲你比較兩個Variant s的不同類型(正如我們的討論後,竟然...... THX @MatsMug)。當比較不同類型的Variants時,比較結果是未定義的行爲,一個數字和一個字符串。

這是Variant anomalies再次..考慮這個MCVE:

Sub Test1() 
    Dim i, salday 
    i = CDate("5/30/2017") 
    salday = Split("20-20-20", "-") 

    Debug.Print Day(i), salday(0)     ' 30 20 
    Debug.Print Day(i) > salday(0)     ' False 
    Debug.Print Day(i) > CStr(salday(0))   ' True 
    '     ^^^^ 
    Debug.Print Val(Day(i)) > salday(0)   ' True 
    '   ^^^^ 
End Sub 

雖然salday(0)是String Variant,明確其與CStr轉換爲String解決的問題。但是,沒有這種轉換,比較失敗。 VBA沒有將數字隱式轉換爲字符串,反之亦然。它比較了兩種不同類型的變體並返回了垃圾結果。

欲瞭解更多有關變詛咒,讀For v=1 to v and For each v in v -- different behavior with different types

事實證明,使用CLngVal迫使數比較是去強制文本比較安全的方式,或CStr


進一步考慮這三個簡單的例子:

Sub Test1() 
    Dim x, y: x = 30: y = "20" 
    Debug.Print x > y    ' False !! 
End Sub 

Sub Test2() 
    Dim x As Long, y: x = 30: y = "20" 
    '  ^^^^^^ 
    Debug.Print x > y    ' True 
End Sub 

Sub Test3() 
    Dim x, y As String: x = 30: y = "20" 
    '   ^^^^^^ 
    Debug.Print x > y    ' True 
End Sub 

正如你所看到的,當兩個變量,數字和字符串,被宣佈變種,比較是垃圾。至少其中一個是明確的,比較成功!

+0

哦,是的,謝謝我錯過了,我認爲如果isnumeric返回true,那麼它必須是一個數字 – newguy

+0

但是,爲什麼第(i)天會返回一個數字? – newguy

+0

@newguy它發生了:)但那領先的空間從哪裏來?一個錯誤?這確實很奇怪。 –

5
Dim stDate, enDate 

該指令聲明瞭兩個Variant變量。他們要在這裏分配:

stDate = STG.Range("B2"): enDate = STG.Range("B4") 

假設[B2][B4]包含實際的日期值,該點處的變量包含Variant/Date。這是因爲這裏的隱含代碼如下:

stDate = STG.Range("B2").Value: enDate = STG.Range("B4").Value 

但是你可能已經知道了。繼續。

salDay = Split(STG.Range("B6"), "-") 

salDay也隱式Variant。這條指令雖然很有用。這裏是隱含的代碼:

salDay = Split(CStr(STG.Range("B6").Value), "-") 

這使得salDay是一個字符串數組。所以,我們在這裏:

?Day(i) 
31 
?salday(0) 
20 

31前的前導空格是因爲眼前的窗格中總會留下了一個負號一個點。 salDay(0)String,沒有領先空間。那是你的線索。

?Day(i)>salday(0) 
False 

隨着salday(0)被一個String,我們在這裏做一個字符串比較,as was already pointed out。除了31號門前沒有領先空間外,隱含的代碼是這樣的,因爲Day(i)類型是Integer

?CStr(Day(i)) > salDay(0) 
False 

的解決辦法是,完全擺脫salDay:你不需要它。假設[B6]還包含一個實際日期,就可以得到一天到Integer馬上:

?Day(STG.Range("B6").Value) 

作爲獎勵你分離從底層日期值是在工作表的字符串表示你的代碼,因此改變NumberFormat不會破壞你的代碼。總是這樣對待日期!

+0

好吧,Cstr是罪魁禍首嗎? – newguy

+0

隱式字符串轉換,是的。 –

+0

很好的解釋。所以,事實證明,將一個int與一個字符串進行比較並不能將任何一種類型轉換爲另一種類型以進行比較?!!奇怪的奇怪的VBA。 –

相關問題