I am trying to use VBA to automatically create data set and save as CSV. I have one Dynamic_Data sheet filled with formulaes which filled when inputs from Sheetlist worksheet given. As per the formula, It can be 50 rows or 500 rows. I want to save only data that has been calculated and now have values in it. But I am not getting last row value and whole worksheet have been saved which also have lot of blank rows or rows with zero value after actual data.
Please help correcting the script.
Here is the code I used.
Sub CompileBPData()
Dim s As String
Dim sname As String
Dim StartName As String
Dim EndName As String
Dim MidName As String
Dim StartNum As String
Dim EndNum As String
Dim CoverNum1 As String
Dim CoverNum2 As String
Dim Cover As String
Dim IntMax As String
Dim GetNewSuffix As String
Dim Job As String
Dim Book As String
Dim EA As String
Dim Lrow As Long
On Error Resume Next
GetNewSuffix = " ("
IntMax = ") "
StartName = "Book "
EndName = "Job_"
MidName = "-"
Sheets("Sheetlist").Select
' Open dialouge box for selecting header
Job = InputBox("Enter Job Number")
If Job = "" Then
Exit Sub
End If
s = InputBox("Enter Next Book Number")
If s = "" Then
Exit Sub
End If
Range("D2").Value = s
Book = InputBox("How many Books in One Column")
If Book = "" Then
Exit Sub
End If
Range("H3").Value = Book
EA = InputBox("EA Code & Name Please")
If EA = "" Then
Exit Sub
End If
Range("I8").Value = EA
'******Finding Last row with no value*********
With wsInpt.Columns("E").SpecialCells(Type:=xlCellTypeBlanks)
Lrow = .Cells(.Cells.Count).Row
End With
'Lrow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row
'**********Select Data Sheet and create Paper Data *********
Sheets("Sheetlist").Select
Range("E2").Select
StartNum = Range("E2")
EndNum = Range("E7")
CoverNum1 = Range("D2")
CoverNum2 = Range("E9")
Cover = Range("I2")
Sheets("Dynamic_Data").Select
ActiveWorkbook.SaveAs Filename:=EA & MidName & StartName & CoverNum1 & MidName & CoverNum2 & GetNewSuffix & "G" & StartNum & MidName & "G" & EndNum & IntMax & Cover & " " & StartName & "_" & EndName & Job, FileFormat:=xlCSV, CreateBackup:=False
ActiveSheet.Name = "Dynamic_Data"
Sheets("Sheetlist").Select
Range("D2").Select
End Sub
Hope this could help you.
Sub CompileBPData()
Dim s As String
Dim sname As String
Dim StartName As String
Dim EndName As String
Dim MidName As String
Dim StartNum As String
Dim EndNum As String
Dim CoverNum1 As String
Dim CoverNum2 As String
Dim Cover As String
Dim IntMax As String
Dim GetNewSuffix As String
Dim Job As String
Dim Book As String
Dim EA As String
Dim Lrow As Long
On Error Resume Next
GetNewSuffix = " ("
IntMax = ") "
StartName = "Book "
EndName = "Job_"
MidName = "-"
Sheets("Sheetlist").Select
' Open dialouge box for selecting header
Job = InputBox("Enter Job Number")
If Job = "" Then
Exit Sub
End If
s = InputBox("Enter Next Book Number")
If s = "" Then
Exit Sub
End If
Range("D2").Value = s
Book = InputBox("How many Books in One Column")
If Book = "" Then
Exit Sub
End If
Range("H3").Value = Book
EA = InputBox("EA Code & Name Please")
If EA = "" Then
Exit Sub
End If
Range("I8").Value = EA
'******Finding Last row with no value*********
With wsInpt.Columns("E").SpecialCells(Type:=xlCellTypeBlanks)
Lrow = .Cells(.Cells.Count).Row
End With
'Lrow = ActiveSheet.Cells(Rows.Count, 1).End(xlUp).Row
'**********Select Data Sheet and create Paper Data *********
Sheets("Sheetlist").Select
Range("E2").Select
StartNum = Range("E2")
EndNum = Range("E7")
CoverNum1 = Range("D2")
CoverNum2 = Range("E9")
Cover = Range("I2")
'------------------ BEGIN OF EDITED PART --------------------------------
'Loop Until Calculation is Done
Do
DoEvents
Loop While Not Application.CalculationState = xlDone
'Find Last ROW
Dim LastRow As Double
LastRow = 60001 ' <-- NOTE!: YOU MUST PUT HERE MAX ROWS NUMBER ))
Do
LastRow = LastRow - 1
Loop Until Worksheets("Dynamic_Data").Range("A" & LastRow).Value <> 0
MsgBox "LastRow= " & LastRow
'Copy the Range of Data
Worksheets("Dynamic_Data").Range("A1:AB" & LastRow).Copy
'Save the CSV File
Application.DisplayAlerts = False 'IT WORKS TO DISABLE ALERT PROMPT
Set tempWB = Application.Workbooks.Add(1)
With tempWB
.Sheets(1).Range("A1").PasteSpecial xlPasteValues
.SaveAs Filename:=EA & MidName & StartName & CoverNum1 & MidName & CoverNum2 & GetNewSuffix & "G" & StartNum & MidName & "G" & EndNum & IntMax & Cover & " " & StartName & "_" & EndName & Job, FileFormat:=xlCSV, CreateBackup:=False
.Close
End With
Application.DisplayAlerts = True 'RESETS DISPLAY ALERTS
'------------------ END OF EDITED PART --------------------------------
ActiveSheet.Name = "Dynamic_Data"
Sheets("Sheetlist").Select
Range("D2").Select
End Sub
I have hit a stumbling block and could just do with some assistance please.
I have been tasked with creating a VBA Macro that looks between two date ranges in a shared inbox sub-folder in Outlook.
If the code finds any Excel documents attached to the emails within that date range it will extract the attachments and will put them into a designated shared drive folder. All of this i had working perfectly, however, I now need to change the code slightly so that on a separate sheet it adds the date the code was last ran (this I have working also) and when the code is next ran it takes the date it last ran as the "Date from" date and searches between that date and whatever the date and time is of the time you are trying to execute the code again - this is where my code isn't working.
Here is my code so far (I am not a VBA expert and some terminology may not be correct so please go easy on my code) - I have had to replace certain sensitive info with "xxxxxx" in the code below.
Sub saveOutlookAttachments()
' For this to work, you need to ensure "Microsoft Office 16.0 Object Library" is ticked
' You can find the object library in Tools -> References
' -- start of initialise all the outlook library details needed
Dim ol As Outlook.Application
Dim ns As Outlook.Namespace
Dim fol As Outlook.Folder
Dim i As Object
Dim mi As Outlook.MailItem
Dim at As Outlook.attachment
Dim Folder As MAPIFolder
Dim OutlookMail As Variant
' -- end of initialise all the outlook library details needed
' -- start of Date from and to initialising
Dim DateStart As Date
Dim DateEnd As Date
Dim DateToCheck As String
' Get the date last ran
If Sheet2.Cells(1, 2) <> "" Then
Sheet1.Cells(2, 2) = Sheet2.Cells(1, 2)
Debug.Print "Start Date is: "; Sheet1.Cells(2, 2)
Sheet1.Cells(2, 4) = Now()
Debug.Print "End Date is: "; Sheet1.Cells(2, 4)
Else
Sheet2.Cells(1, 2) = ""
Debug.Print Sheet1.Cells(2, 2)
End If
DateStart = Sheet1.Cells(2, 2) ' Cell B2
DateEnd = Sheet1.Cells(2, 4) ' Cell B4
DateToCheck = "[ReceivedTime] >= """ & DateStart & """ And [ReceivedTime] <= """ & DateEnd & """"
Debug.Print "Date to Check is: "; DateToCheck
' -- end of Date from and to initialising
' -- start of Set ol and Set ns
Set ol = New Outlook.Application
Set ns = ol.GetNamespace("MAPI")
' -- end of Set ol and Set ns
' Which folder should the script be reading from?
Set fol = ns.Folders("~ xxxxxxx ").Folders("Inbox").Folders("xxxxxxxx")
' if there is an error when the code runs then stop the script and go straight to "errordetails" found at the bottom of the screen
On Error GoTo errordetails
' For each email in the folder (Restricted to the date range entered on the Spreadsheet)
For Each i In fol.Items.Restrict(DateToCheck)
' If the email is an Outlook email
If i.Class = OlMail Then
Set mi = i
UserForm1.Show
' If there are more than 0 attachments, ie, if it finds an attachment
If mi.Attachments.Count > 0 Then
For Each at In mi.Attachments
'Debug.Print mi.SenderName & " " & mi.ReceivedTime ' <- uncomment this part if you need to debug (remember to open the "immediate" window also
' Look for attachments that contain ".xls" (this will also pick up ".xlsx" and ".xlsm" etc
If InStr(LCase(at.FileName), ".xls") > 0 Then
' Tell the script where to save the file and what details need to be appeneded to the file name to make it a unique name
at.SaveAsFile "\\xxxx\xxxxx\xxxxx\" & Format(mi.ReceivedTime, "yyyy-mm-dd hh-nn-ss") & at.FileName
Else
' literally do nothing (it's probably not needed but added just in case)
End If
Next at
End If
End If
Next i
UserForm1.Hide
CountNumberOfFiles
Sheet2.Cells(1, 1) = "Date last ran was"
Sheet2.Cells(1, 2) = Now()
errordetails:
Debug.Print "Error number: " & Err.Number _
& " " & Err.Description;
End Sub
Sub CountNumberOfFiles()
Dim FolderPath As String
Dim Path As String
Dim Count As Integer
FolderPath = "\\xxxx\xxxxxxx\xxxxxxxxx"
Path = FolderPath & "\*"
FileName = Dir(Path)
Do While FileName <> ""
Count = Count + 1
FileName = Dir()
Loop
MsgBox "Search completed. There are " & Count & " attachments extracted to the folder \\xxxxxx\xxxxxx\xxxx"
End Sub
In the Immediate window, the Debug.Print for this part does show all the correct dates and times but it says it finds nothing even when there is one item that definitely matches.
' Get the date last ran
If Sheet2.Cells(1, 2) <> "" Then
Sheet1.Cells(2, 2) = Sheet2.Cells(1, 2)
Debug.Print "Start Date is: "; Sheet1.Cells(2, 2)
Sheet1.Cells(2, 4) = Now()
Debug.Print "End Date is: "; Sheet1.Cells(2, 4)
Else
Sheet2.Cells(1, 2) = ""
Debug.Print Sheet1.Cells(2, 2)
End If
DateStart = Sheet1.Cells(2, 2) ' Cell B2
DateEnd = Sheet1.Cells(2, 4) ' Cell B4
DateToCheck = "[ReceivedTime] >= """ & DateStart & """ And [ReceivedTime] <= """ & DateEnd & """"
Debug.Print "Date to Check is: "; DateToCheck
' -- end of Date from and to initialising
Thank you in advance for any assistance provided.
Dates are DateTime, not Text, so create text expressions for the date values:
DateToCheck = "[ReceivedTime] >= #" & Format(DateStart, "yyyy\/mm\/dd") & "# And [ReceivedTime] <= #" & Format(DateEnd, "yyyy\/mm\/dd") & "#"
Addendum:
Looking up the docs (always highly recommended), it appears that criteria must be text:
Although dates and times are typically stored with a Date format, the
Find and Restrict methods require that the date and time be converted
to a string representation. To make sure that the date is formatted as
Outlook expects, use the Format function. The following example
creates a filter to find all contacts that have been modified after
January 15, 1999 at 3:30 P.M.
Example:
sFilter = "[LastModificationTime] > '" & Format("1/15/99 3:30pm", "ddddd h:nn AMPM") & "'"
So, I guess you filter should read:
DateToCheck = "[ReceivedTime] >= '" & Format(DateStart, "ddddd h:nn AMPM") & "' And [ReceivedTime] <= '" & Format(DateEnd, "ddddd h:nn AMPM") & "'"
I've got an excel script that that checks and compare dates between cells in different workbooks.
I've got four workbooks, wbk, wbkA, wbkB, wbkC, and wbkD.
Date in last cell in Column A of wbk is used as reference date
Date in Cell A9 of the rest of the workbooks is checked against reference date to check that they are one day after reference date
results are written to a log file
The script should write all results to a log (whether date is ok or not) and should only continue when all dates are ok. Ohterwise it should write to the log file which dates are not ok and exit sub.
If possible I would like to be call comparebooks from other modules instead
My problem:
Date checks work individually but I'm having trouble getting the script to check for multiple dates without running into errors
I cannot get it to work together with the writing to the log
Script to check compare dates
Sub comparebooks()
Dim dateX As Date
Dim dateA As Date
Dim dateB As Date
Dim dateC As Date
Dim dateD As Date
sFilename = ThisWorkbook.Path & "\Logs.txt"
sPath = ThisWorkbook.Path & "\Source\"
sFile = Dir(sPath & "2G Voice*.xlsx")
sFile1 = Dir(sPath & "2G Data*.xlsx")
sFile2 = Dir(sPath & "3G*.xlsx")
sFile3 = Dir(sPath & "4G*.xlsx")
'reference date file 4G
Set wbk = Workbooks.Open(ThisWorkbook.Path & "\2G.xlsx")
Set varSheet = wbk.Worksheets("2G Voice")
dateX = wbk.Worksheets("2G Voice").Range("A" & Rows.Count).End(xlUp)
'file dates to check
Set wbkA = Workbooks.Open(sPath & sFile)
Set varSheetA = wbkA.Worksheets("Sheet1")
dateA = wbkA.Worksheets("Sheet1").Range("A9")
Set wbkB = Workbooks.Open(sPath & sFile1)
Set varSheetB = wbkB.Worksheets("Sheet1")
dateB = wbkB.Worksheets("Sheet1").Range("A9")
Set wbkC = Workbooks.Open(sPath & sFile2)
Set varSheetC = wbkC.Worksheets("Sheet1")
dateC = wbkC.Worksheets("Sheet1").Range("A9")
Set wbkD = Workbooks.Open(sPath & sFile3)
Set varSheetD = wbkD.Worksheets("Sheet1")
dateD = wbkD.Worksheets("Sheet1").Range("A9")
'check 4g date
If dateA = DateAdd("d", 1, dateX) Then
Debug.Print dateA & " 2G Voice is OK"
If dateB = DateAdd("d", 1, dateX) Then
Debug.Print dateB & " 2G Data is OK"
If dateC = DateAdd("d", 1, dateX) Then
Debug.Print dateC & " 3G CS_PS is OK"
If dateD = DateAdd("d", 1, dateX) Then
Debug.Print dateD & " 4G Data is OK"
Else
Debug.Print "Date is not OK"
End If
Exit Sub
End If
End Sub
Logbook script
' Archive file at certain size
If FileLen(sFilename) > 20000 Then
FileCopy sFilename _
, Replace(sFilename, ".txt", Format(Now, "ddmmyyyy hhmmss.txt"))
Kill sFilename
End If
' Open the file to write
Dim filenumber As Variant
filenumber = FreeFile
Open sFilename For Append As #filenumber
Print #filenumber, CStr(Now) & ", " & "Missing source file: " & strType & " is missing " & chknum - i & " file(s)"
Close #filenumber
End If
Can someone please assist?
Hopefully someone could help :)
I use VBA code that runs through Microsoft Outlook Appointments, and for each appointment - prints a few details - to an Excel table.
If I set the start date of an appointment on 01-April-2019, and then postpone that appointment to 12-April-2019, and then postpone that appointment to 15-April-2019 - I have 3 "Appointment Item" objects in my folder.
I would like to print for each appointment in the folder - the "Start Date" that was set originally.
For example: Print for the first appointment - the first original start date (01-April-2019), for the first postponed appointment - the first postponed start date (12-April-2019), and for the second postponed appointment - the second postponed start date (15-April-2019).
However, when I run my code - the last "Start Date" is printed (15-April-2019, 15-April-2019, 15-April-2019), instead of the original (01-April-2019, 12-April-2019, 15-April-2019) .
I read a lot about different types of "date" objects, but couldn't find the correct one.
Could anyone help me?
Thank you very much!
Sub GetFromOutlook()
'Early Binding: Tools > References > Microsoft Outlook xx.0 Object Library > OK
Dim OutlookApp As Outlook.Application
Dim OutlookNS As Namespace
Dim Folder As MAPIFolder
Dim oApp As Outlook.Application
Dim oG As Outlook.Folder 'Method for IMAP, as used by Gmail.
Dim oM As Outlook.MeetingItem
Dim oAA As Outlook.AppointmentItem
Dim oI As Outlook.RecurrencePattern
Dim sMsg$, sAdd$
Dim i As Long
Dim j As Long
Set OutlookApp = New Outlook.Application
Set OutlookNS = OutlookApp.GetNamespace("MAPI")
Set Folder = OutlookNS.GetDefaultFolder(olFolderInbox).Parent.Folders("CCB Meetings")
Dim icon As String
Set oApp = CreateObject("Outlook.Application")
Set oG = OutlookNS.GetDefaultFolder(olFolderInbox).Parent.Folders("CCB Meetings")
For i = 1 To oG.Items.Count
If TypeName(oG.Items(i)) = "MeetingItem" Then j = j + 1
Next i
If j = 0 Then Exit Sub
' Create titles
Range("A1").Offset(0, 0).Value = "SenderName"
Range("B1").Offset(0, 0).Value = "Subject"
Range("C1").Offset(0, 0).Value = "CreationTime (Scheduled time of the first appointment)"
Range("D1").Offset(0, 0).Value = "ReceivedTime (Scheduled time of the current appointment)"
Range("E1").Offset(0, 0).Value = "Start (start time of the last scheduled appointment)"
Range("F1").Offset(0, 0).Value = "StartTime (doesnt work yet)"
Range("G1").Offset(0, 0).Value = "Location"
Range("H1").Offset(0, 0).Value = "RequiredAttendees"
Range("I1").Offset(0, 0).Value = "OptionalAttendees"
Range("J1").Offset(0, 0).Value = "ResponseStatus"
On Error Resume Next
j = 0
For i = 1 To oG.Items.Count
Set oM = oG.Items(i)
With oG.Items(i).GetAssociatedAppointment(True)
j = j + 1
Range("A1").Offset(j, 0).Value = oM.SenderName
Range("B1").Offset(j, 0).Value = oM.Subject
Range("C1").Offset(j, 0).Value = .CreationTime
Range("D1").Offset(j, 0).Value = oM.ReceivedTime
Range("E1").Offset(j, 0).Value = .Start
Range("F1").Offset(j, 0).Value = oAA.GetRecurrencePattern '??????????????????
Range("G1").Offset(j, 0).Value = .Location
Range("H1").Offset(j, 0).Value = .RequiredAttendees
Range("I1").Offset(j, 0).Value = .OptionalAttendees
Range("J1").Offset(j, 0).Value = .ResponseStatus
End With
Next i
On Error GoTo 0
Set Folder = Nothing
Set OutlookNS = Nothing
Set OutlookApp = Nothing
End Sub
You can create a UserProperties field manually or Add a UserProperties field with VBA code.
UserProperties object
UserProperties.Add method
OlUserPropertyType enumeration
Once you have the field you can enter data manually or with VBA.
With VBA consider ItemAdd. Set custom value when item moved to folder in outlook
I have just noticed Niton's latest comment. I think it is an interesting idea. I suspect you still need my investigative macro and you will still need events to create the custom property so this answer should still be useful.
I would need to invest more time than I have available at the moment to address your requirement. This answer includes what I have to hand in the hope that it will help you.
Your code suggests you do not understand recurring entries, you are not familiar with the different types of calendar items and you have misinterpreted some of the properties. If there is any detailed documentation on calendar items available via the internet, I have failed to find it. There is basic documentation (referenced below): this object has these properties; this property is a long/string/enumeration; one sentence definitions and so on. But none of this basic documentation helped me understand how, for example, exceptions related to master entries.
The code below is an Excel based investigation I conducted some months ago. I have not had the time to move to the next stage but I believe it will give you a start.
Option Explicit
Sub DiagCal()
' Outputs major properties of all calendar items within the default
' calendar for a specified date range. The objective is to better
' understand calendar items and how they link.
' Requires reference to Microsoft Outlook nn.n Library
' where "nn.n" identifies the version of Office you are using.
' 27Dec18 First version coded
' 30Dec18 This version coded
' 18Apr19 Reviewed comments and made some improvements.
' * Together these constants identify the start and length of the report period.
' * The report period starts DateReportStartOffset days before today.
' * DateReportLenType and DateReportLen are used as parameters for function DateAdd
' which is used to calculate the report period end date for the start date. See
' function DateAdd for permitted values for these constants.
' * These constants provided a convenient way of specify the start and end date
' of the report period when this macro was written. Something simpler would
' probably be better now.
Const DateReportLen As Long = 1
Const DateReportLenType As String = "yyyy"
Const DateReportStartOffset As Long = -363
Dim AppointToReport As New Collection
Dim AppOutlook As New Outlook.Application
Dim CalEnt As Object
Dim CalEntClass As Long
Dim DateReportEnd As Date
Dim DateReportStart As Date
Dim FileBody As String
Dim FldrCal As Outlook.Folder
Dim InxAir As Long
Dim InxFC As Long
Dim PathDesktop As String
PathDesktop = CreateObject("WScript.Shell").SpecialFolders("Desktop")
' Identify date range to be reported on
DateReportStart = DateSerial(Year(Now), Month(Now), Day(Now) + DateReportStartOffset)
DateReportEnd = DateAdd(DateReportLenType, DateReportLen, DateReportStart)
' This assumes the calendar of interest is the default calendar.
' Change as necessary
Set FldrCal = AppOutlook.Session.GetDefaultFolder(olFolderCalendar)
' This loop reviews the entire calendar and identifies Calendar Items
' that fall entirely or partially within the report period. All such
' Calendar Items are recorded in collection AppointToReport.
For InxFC = 1 To FldrCal.Items.Count
Set CalEnt = FldrCal.Items(InxFC)
' Occasionally I get syncronisation errors. This code avoids them.
CalEntClass = -1
On Error Resume Next
CalEntClass = CalEnt.Class
On Error GoTo 0
' I have never found anything but appointments in
' Calendar but test just in case
If CalEntClass = olAppointment Then
Call DiagCalRecordEntry(CalEnt, DateReportStart, DateReportEnd, AppointToReport)
End If
Next InxFC
FileBody = "Calendar entries within or partially within " & _
Format(DateReportStart, "d mmm yy") & _
" to " & Format(DateReportEnd, "d mmm yy") & vbLf & _
"Total calendar entries: " & FldrCal.Items.Count & vbLf & _
"Calendar entries within or partially within report period: " & _
AppointToReport.Count
' This loop outputs the major properties of every Calendar Items recorded
' in collection AppointToReport.
For InxAir = 1 To AppointToReport.Count
FileBody = FileBody & vbLf & String(70, "=")
FileBody = FileBody & vbLf & AppointToReport(InxAir)(1)
Next
Call PutTextFileUtf8NoBom(PathDesktop & "\Calendar.txt", FileBody)
End Sub
Sub DiagCalRecordEntry(ByRef CalEnt As Object, _
ByVal DateReportStart As Date, _
ByVal DateReportEnd As Date, _
ByRef AppointToReport As Collection, _
Optional ByVal OriginalDate As Date)
' If calendar entry is within or partially within report range, add
' its details to AppointToReport
Dim AllDayEvent As Boolean
Dim AppointDtls As String
Dim AppointId As String
Dim AppointIdMaster As String
Dim BusyStatus As String
Dim DateRecurrEnd As Date
Dim DateRecurrStart As Date
Dim DateAppointEnd As Date
Dim DateAppointStart As Date
Dim DayOfMonth As Long
Dim DayOfWeekMask As String
Dim DayOfWeekMaskCode As Long
Dim DurationEntry As Long
Dim DurationRecurr As Long
Dim InxE As Long
Dim Instance As Long
Dim Interval As Long
Dim Location As String
Dim MonthOfYear As Long
Dim NoEndDate As Boolean
Dim NumOccurrences As Long
Dim RecurrenceState As String
Dim RecurrenceType As String
Dim RecurrPattern As Outlook.RecurrencePattern
Dim Subject As String
Dim TimeStart As Date
Dim TimeEnd As Date
'Debug.Assert False
' Get values from calendar entry which identify if entry is within
' report range
With CalEnt
DateAppointStart = .Start
DateAppointEnd = .End
Select Case .RecurrenceState
Case olApptNotRecurring
'Debug.Assert False
RecurrenceState = "Non-recurring calendar entry"
Case olApptMaster
'Debug.Assert False
RecurrenceState = "Master calendar entry"
Case olApptException
'Debug.Assert False
RecurrenceState = "Exception to Master calendar entry"
Case olApptOccurrence
Debug.Assert False
' I believe this state can only exist if GetOccurrence() is used
' to get a single occurrence of a Master entery. I do not believe
' it can appear as a calendar entry
RecurrenceState = "Occurrence"
Case Else
Debug.Assert False
RecurrenceState = "Unrecognised (" & .RecurrenceState & ")"
End Select
End With
If RecurrenceState = "Master calendar entry" Then
'Debug.Assert False
Set RecurrPattern = CalEnt.GetRecurrencePattern()
With RecurrPattern
DateRecurrStart = .PatternStartDate
DateRecurrEnd = .PatternEndDate
End With
If DateRecurrStart <= DateReportEnd And _
DateRecurrEnd >= DateReportStart Then
' Some or all occurences of this Master entry are within report range
'Debug.Assert False
Else
' No occurences of this Master entry are within report range
'Debug.Assert False
Exit Sub
End If
Else
' Non recurring or exception appointment
If DateAppointStart <= DateReportEnd And _
DateAppointEnd >= DateReportStart Then
' Entry is within report range
'Debug.Assert False
Else
' Non recurring entry is not within report range
'Debug.Assert False
Exit Sub
End If
End If
' Calendar entry is within or partially within report period
' Get remaining properties from entry
'Debug.Assert False
With CalEnt
AllDayEvent = .AllDayEvent
AppointId = .GlobalAppointmentID
Select Case .BusyStatus
Case olBusy
'Debug.Assert False
BusyStatus = "Busy"
Case olFree
'Debug.Assert False
BusyStatus = "Free"
Case olOutOfOffice
'Debug.Assert False
BusyStatus = "Out of Office"
Case olTentative
Debug.Assert False
BusyStatus = "Tentative appointment"
Case olWorkingElsewhere
'Debug.Assert False
BusyStatus = "Working elsewhere"
Case Else
Debug.Assert False
BusyStatus = "Not recognised (" & .BusyStatus & ")"
End Select
Location = .Location
Subject = .Subject
End With
If RecurrenceState = "Exception to Master calendar entry" Then
RecurrenceState = RecurrenceState & vbLf & _
"Master's Id: " & CalEnt.Parent.GlobalAppointmentID & vbLf & _
"Original Date: " & OriginalDate
End If
AppointDtls = RecurrenceState & vbLf & _
"AllDayEvent: " & AllDayEvent & vbLf & _
"AppointId: " & AppointId & vbLf & _
"BusyStatus: " & BusyStatus & vbLf & _
"DateAppointStart: " & DateAppointStart & vbLf & _
"DateAppointEnd: " & DateAppointEnd & vbLf & _
"DurationEntry: " & DurationEntry & vbLf & _
"Location: " & Location & vbLf & _
"Subject: " & Subject
If RecurrenceState <> "Master calendar entry" Then
' AppointDtls complete for this appointment
Call StoreSingleAppoint(Format(DateAppointStart, "yyyymmddhhmm"), _
AppointDtls, AppointToReport)
Else
'Debug.Assert False
With RecurrPattern
' Not all parameters have a meaningful value for all RecurrenceTypes
' but the value always appears to be of the correct data type.
DateRecurrStart = .PatternStartDate
DateRecurrEnd = .PatternEndDate
DayOfMonth = .DayOfMonth
DayOfWeekMaskCode = .DayOfWeekMask
DayOfWeekMask = ""
If DayOfWeekMaskCode >= olSaturday Then
Debug.Assert False
DayOfWeekMask = "+Saturday"
DayOfWeekMaskCode = DayOfWeekMaskCode - olSaturday
End If
If DayOfWeekMaskCode >= olFriday Then
'Debug.Assert False
DayOfWeekMask = "+Friday" & DayOfWeekMask
DayOfWeekMaskCode = DayOfWeekMaskCode - olFriday
End If
If DayOfWeekMaskCode >= olThursday Then
'Debug.Assert False
DayOfWeekMask = "+Thursday" & DayOfWeekMask
DayOfWeekMaskCode = DayOfWeekMaskCode - olThursday
End If
If DayOfWeekMaskCode >= olWednesday Then
'Debug.Assert False
DayOfWeekMask = "+Wednesday" & DayOfWeekMask
DayOfWeekMaskCode = DayOfWeekMaskCode - olWednesday
End If
If DayOfWeekMaskCode >= olTuesday Then
'Debug.Assert False
DayOfWeekMask = "+Tuesday" & DayOfWeekMask
DayOfWeekMaskCode = DayOfWeekMaskCode - olTuesday
End If
If DayOfWeekMaskCode >= olMonday Then
'Debug.Assert False
DayOfWeekMask = "+Monday" & DayOfWeekMask
DayOfWeekMaskCode = DayOfWeekMaskCode - olMonday
End If
If DayOfWeekMaskCode >= olSunday Then
'Debug.Assert False
DayOfWeekMask = "+Sunday" & DayOfWeekMask
End If
If DayOfWeekMask = "" Then
'Debug.Assert False
DayOfWeekMask = "None"
Else
'Debug.Assert False
DayOfWeekMask = Mid$(DayOfWeekMask, 2) ' Remove leading +
End If
DurationRecurr = .Duration
Instance = .Instance
Interval = .Interval
MonthOfYear = .MonthOfYear
NoEndDate = .NoEndDate
NumOccurrences = .Occurrences
Select Case .RecurrenceType
Case olRecursDaily
'Debug.Assert False
RecurrenceType = "Daily"
Case olRecursMonthly
Debug.Assert False
RecurrenceType = "Monthly"
Case olRecursMonthNth
Debug.Assert False
RecurrenceType = "MonthNth"
Case olRecursWeekly
'Debug.Assert False
RecurrenceType = "Weekly"
Case olRecursYearly
'Debug.Assert False
RecurrenceType = "Yearly"
Case olRecursYearNth
Debug.Assert False
RecurrenceType = "YearNth"
Case Else
Debug.Assert False
RecurrenceType = "Unrecognised Value (" & RecurrenceType & ")"
End Select
TimeStart = .StartTime
TimeEnd = .EndTime
End With
AppointDtls = AppointDtls & vbLf & "DateRecurrStart: " & DateRecurrStart _
& vbLf & "DateRecurrEnd: " & DateRecurrEnd _
& vbLf & "DayOfMonth: " & DayOfMonth _
& vbLf & "DayOfWeekMask: " & DayOfWeekMask _
& vbLf & "DurationRecurr: " & DurationRecurr _
& vbLf & "Instance: " & Instance _
& vbLf & "Interval: " & Interval _
& vbLf & "MonthOfYear: " & MonthOfYear _
& vbLf & "NoEndDate: " & NoEndDate _
& vbLf & "NumOccurrences: " & NumOccurrences _
& vbLf & "RecurrenceType: " & RecurrenceType _
& vbLf & "TimeStart: " & TimeStart & " (" & CDbl(TimeStart) & ")" _
& vbLf & "TimeEnd: " & TimeEnd & " (" & CDbl(TimeEnd) & ")"
For InxE = 1 To RecurrPattern.Exceptions.Count
AppointDtls = AppointDtls & vbLf & "Exception " & InxE & " for occurrence on " & _
RecurrPattern.Exceptions.Item(InxE).OriginalDate
Next
Call StoreSingleAppoint(Format(DateRecurrStart, "yyyymmddhhmm"), _
AppointDtls, AppointToReport)
For InxE = 1 To RecurrPattern.Exceptions.Count
Call DiagCalRecordEntry(RecurrPattern.Exceptions.Item(InxE).AppointmentItem, _
DateReportStart, DateReportEnd, AppointToReport, _
RecurrPattern.Exceptions.Item(InxE).OriginalDate)
Next
End If ' RecurrenceState <> "Master calendar entry"
End Sub
Public Sub PutTextFileUtf8NoBom(ByVal PathFileName As String, ByVal FileBody As String)
' Outputs FileBody as a text file named PathFileName using
' UTF-8 encoding without leading BOM
' Needs reference to "Microsoft ActiveX Data Objects n.n Library"
' Addition to original code says version 2.5. Tested with version 6.1.
' 1Nov16 Copied from http://stackoverflow.com/a/4461250/973283
' but replaced literals with parameters.
' 15Aug17 Discovered routine was adding an LF to the end of the file.
' Added code to discard that LF.
' 11Oct17 Posted to StackOverflow
' 9Aug18 Comment from rellampec suggested removal of adWriteLine from
' WriteTest statement would avoid adding LF.
' 30Sep18 Amended routine to remove adWriteLine from WriteTest statement
' and code to remove LF from file. Successfully tested new version.
' References: http://stackoverflow.com/a/4461250/973283
' https://www.w3schools.com/asp/ado_ref_stream.asp
Dim BinaryStream As Object
Dim UTFStream As Object
Set UTFStream = CreateObject("adodb.stream")
UTFStream.Type = adTypeText
UTFStream.Mode = adModeReadWrite
UTFStream.Charset = "UTF-8"
UTFStream.Open
UTFStream.WriteText FileBody
UTFStream.Position = 3 'skip BOM
Set BinaryStream = CreateObject("adodb.stream")
BinaryStream.Type = adTypeBinary
BinaryStream.Mode = adModeReadWrite
BinaryStream.Open
UTFStream.CopyTo BinaryStream
UTFStream.Flush
UTFStream.Close
Set UTFStream = Nothing
BinaryStream.SaveToFile PathFileName, adSaveCreateOverWrite
BinaryStream.Flush
BinaryStream.Close
Set BinaryStream = Nothing
End Sub
Sub StoreSingleAppoint(ByVal SeqKey As String, _
ByVal AppointDtls As String, _
ByRef AppointToReport As Collection)
' Entries in AppointToReport are of the form:
' VBA.Array(SeqKey, AppointDtls)
' Add new entry to AppointToReport so entries are in ascending order by SeqKey
Dim InxAtr As Long
If AppointToReport.Count = 0 Then
'Debug.Assert False
' first appointment
AppointToReport.Add VBA.Array(SeqKey, AppointDtls)
Else
For InxAtr = AppointToReport.Count To 1 Step -1
If SeqKey >= AppointToReport(InxAtr)(0) Then
' New appointment belongs after this existing entry
'Debug.Assert False
AppointToReport.Add VBA.Array(SeqKey, AppointDtls), , , InxAtr
Exit Sub
End If
Next
' If get here, new appointment belongs before all existing appointments
'Debug.Assert False
AppointToReport.Add VBA.Array(SeqKey, AppointDtls), , 1
End If
End Sub
Create a macro-enabled workbook and copy the above code to a module.
Near the top of the code you will find:
' Identify date range to be reported on
DateReportStart = DateSerial(Year(Now), Month(Now), Day(Now) + DateReportStartOffset)
DateReportEnd = DateAdd(DateReportLenType, DateReportLen, DateReportStart)
I suggest replacing these statements with something simple like:
DateReportStart = #4/15/2019#
DateReportEnd = #4/18/2019#
Warning: VBA date literals use middle-endian format which confuses everyone except civilian Americans.
Macro DiagCal() creates a desktop file named “Calendar.txt” containing details of every calendar item that is entirely or partially within the report period. When I tested it, I created every sort of calendar entry: single appointments; entries recurring by day, week, month, year; weekly patterns; multi-day, all-day and part-day events; exceptions to instances of recurring entries and so on.
Visit https://learn.microsoft.com/en-us/office/vba/api/Outlook.AppointmentItem
On the left is an index with entries for the events, methods and properties of an appointment item. Expand the properties and methods and look for information that did not interest me but might interest you. Look through my code and workout how to add that information. If you cannot see how to add information, report the information you want in a comment and I will add it for you.
Expand the events and study what is available. I have never used appointment item events. I have found events easy enough to use with mail items so I assume appointment items will be similar. It is not immediate clear to me which would be the best events to use. I think you need to know when a new item is added and when an item is changed. I would try some of these events and write code to output a few properties to the Immediate Windows to better understand when these events are triggered and what data is available.
I believe you will have to initialise your workbook with code something like my macro which extracts the interesting properties of existing appointment items. You then need events to output the interesting properties of new or changed events.
I would not use events to update the workbook. (1) If you update the workbook in real time there will probably be a noticeable delay while the event is processed. (2) The update code is likely to be complex and unlikely to be correct on first attempt. If you update the workbook in real time, you will have to cause the events to be triggered again and again until you get the code right.
I would get each event to output a small text file, containing the interesting properties, to a suitable disc folder. Outputting a text file will be take little time and should not be noticeable to the user. These text files can be used again and again to update the workbook until you get the code right.
I hope the above gives you some ideas.
I run a report on a daily basis called "Contract Values UK - dd-mm-yy"
where dd-mm-yy represents the day month and year the report was run.
I've tried the below code but this seems unable to locate the file.
Can someone help me adapt the below code - many thanks.
Sub OpenLatest()
a matching date
Dim dtTestDate As Date
Dim sStartWB As String
Const sPath As String = "C:\Users\Documents\Weekly Contract Values Analysis\"
Const dtEarliest = #1/1/2018#
dtTestDate = Date
sStartWB = ActiveWorkbook.Name
While ActiveWorkbook.Name = sStartWB And dtTestDate >= dtEarliest
On Error Resume Next
Workbooks.Open sPath & "Contract Values UK - " & Format(dtTestDate, "(DD-MM-YY)") & ".xlsm"
dtTestDate = dtTestDate - 1
On Error GoTo 0
Wend
If ActiveWorkbook.Name = sStartWB Then MsgBox "Earlier file not found."
End Sub
Is this what you are trying? (Untested)
I am assuming the file name is like Contract Values UK - dd-mm-yy.xlsm
Const sPath As String = "C:\Users\Documents\Weekly Contract Values Analysis\"
Const dtEarliest = #1/1/2018#
Sub Sample()
Dim i As Long
Dim dt As Date: dt = Date
Dim flName As String, dtPart As String
'~~> Loop through dates in reverse
For i = dt To dtEarliest Step -1
dtPart = Format(i, "dd-mm-yy")
'~~> Create your file name
flName = "Contract Values UK - " & dtPart & ".xlsm"
'~~> Check if exists
If Dir(sPath & flName) <> "" Then
MsgBox sPath & flName '<~~ You can now work with this file
Exit For
End If
Next i
End Sub