比较日期时,为什么31> = 20在这里返回False?

时间:2017-06-02 22:57:28

标签: vba excel-vba excel

我正在调试此代码,但我不确定为什么这会返回false而不是true。

?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

2 个答案:

答案 0 :(得分:6)

因为您正在比较两个不同类型的import java.io.IOException; import java.io.PrintWriter; import java.util.Random; public class MainClass { public static void main(String[] args) { // TODO Auto-generated method stub try{ PrintWriter writer = new PrintWriter("bigfile.txt", "UTF-8"); Random random = new Random(); for(int i = 0; i < 23695522; i++) { char[] word = new char[random.nextInt(8)+3]; // words of length 3 through 10. (1 and 2 letter words are boring.) for(int j = 0; j < word.length; j++) { word[j] = (char)('a' + random.nextInt(26)); } writer.print(new String(word) + ' '); if (i % 10 == 0){ writer.println(); } } writer.close(); } catch (IOException e) { // do something } } } (事后我们讨论了...... thx @MatsMug)。比较不同类型的Variant,一个数字和一个字符串时,比较结果是未定义的行为。

再一次Variant anomalies。考虑一下这个MCVE:

Variants

虽然salday(0)是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 ,但明确将String Variant转换为String解决了问题。但是,如果没有转换,则比较失败。 VBA没有隐式将数字转换为字符串,反之亦然。它比较了两种不同类型的变体并返回了垃圾结果。

有关变体诅咒的更多信息,请阅读For v=1 to v and For each v in v -- different behavior with different types

事实证明,使用CStrCLng强制进行数字比较是一种安全的方法,或Val强制进行文字比较。

进一步考虑这三个简单的例子:

CStr

正如您所看到的,当两个变量(数字和字符串)都被声明为变体时,比较就是垃圾。当其中至少有一个是显式的时,比较成功!

答案 1 :(得分: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不会破坏您的代码。总是把日期视为这样!