Access VBA not appending date properly in loop - vba

I'm trying to make a loop that (among other things) inserts a date and then in each row, adds a month to that date. It is not appending the first date properly. The date is a DLookup from a date field in a query, so I think it should work as a date. And I don't see anything wrong with my SQL statement. But when this runs the date shows up in the table as 12/30/1899 and if you click on it, it changes to 12:03:34 AM. It's supposed to be 5/1/15. Nothing I've tried to get this to work has given me any other results.
Here's my code, please note: there's probably a couple other things wrong with my overall code I'm sure, but I'm focusing on this date problem for now. Feel free to point out whatever you find, though.
Private Sub AmortButton_Click()
DoCmd.SetWarnings False
Dim Account As Long: Account = DLookup("[L#]", "qry_info4amort") 'working
Dim StartDate As Date: StartDate = CDate(DLookup("PaidToDate", "qry_info4amort")) 'NOT WORKING
Dim InterestRate As Double: InterestRate = DLookup("IntCur", "qry_info4amort") 'working
Dim piConstant As Integer: piConstant = DLookup("[P&IConstant]", "qry_info4amort")
Dim UPB As Currency: UPB = DLookup("UPB", "qry_info4amort") 'working
Dim tempUPB As Currency: tempUPB = UPB 'working (just to establish variable)
Dim AmortInterest As Currency: AmortInterest = 0 'working (just to establish variable)
Dim AmortPrincipal As Currency: AmortPrincipal = 0 'working (just to establish variable)
Dim Ranking As Integer: Ranking = 1 'working (just to establish variable)
Dim PaymentLoop As Integer: PaymentLoop = 1 'working (just to establish variable)
Dim PaymentNumber As Integer: PaymentNumber = DLookup("NumPmts", "qry_info4amort") 'working
Dim tempInterest As Integer: tempInterest = 0 'working (just to establish variable)
Do While PaymentLoop <= PaymentNumber 'working
tempInterest = Round(tempUPB * (InterestRate / 12), 2)
tempUPB = Round(tempUPB - (piConstant - tempInterest), 2)
AmortPrincipal = AmortPrincipal + (piConstant - tempInterest)
AmortPrincipal = (piConstant - tempInterest)
AmortInterest = AmortInterest + tempInterest
DoCmd.RunSQL "INSERT INTO tbl_AmortizationTest ([L#],[Payment#],[PaymentDate],[UPB],[Interest],[Principal],[TotalPayment],[InterestRate],[TempUPB],[Ranking]) " & _
"VALUES (" & Account & "," & PaymentLoop & "," & StartDate & "," & UPB & "," & tempInterest & "," & AmortPrincipal & "," & (tempInterest + AmortPrincipal) & "," & InterestRate & "," & tempUPB & "," & Ranking & ")"
UPB = tempUPB
StartDate = DateAdd("m", 1, StartDate) 'NOT WORKING
PaymentLoop = PaymentLoop + 1 'working
Ranking = Ranking + 1 'working
Loop
MsgBox "Done!"
DoCmd.SetWarnings True
End Sub

First, if PaidToDate is of data type Date, retrieve your date as is:
StartDate = DLookup("PaidToDate", "qry_info4amort")
If it is a string, CDate or DateValue will do:
StartDate = DateValue(DLookup("PaidToDate", "qry_info4amort"))
Second, format a proper string expression for the date when concatenating it into SQL:
... PaymentLoop & ",#" & Format(StartDate, "yyyy\/mm\/dd") & "#," & UPB ...

Instead of using CDate() around your DLookup("PaidToDate", "qry_info4amort") you are probably going to have to pull out the relevant parts piece by piece...
StartDate = DateSerial(<year>, <month>, <day>)
For example, if DLookup("PaidToDate", "qry_info4amort") returns 05012015 then you could do:
StartDate = DateSerial(Mid(DLookup("PaidToDate", "qry_info4amort"),5,4), Left(DLookup("PaidToDate", "qry_info4amort"),2), Mid(DLookup("PaidToDate", "qry_info4amort"),3,2))
If the DLookup("PaidToDate", "qry_info4amort") returns a value with / in it, then you will have to use some Instr() functions... More on that here.

Related

VBA UDF for list of MM.YYYY (months) between two dates

I am trying to list the dates between two given months: a) 1/1/2021; b) 6/1/2021 in format: 01.2021; 02.2021; 03.2021; 04.2021; 05.2021; 06.2021
I was able to find and use this UDF:
Function MONTHRANGE(startDate As Date, endDate As Date, _
Optional Delim As String = "; ", _
Optional dFormat As String = "MM.YYYY") As String
MONTHRANGE = Join(Evaluate("TRANSPOSE(TEXT(ROW(" & CLng(startDate) & ":" & CLng(endDate) & ")," & Chr(34) & dFormat & Chr(34) & "))"), Delim)
End Function
The output of this is repeated dates (for each day of the month) in the format I want - how can I return just the unique values (one - per month)?
Something like the following gets the job done:
Option Explicit
Private Sub Test()
Debug.Print GetMonths(CDate("1/1/2021"), CDate("6/1/2021"))
End Sub
Private Function GetMonths(ByVal StartDate As Date, ByVal EndDate As Date) As String
Do While StartDate <= EndDate
GetMonths = GetMonths & Format(Month(StartDate), "00") & "." & Year(StartDate) & "; "
StartDate = DateAdd("m", 1, StartDate)
Loop
GetMonths = Left(GetMonths, Len(GetMonths) - 2)
End Function

Why is 31 >= 20 returning False here when comparing day?

I was debugging this code but I am not sure why this is returning false instead of true.
?Day(i)>salday(0)
False
?Day(i)
31
?salday(0)
20
?isnumeric(day(i))
True
?isnumeric(salday(0))
True
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
Because you are comparing two Variants with different types (As it turned out after our discussions... thx #MatsMug). The comparison result is undefined behavior when comparing Variants of different types, one numeric and one String.
It's the Variant anomalies once again.. Consider this 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
Although salday(0) is a String Variant, explicitly converting it to String with CStr solved the issue. However, without that conversion, the comparison failed. VBA did not implicitly convert the number to a string or vice-versa. It compared two Variants of different types and returned a rubbish result.
For more about the Variant curse, read For v=1 to v and For each v in v -- different behavior with different types
As it turns out, using CLng or Val to force number comparison is the safe way to go, or CStr to force text comparison.
Consider further these three simple examples:
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
As you can see, when both variables, the number and the string, were declared variants, the comparison is rubbish. When at least one of them is explicit, the comparison succeeds!
Dim stDate, enDate
This instruction declares two Variant variables. They're assigned here:
stDate = STG.Range("B2"): enDate = STG.Range("B4")
Assuming [B2] and [B4] contain actual date values, at that point the variables contain a Variant/Date. That's because the implicit code here is as follows:
stDate = STG.Range("B2").Value: enDate = STG.Range("B4").Value
But you probably know that already. Moving on.
salDay = Split(STG.Range("B6"), "-")
salDay is also an implicit Variant. That instruction is quite loaded though. Here's the implicit code:
salDay = Split(CStr(STG.Range("B6").Value), "-")
This makes salDay an array of strings. So here we are:
?Day(i)
31
?salday(0)
20
The leading space in front of 31 is because the immediate pane always leaves a spot for a negative sign. salDay(0) being a String, there's no leading space. That was your clue right there.
?Day(i)>salday(0)
False
With salday(0) being a String, we're doing a string comparison here, as was already pointed out. Except there's no leading space in front of the 31; the implicit code is this, because the type of Day(i) is Integer:
?CStr(Day(i)) > salDay(0)
False
The solution is to get rid of salDay altogether: you don't need it. Assuming [B6] also contains an actual date, you can get the day into an Integer right away:
?Day(STG.Range("B6").Value)
As a bonus you decouple your code from the string representation of the underlying date value that's in your worksheet, so changing the NumberFormat won't break your code. Always treat dates as such!

adding calculated column using vba and variables

Depending on some inputs from the users in a user form, I am building code to automatically create calculated columns based on defined criteria. However, I am getting a syntax error in the field expression, code provided below.
Option Compare Database
Private Sub Calculate_Click()
Dim db As Database
Dim rs As Recordset
Dim x As Integer
Dim Months As Integer
Dim WPmonthly As String ' field name for monthly written premium
Dim runningDate As Date
Dim useDateLower As Date
Dim useDateUpper As Date
Dim tdf As dao.TableDef
Dim fld As dao.Field2
Months = Me.YearsBack * 12 + Month(Me.ValDate)
If Me.Period = "monthly" Then
Set db = CurrentDb
Set tdf = db.TableDefs("tblEPdata")
For x = 1 To Months
runningDate = Format(DateAdd("m", -x + 1, Me.ValDate), "mm yyyy")
useDateLower = runningDate
useDateUpper = Format(DateAdd("m", -x + 2, Me.ValDate), "mm yyyy")
WPmonthly = "WP M" & Month(runningDate) & " " & Year(runningDate)
Set fld = tdf.CreateField(UPRmonthly)
fld.Expression = "iif([issuedate]<#" & useDateUpper & "#,iif([issuedate]>=#" & useDateLower & "#,[grossPremium]))" ' output gross premium if issue date is between usedateupper and usedatelower, otherwise 0
tdf.Fields.Append fld
Next
MsgBox "added"
End If
End Sub
You don't have enough arguments for iif - it takes three arguments (see here):
IIf ( expr , truepart , falsepart )
Judging by your comment in the code, you want either:
"iif([issuedate]<#" & useDateUpper & "#,iif([issuedate]>=#" & useDateLower & "#,[grossPremium],0),0)"
Or you can simplify this e.g. to:
"iif([issuedate]<#" & useDateUpper & "# and [issuedate]>=#" & useDateLower & "#,[grossPremium],0)"
Figured it out. The variable wpmonthly was supposed to be used where uprmonthly was being used. uprmonthly was not defined.
Cheers

VBA generating formula via variables

Can someone please help me to fix the formula in the sub. I need to enter dates into it via variables but it always gives me an error '13' data types
I'm talking about the bit:
Cells(5, field).FormulaLocal = "=SUMMEWENNS(Rawdata!K2:K3446;Rawdata!I2:I3446;""bezahlt"";Rawdata!A2:A3446;" >= " & weekstart & "";Rawdata!A2:A3446;" <= " & weekend & "")"
The Sub apart from that formula works.....
Sub get_cal_weeks()
Dim weeks As Integer, i As Integer, col As String, weekstart As Date, weekend As Date, calweeks() As Variant
'start column is D
col = "D"
'get amount of weeks
weeks = countcalweeks()
'populate array calweeks
calweeks = fillcalweeks(weeks)
For i = 0 To weeks
field = i + i + 4
weekstart = calweeks(i, 0)
weekend = calweeks(i, 1)
Cells(5, field).FormulaLocal = "=SUMMEWENNS(Rawdata!K2:K3446;Rawdata!I2:I3446;""bezahlt"";Rawdata!A2:A3446;" >= " & weekstart & "";Rawdata!A2:A3446;" <= " & weekend & "")"
Next
End Sub
Thank you
I suggest you convert to long (or double if you need times)
Cells(5, field).FormulaLocal = "=SUMMEWENNS(Rawdata!K2:K3446;Rawdata!I2:I3446;""bezahlt"";Rawdata!A2:A3446;"">=" & CLng(weekstart) & """;Rawdata!A2:A3446;""<=" & CLng(weekend) & """)"

VBA Macro and changing date format to mmm-yy

I am having problems with an excel macro (VBA) that is meant to grab a date from an excel spreadsheet, subtract one month and reformat it to MMM-YY. Basically I want to take 3/31/2013 and convert it to Feb-13
Here is my code:
Dim ReportDate As Date
ReportDate = Worksheets("Current").Cells(2, 16) 'ex. 03-31-2013
prevMonth = Format((Month(ReportDate) - 1) & "/" & Day(ReportDate) & "/" & Year(ReportDate), "mmm") & "-" & Format(ReportDate, "yy")
Debug.Print prevMonth
The result I get is 2/31/2013-13
So I tried changing the prevMonth variable:
prevMonth = Format((Month(ReportDate) - 1) & "/" & Day(ReportDate) & "/" & Year(ReportDate), "mmm-yy")
But got just 2/31/2013 again
I tried to declare prevMonth as an Integer or a Date but I get a type mismatch error. I can only declare it as a String but it still doesn't help the program.
Thanks in advance for your help.
Try this
Sub Demo()
Dim ReportDate As Date
Dim prevMonth As Date
ReportDate = Worksheets("Current").Cells(2, 16) 'ex. 03-31-2013
prevMonth = DateAdd("m", -1, ReportDate)
Debug.Print Format(prevMonth, "mmm-yy")
End Sub