VBA - Save macro naming workbook - vba

I have code below to save the current workbook and attach today's date to the end of the file name. How would I modify the code so if two copies of the workbook were to be saved on the same day, the first one would save normally as "Workbook Name, Today's Date.xlsm" and the second one would save as "Workbook Name, Today's Date Copy 2.xlsm" instead of "Workbook Name, Today's Date, Today's Date.xlsm" (Attaching the Date twice to the end of the file name, which is what it does now). Same thing if the workbook were to be saved 3,4,5 times a day they should save as Copy 3,4,5,etc...
`Sub Save_Workbook()
Const Path = "H:\HR\Cole G\Timehseet Test Path\"
Dim FileName As String
Dim Pos As Long
Pos = InStrRev(ActiveWorkbook.Name, ".") - 1
' If there wasn't a ".", then the file doesn't have an extension and Pos = -1
If Pos < 0 Then Pos = Len(ActiveWorkbook.Name)
' Now put everything together, including the file extension...
ActiveWorkbook.SaveAs Path & Left(ActiveWorkbook.Name, Pos) & Format (Now, "d-mm-yyyy") & Mid(ActiveWorkbook.Name, Pos + 1)
End Sub`

You could try a recursive approach like so (not tested):
Sub CreateCopyFile(ByVal oldFileName As String, Optional ByVal copyNo As Long = 1)
If FileLen(oldFileName & " Copy (" & copyNo & ")") Then
CreateCopyFile(oldFileName, copyNo + 1)
Else
ActiveWorkbook.SaveAs oldFileName & " Copy (" & copyNo & ")"
End If
End Sub
Then change your code to the following:
Dim potentialFileName As String
potentialFileName = Path & Left(ActiveWorkbook.Name, Pos) & Format(Now, "d-mm-yyyy") & Mid(ActiveWorkbook.Name, Pos + 1)
If FileLen(potentialFileName) Then
CreateCopyFile(potentialFileName)
Else
ActiveWorkbook.SaveAs potentialFileName
End If
'// rest of code here....
There used to be a cleaner way of doing this using a command prompt, however in recent years it seems that Windows no longer allows the use of it via VBA without changing security settings (which I do not advise...)

If Dir(Path & Left(ActiveWorkbook.Name, Pos) & Format (Now, "d-mm-yyyy") & Mid(ActiveWorkbook.Name, Pos + 1)) <> "" Then
ActiveWorkbook.SaveAs Filename:=Path & Left(ActiveWorkbook.Name, Pos) & copy 2 & Mid(ActiveWorkbook.Name, Pos + 1)
Else
ActiveWorkbook.SaveAs Filename:=Path & Left(ActiveWorkbook.Name, Pos) & Format (Now, "d-mm-yyyy") & Mid(ActiveWorkbook.Name, Pos + 1)
use this to save your file

Related

VBA - Comparing Layouts of Two Files

I am trying to figure out how to check that the layout (not the full content) of a CSV file is the same of that in the preceding month (or, if that file doesn't exist, the last available CSV file).
Often companies change the format/layout of their CSV extracts, so I want my code to automatically detect any changes (new columns added, changing order of columns, etc).
Please let me know if you have an idea of how this could be achieved!
Thanks in advance!
Please, try the next code. It assumes that the csv to be compared is comma separated and ending lines are vbCrLf:
Private Sub CheckCSVfile()
Dim ws As Worksheet, strFile As String, ans As VbMsgBoxResult, sep As String
Dim arrRef, arrCSV, cols, i As Long, strProbl As String
ans = MsgBox("Is the active sheet the one you wan to use as reference to compare the CSV file structure?" & vbCrLf & _
"If this is the situation, please press ""Yes""!", vbYesNo, "Confirm the active sheet as reference")
If ans <> vbYes Then Exit Sub
Set ws = ActiveSheet
'Put the first sheet row values in an array (2D array):
arrRef = ws.Range(ws.cells(1, 1), ws.cells(1, ws.cells(1, ws.Columns.count).End(xlToLeft).Column)).value
''Browse for the .csv file to be checked:
strFile = Application.GetOpenFilename("Text Files (*.csv),*.csv", , "Please select the csv file to be checked.")
If strFile = "False" Then Exit Sub
'Put the content of the csv file in an array (split by the line ending separator). If not vbCrLf, use the appropriate one:
arrCSV = Split(CreateObject("Scripting.FileSystemObject").OpenTextFile(strFile, 1).ReadAll, vbCrLf)
sep = "," 'the csv file separator. Use here the correct one if not comma
cols = Split(arrCSV(0), sep) 'number of columns of the first csv file row (zero based array)
If UBound(cols) + 1 <> UBound(arrRef, 2) Then '+ 1 for the first array because it is of 0 based type
strProbl = strProbl & "The number of columns in the new csv file is different (" & UBound(cols) & " against " & UBound(arrRef) & ")." & vbCrLf
End If
'Comparing each header:
For i = 0 To UBound(arrRef, 2) - 1
If UCase(arrRef(1, i + 1)) <> UCase(cols(i)) Then
strProbl = strProbl & "The value in the column " & i + 1 & " is different (" & cols(i) & " against " & arrRef(1, i + 1) & ")" & vbCrLf
End If
Next i
Stop
If strProbl <> "" Then
MsgBox "The new csv file has a different structure: " & vbCrLf & vbCrLf & strProbl, vbCritical, "Structure problems..."
Else
MsgBox "The both files structure is the same!", vbInformation, "No any structure problem"
End If
End Sub
You must firstly open and activate the sheet of the previous csv file (to be used as reference) and then run the above code.
Please, send some feedback after testing it...

VBA - Saving multiple copies of a workbook with a specific naming convention

I have code below to save the current workbook and attach today's date to the end of the file name. How would I modify the code so if two copies of the workbook were to be saved on the same day, the first one would save normally as "Workbook Name, Today's Date.xlsm" and the second one would save as "Workbook Name, Today's Date Copy 2.xlsm". Same thing if the workbook were to be saved 3,4,5 times a day they should save as Copy 3,4,5,etc...
Sub Save_Workbook()
Const Path = "H:\HR\Cole G\Timehseet Test Path\"
Dim FileName As String
Dim Pos As Long
Pos = InStrRev(ActiveWorkbook.Name, ".") - 1
' If there wasn't a ".", then the file doesn't have an extension and Pos = -1
If Dir(Path & Left(ActiveWorkbook.Name, Pos) & Format(Now, "d-mm-yyyy") & Mid(ActiveWorkbook.Name, Pos + 1)) <> "" Then
ActiveWorkbook.SaveAs FileName:=Path & Left(ActiveWorkbook.Name, Pos) & "copy 2" & Mid(ActiveWorkbook.Name, Pos + 1)
Else
ActiveWorkbook.SaveAs FileName:=Path & Left(ActiveWorkbook.Name, Pos) & Format(Now, "d-mm-yyyy") & Mid(ActiveWorkbook.Name, Pos + 1)
End If
End Sub
Instead of appending "Copy xxx", why not to append the time?
eg
"Workbook Name, 2018-04-05 12.30.23.xlsm"
Well, the question could be changed a bit, to get what you are looking for. In general, you are looking for a function, which splits some strings by dots and spaces and increments the last one with 1.
E.g., if this is your input:
"WorkbookName 12.12.12.xlsm"
"WorkbookName 13.18.22 Copy 230.xlsm"
"WorkbookName 12.11.19 Copy 999.xlsm"
Your function should give the folowing output:
"WorkbookName 12.12.12.xlsm"
"WorkbookName 13.18.231.xlsm"
"WorkbookName 12.11.1000.xlsm"
Once you achieve this, the saving of the workbook could be carried out through that function. This is some function that gets that output:
Sub TestMe()
Dim path1 As String: path1 = "WorkbookName 12.12.12.xlsm"
Dim path2 As String: path2 = "WorkbookName 13.18.22 Copy 230.xlsm"
Dim path3 As String: path3 = "WorkbookName 12.11.19 Copy 999.xlsm"
Debug.Print changeName(path1)
Debug.Print changeName(path2)
Debug.Print changeName(path3)
End Sub
Public Function changeName(path As String) As String
changeName = path
Dim varArr As Variant
varArr = Split(path, ".")
Dim splitNumber As Long
splitNumber = UBound(varArr)
Dim preLast As String: preLast = varArr(splitNumber - 1)
If IsNumeric(preLast) Then Exit Function
Dim lastWithSpace As String
lastWithSpace = Split(preLast)(UBound(Split(preLast)))
Dim incrementSome As String
incrementSome = Left(preLast, Len(preLast) - Len(lastWithSpace))
If IsNumeric(lastWithSpace) Then
preLast = Split(preLast)(UBound(Split(preLast))) + 1
varArr(splitNumber - 1) = incrementSome & preLast
changeName = Join(varArr, ".")
End If
End Function
The changeName function could be a bit sanitized, with some checks, whether UBound-1 exists in order to avoid error.The function splits the input string to array by . symbol and works with the pre-last value received. Then, if the value is numeric, it does nothing, but if the value looks like this 22 Copy 230, it splits once again and increments the last element with one.
At the end it returns the string.
If you need to check the date as well, then one more layer of splits and arrays should be added.
Listen, you added a comma after the original name, Great! (now use it)
Dim FileName as String, FileExtension as String
FileName = "Workbook Name, Today's Date Copy 2.xlsm"
Pos = InStrRev(FileName, ".") - 1
FileExtension = ".xlsx" ' <-- Set a default
If Pos > 0 then
FileExtension = Mid(FileName, Pos)
FileName = Left(FileName, Pos)
End if
FileExtension has been pulled out from the FileName, and the Filename doesn't have an extension anymore. Now lets go after the Comma
Pos = InStrRev(FileName, ",")
If Pos2 > 0 then FileName = Left(FileName, Pos2 -1)
That was easy, FileName has now been cleaned of the Date and Copy junk. While you could have looked for the copy before we cleaned it, I think it's easier to just try a few times, since you're going to want to check if the file exists anyway.
You can alternatively just add the time like PhantomLord mentioned.
Dim Try as long
Dim FullName as String
Try = 0
FullName = Path & FileName & Format(Now, ", d-mm-yyyy") & FileExtension
' Lets put a safety limit to stop the code if something goes wrong
Do While Try < 1000 And Dir(FullName) = vbNullString
Try = Try + 1
FullName = Path & FileName & Format(Now, ", d-mm-yyyy") & " Copy " & IIF(Try > 1, Try, vbNullString) & FileExtension
Loop
ActiveWorkbook.SaveAs FileName:=FullName
I even thru in the IIF() for fun!

Creating a macro that resets file and saves as new day

At work, I've been trying to create a macro that will automatically clear a certain range - only content -, the range being B78:G83.
After clearing this range, I'd like the macro to save the current file under a new name. The new name should be the current day, with format "dd mmmm" (two digits for the name, a space in between and then the full month's name)
The file path is (f.e.)
"T:\RESERVATIONS\Duty Report\2017\4. April\25 april"
with the year, month and current date being variable (as we make separate folders for these files at work).
Sub NieuweDag()
'
' NieuweDag Macro
' Invoer wissen en opslaan als nieuwe dag
'
' Sneltoets: Ctrl+q
'
Range("B78:G83").Select
Range("G82").Activate
Selection.ClearContents
Dim FilePath As String
Dim NewName As String
FilePath = "T:\RESERVATIONS\Duty Report\": NewName = FilePath & Year(Now()) & "\" & Month(Now()) & ". " & MonthName(Now()) & "\" & Format(Date, "dd mmmm") & ".xlsm"
ActiveWorkbook.SaveAs Filename:=NewName, FileFormat _
:=xlOpenXMLWorkbookMacroEnabled, CreateBackup:=False
End Sub
This is what I've got but it doesn't work. I get Error 5. It's in dutch, so allow me to translate:
Error 5 during launch:
Invalid procedure-call or invalid argument
Anyone out here be able to help me out?
The proper format is MonthName(number of month, [abbreviate]), you should use
MonthName(Month(Now()))
instead of
MonthName(Now())
Plus, you can enhance your code by using
Range("B78:G83").ClearContents
instead of
Range("B78:G83").Select
Range("G82").Activate
Selection.ClearContents
You can reduce the amount of coding required to create NewName by changing
NewName = FilePath & Year(Now()) & "\" & Month(Now()) & ". " & MonthName(Now()) & "\" & Format(Date, "dd mmmm") & ".xlsm"
to
NewName = FilePath & Format(Now(), "yyyy\\m. mmmm\\dd mmmm") & ".xlsm"

VBA:adding files with new version _vX, with separate dates

I am having trouble with creating new version, with the dates selected by the users.
So here I have 2 separate workbooks:
1) Macro - where the users will click the button and generate the macro
2) Report template - when the users click the macro, the figures will be generated into the templates, with the dates in the naming convention, and the version.
The report template naming convention looks like this : BSLCT_DDMMYYYYG where DDMMYYYY is the date, that the users will select in the report template.
So when the report is generated, it will SaveAs another file i.e BSLCT_10072020G.
The code I used to generate is as follow:
Sub Naming reports()
Windows("BSTCT_DDMMYYYYG.xls").Activate
Sheets("G.0(GenInfo)").Select
ActiveWorkbook.SaveAs Path & "\BSLCT_" & REPORT_DATE & "G.xls"
ActiveWorkbook.Close
End Sub
where i define the REPORT_DATE before that.
Now, the users need to have a versioning in their file naming as well, which is something like BSTCT_DDMMYYYYG_vX.xls. So as long as the users run the macro, the macro will generate a new version, regardless of whether the date has already existed.
I managed to create a _v1 using the following codes:
Sub version
Windows("BSTCT_DDMMYYYYG.xls").Activate
Sheets("G.0(GenInfo)").Select
If InStr(ActiveWorkbook.Name, "_v") = 0 Then
fileName = ActiveWorkbook.Path & "\" & Left(ActiveWorkbook.Name,
InStr(ActiveWorkbook.Name, ".") - 1) & "_v1." & ext
ActiveWorkbook.SaveAs (fileName)
Else
index = CInt(Split(Right(ActiveWorkbook.Name, Len(ActiveWorkbook.Name) - InStr(ActiveWorkbook.Name, "_v") - 1), ".")(0))
index = index + 1
fileName = ActiveWorkbook.Path & "\" & Left(ActiveWorkbook.Name,InStr(ActiveWorkbook.Name, "_v") - 1) & "_v" & index & "." & ext
End If
ActiveWorkbook.SaveAs (fileName)
End Sub
However, after generating the v1, I couldn't generate v1 onwards, because i need to activate the "BSTCT_DDMMYYYYG.xls" window to pick up the report date, this will then break my codes.
Also, while I am adding the version, at the same time i would like to get the DDMMYYYY into the naming too.
How can I do that?
I really appreciate your helps.
now i am trying to keep adding the newer version with the following code:
Sub SaveNewVersion()
Dim fileName As String, index As Long, ext As String, sVersion As String
arr = Split(ActiveWorkbook.Name, ".")
ext = arr(UBound(arr))
sVersion = "_v"
Windows("BSLCT_DDMMYYYYG.xls").Activate
Sheets("G.0(GenInfo)").Select
If InStr(ActiveWorkbook.Name, "_v") = 0 Then
fileName = ActiveWorkbook.Path & "" & Left(ActiveWorkbook.Name, InStr(ActiveWorkbook.Name, ".") - 1) & "_v1." & ext
ActiveWorkbook.SaveAs "\BSLCT_" & REPORT_DATE & "G" & sVersion & index & ".xls"
Else
index = CInt(Split(Right(ActiveWorkbook.Name, Len(ActiveWorkbook.Name) - InStr(ActiveWorkbook.Name, "_v") - 1), ".")(0))
index = index + 1
fileName = ActiveWorkbook.Path & "" & Left(ActiveWorkbook.Name, InStr(ActiveWorkbook.Name, "_v") - 1) & "_v" & index & "." & ext
ActiveWorkbook.SaveAs "\BSLCT_" & REPORT_DATE & "G " & sVersion & index & ".xls"
End If
ActiveWorkbook.Close
End Sub
but at first it keeps replacing my first version, and then saying that this line of code:
index = CInt(Split(Right(ActiveWorkbook.Name, Len(ActiveWorkbook.Name) - InStr(ActiveWorkbook.Name, "_v") - 1), ".")(0)) has syntax error.
Does anyone can help on this? I am really clueless where can I modify this.
Try this:
Sub SetNewName()
Dim wbk As Workbook
Dim sDate As String
Dim sVersion As String
sDate = Format(Date, "ddMMyyyy")
sVersion = "_v1"
Set wbk = Application.Workbooks("BSTCT_DDMMYYYYG.xls")
wbk.SaveAs ActiveWorkbook.Path & "\" & sDate & sVersion & ".xls"
End Sub

Correct Excel Macro to Save A Copy Excel File as TXT or CSV

So I have this home-made Excel Macro Template.
The task of the macro code that I inserted in my xlsm file is to Save a copy in the same folder with a different format. That format is .txt (see image below)
The expected result of the macro (after saving) should be the same with the excel file (visually) but this time it is in a .txt format.
Unfortunately, that didn't happened. It generates a different txt file and it contains unreadable alpha numeric characters, here's an example of the generated txt file.
¬TËNÃ0 ¼#ñ ‘¯(vဠjÚ # °µ· ©c[^SÚ¿g“–
P ö '±wfvìq 8o\1ÃD6øJœËž(Ðë`¬ŸTâõå¾¼ eð \ðX‰ ’ NOú/‹ˆTpµ§JÔ9Çk¥H×Ø É ÑóÌ8¤ 2 ¦‰Š §0AuÑë]* |FŸËÜbˆAÿ Çðîrq7çßK%#ëEq³\×RU btVCf¡jæ l¨ã±Õ(g#xJá
u j#XBG{Ð~J.Wr%WvŒTÛHgÜÓ †vf»ÜUÝ#ûœ¬Áâ R~€†›Rs§>BšŽB˜ÊÝ «žq®ÑIª ³l#§pçaä ý ë¿ î`ê*IuÃù ( ³´Ü ýÞð JŠ Át` “m'Ýû ™ ªîy¸„ f !å…C:r·KÐ}Ì5$4Ï9q Ž.à;ö. ¼] H ¼„ÿwá+mu S¶¸ŽÃ¦Ã¶fäÔ l;¶×‚A³ [u×Ðà ÿÿ PK ! µU0#ô L _rels/.rels ¢ (
Here's my macro code:
Sub SaveMe()
Dim FName As Range
Dim firstDate As String
Dim firstTime As String
Dim answer As Integer
firstDate = Format(Date, "mmddyyyy")
firstTime = Format(Now, "hhmmssAM/PM")
Set FName = Range("H5")
ActiveWorkbook.SaveCopyAs FileName:=ActiveWorkbook.Path & "\" & "QB JE " & FName & " " & firstDate & " " & firstTime & ".txt", FileFormat:=xlText, CreateBackup:=False
End Sub
I was wondering if anyone could take a look at my code and help to point out whats wrong.
It looks like you want the SaveAs Not the SaveCopyAs.
Fileformat xlText or xlTextMSDOS
You can two step the process. Save a copy, then open it, and save it as a text file.
ActiveWorkbook.SaveCopyAs FileName:=ActiveWorkbook.Path & "\" & "QB JE " & FName & " " & firstDate & " " & firstTime & ".xlsx"
Workbooks.Open (ActiveWorkbook.Path & "\" & "QB JE " & FName & " " & firstDate & " " & firstTime & ".xlsx")
ActiveWorkbook.SaveAs FileName:=ActiveWorkbook.Path & "\" & "QB JE " & FName & " " & firstDate & " " & firstTime & ".txt", FileFormat:=xlText, CreateBackup:=False
https://msdn.microsoft.com/en-us/library/office/ff841185.aspx
https://msdn.microsoft.com/en-us/library/office/ff198017.aspx
See from my post here. Excel VBA Export To Text File with Fixed Column Width + Specified Row and Columns Only + Transpose
Loop all rows and all cells. Send each value to a padspace function. Build the string from for each cells value with spaces padded after the cell value.
You will have to add a reference to you workbook. In the VBA IDE go to the tools pull down menu and select references. Then scroll down and select "Microsoft Scripting Runtime". Then hit OK.
Adjust the pad space function call argument to a number that fits the data that you have in your spreadsheet. So you will change the 20 in the line with the padspace call. PadSpace(20, len(cellValue))
This will do all rows and columns.
Public Sub MyMacro()
Dim lRow As Long
Dim lCol As Long
Dim strRow As String
Dim ws As Excel.Worksheet
Dim ts As TextStream
Dim fs As FileSystemObject
'Create the text file to write to
Set fs = New FileSystemObject
Set ts = fs.CreateTextFile("C:\Temp\test.txt", True, False)
Set ws = Application.ActiveSheet
'Loop through all the rows.
lRow = 1
Do While lRow <= ws.UsedRange.Rows.count
'Clear the string we are building
strRow = ""
'Loop through all the columns for the current row.
lCol = 1
Do While lCol <= ws.UsedRange.Columns.count
'Build a string to write out.
strRow = strRow & ws.Cells(lRow, lCol) & PadSpace(20, Len(ws.Cells(lRow, lCol)))
lCol = lCol + 1
Loop
'Write the line to the text file
ts.WriteLine strRow
lRow = lRow + 1
ws.Range("A" & lRow).Activate
Loop
ts.Close: Set ts = Nothing
Set fs = Nothing
End Sub
'This function will take the max number of spaces you want and the length of the string in the cell and return you the string of spaces to pad.
Public Function PadSpace(nMaxSpace As Integer, nNumSpace As Integer) As String
If nMaxSpace < nNumSpace Then
PadSpace = ""
Else
PadSpace = Space(nMaxSpace - nNumSpace)
End If
End Function