How to get yyyy-mm-dd from mm/dd/yyy in Excel - excel

I have a date in mm/dd/yyyy format from a textbox in a userform, and I want to get each value mm, dd, and yyyy to a number. (Example, 10/12/2020 would become 2020-10-12)
Here is my code so far, which gets the month part finished.
Dim DateDay As String, DateMonth As String, DateYear As String
Dim firstslash As Integer, secondslash As Integer
firstslash = InStr(TextBox3, "/")
DateMonth = Left(TextBox3, firstslash - 1)
If Len(DateMonth) = 1 Then
DateMonth = "0" & DateMonth
End If
'code for day and year
MsgBox("Date =" & DateYear & "-" & DateMonth & "-" & DateDay)
How can I add to this so it can get the day and year part as well?

The trick is to be sure that you are dealing with a date, that is a large integer (43861 for today). Therefore you should convert whatever is in the textbox to an integer representing a date. That true date you can then present in any format you want. The code below does exactly that.
Private Sub CallExtractDate()
Dim Dat As Date
Dat = ExtractDate("01/31/2020")
MsgBox Format(Dat, "yyyy-mm-dd") & vbCr & _
Format(Dat, "ddd, dd mmm, yyyy") & vbCr & _
Format(Dat, "dddd")
End Sub
Function ExtractDate(ByVal TxtDate As String) As Date
Dim Sp() As String
If IsDate(TxtDate) Then
ExtractDate = CDate(TxtDate)
Else
Sp = Split(TxtDate, "/")
On Error Resume Next
ExtractDate = DateSerial(Int(Sp(2)), Int(Sp(0)), Int(Sp(1)))
End If
End Function
In your project you would probably use the function with a call like this.
Dat = ExtractDate(TextBox1.Value)

Related

Split date/time not working when 12:00:00 AM

I have vba function to split date/time on my worksheet
but when it find 0:00AM it will stop and I don't know how to fix this
code
Function extractDateTime(strTime As Date) As Variant
Dim arrD, d As String, t As Date
arrD = Split(strTime, " ")
d = arrD(0)
t = CDate(arrD(1) & " " & arrD(2))
extractDateTime = Array(d, t)
End Function
pic when it find date/time at 12:00:00 AM
function not return value arrD(1) and arrD(2)
cell value
pic when function normally working
Always handle date/time as Date, not text, not numbers, no exceptions. So:
Public Function ExtractDateTime(Value As Date) As Variant
Dim d As Date
Dim t As Date
d = DateValue(Value)
t = TimeValue(Value)
ExtractDateTime = Array(d, t)
End Function
Parsing the Date for spaces is not a great way to go about it.
Instead, you can use Format to just get the pieces you want.
Function extractDateTime(dt As Date) As Variant
Dim d As String, t As String
d = Format(dt, "dd/mm/yyyy")
t = Format(dt, "hh:mm:ss AMPM")
extractDateTime = Array(d, t)
Debug.Print d
Debug.Print t
Debug.Print Format(dt, "mmm dd, yyyy")
Debug.Print Format(dt, "mmmm")
Debug.Print WeekdayName(Weekday(dt))
End Function
Kinda seems like a waste of a function tho when you can just do this:
Result = Array(Format(dt, "dd/mm/yyyy"), Format(dt, "hh:mm:ss AMPM"))

Sequencing a part number using User Form

I am completely new in VBA or programming. Right now I am developing a macro for a manufacturing site that inputs process data using Excel's User Forms. One of the things I want this macro to do is to automatically create run numbers for each process. The run number syntax we use is as follows:
V1.yy.mm.dd-1
V1.yy.mm.dd-2
V1.yy.mm.dd-3
Ex V1.20.04.29-1
The way I am trying to set up the run number creation is that when I select an item from a ComboBox the part number gets created into a TextBox to later be submitted into the corresponding database. I am not sure how to create a sequence after the Prefix = V1.yy.mm.dd-, I tried to use a CountIf application that would count the number of Prefixes with the same date in the spreadsheet for sequencing, but it seems the function does not work for partial matches. I tried to use the following but I can't get it to work. I am sure there are simpler ways to do this, can you give me a few suggestions? Thanks
This is the code I wrote so far:
Private Sub ComboBox1_Change()
If Me.ComboBox1.Value <> "" Then
Dim Prefix As String
Dim mm, dd, yy As String
Dim sh As Worksheet
Set sh = ThisWorkbook.Sheets("2- V1 Loading (2)")
Dim s As Long
s = 1 + sh.Application.Count(Application.Match(Prefix, Range("B:B"), 0))
mm = Format(Date, "mm")
dd = Format(Date, "dd")
yy = Format(Date, "yy")
Prefix = "V1." & yy & "." & mm & "." & dd & "-"
v1 = "V1." & yy & "." & mm & "." & dd & "-" & "" & s
Me.TextBox6.Value = v1
End If
Maybe something like this ?
Private Sub ComboBox1_Change()
If Me.ComboBox1.Value <> "" Then
Set sh = ThisWorkbook.Sheets("2- V1 Loading (2)")
oDate = Format(Date, "yy.mm.dd")
oConst = "V1." & oDate & "-"
Range("B1:B10000").Copy Destination:=Range("zz1") 'copy all the item to helper column
Range("zz:zz").Replace What:=oConst, Replacement:="" 'get only the number from all the items with the current date
nextNum = Application.Max(Range("zz:zz")) + 1 'get the next number
MsgBox oConst & CStr(nextNum) 'this line only for checking
Range("zz:zz").ClearContents 'clear the helper column
Me.TextBox6.Value = oConst & CStr(nextNum)
End If
But this assuming that the item number in columns B is only at the same day.
If for example there is a forgotten data from any day before the current day, and this want to be inputted with that day and the next number, it need an input box or maybe a cell in sheet where the value is that day, then it will give the last number of that day.
Suppose the data in column B is something like below:
If the code is run today, it will show V1.20.04.30-4 as the next number. With the same data like above, if the code is run tomorrow, it will give V1.20.05.01-1.
To get the next number from yesterday (29 Apr 2020), the code need more line - which is to know on what day the code must get the next number.
Or this kind of line maybe is shorter:
oConst = "V1." & Format(Date, "yy.mm.dd") & "-"
nextNum = oConst & Application.WorksheetFunction.CountIf(Range("B:B"), "*" & oConst & "*") + 1
MsgBox nextNum
There are a few ways you could go about this but I'd say the easiest would be to put the incrementing run number in a separate cell somewhere on your worksheet (or another one if you want) to reference each time.
For example:
When the data is entered onto your 'database' sheet, write the run value to ThisWorkbook.Sheets("2- V1 Loading (2)").Range("AZ1").
Then in your code check that value like so:
Private Sub ComboBox1_Change()
If Me.ComboBox1.Value <> "" Then
Dim Prefix As String
Dim mm, dd, yy As String
Dim sh As Worksheet
Set sh = ThisWorkbook.Sheets("2- V1 Loading (2)")
Dim s As Long
s = 1 + sh.Range("AZ1").Value
mm = Format(Date, "mm")
dd = Format(Date, "dd")
yy = Format(Date, "yy")
Prefix = "V1." & yy & "." & mm & "." & dd & "-"
v1 = "V1." & yy & "." & mm & "." & dd & "-" & s
Me.TextBox6.Value = v1
Presuming that the reference numbers are written to column B of the 2- V1 Loading (2) tab then the next number must always be the one found at the bottom of the column + 1. If there is no number for that date than the new sequential number should be 1. The code below implements that method
Function NextRef() As String
' 016
Dim Fun As String
Dim Counter As Integer
Dim Rng As Range
Dim Fnd As Range
Dim Sp() As String
Fun = Format(Date, """V1.""yy.mm.dd")
With ThisWorkbook.Worksheets("2- V1 Loading (2)")
' start in row 2 (row 1 holding column captions)
Set Rng = .Range(.Cells(2, "B"), .Cells(.Rows.Count, "B").End(xlUp))
End With
If Rng.Row > 1 Then ' skip, if the column is empty
' finds the first occurrence of Ref from the bottom
Set Fnd = Rng.Find(What:=Fun, _
After:=Rng.Cells(1), _
LookIn:=xlValues, _
LookAt:=xlPart, _
SearchDirection:=xlPrevious)
If Not Fnd Is Nothing Then
Sp = Split(Fnd.Value, "-")
If UBound(Sp) Then Counter = Val(Sp(1))
End If
End If
NextRef = Fun & -(Counter + 1)
End Function
You can use the function simply like ComboBox1.Value = NextRef. However when and how to call that line of code is a bit unclear in your design as published. Especially, it's not clear why you would want it in a ComboBox at all, given that the box might also contain other information. Your idea to use the Change event may not work as intended because that event occurs with every letter the user types. I have tested this:-
Private Sub ComboBox1_GotFocus()
' 016
With ComboBox1
If .Value = "" Then .Value = NextRef
End With
End Sub
The next reference number is inserted as soon as you click on the ComboBox. It works but it doesn't make sense. I think now that you have the function that does the work you will find a way to deploy it. Good luck.

VBA Date Format For Variable

I need to turn content in a spreadsheet column from text to a date.
The cell format is text and the inputters were instructed to input a date as "ddmmyyyy".
Accidents happened and I found some content that would not parse as a date, including entries like "Unknown".
So I used a variable declared as a date and wrote an error handler to deal with content that would not parse.
Now for the bit I cannot work out.
If the date was 3rd March 2000 and someone input that as "03332000" that will not parse because "33" cannot be a month or a day; it is caught by the error handler as I wanted.
But if it was input as "03132000" I can't think of a way of preventing VBA converting that to a valid date as "13/03/2000".
Declaring a format for the date variable will not prevent VBA parsing the date.
I can write something that tests number range of the day and month part of the string but that is extra lines of code and I was hoping to do it just by the error handler.
I'd approach it a little differently and let Excel do the work.
Public Function ValidateDate(ByVal strDate As String) As Boolean
Dim intDay As Integer, intMonth As Integer, intYear As Integer, dtDate As Date
ValidateDate = True
On Error GoTo IsInValid
If Len(strDate) <> 8 Then GoTo IsInValid
If Not IsNumeric(strDate) Then GoTo IsInValid
intDay = Left(strDate, 2)
intMonth = Mid(strDate, 3, 2)
intYear = Right(strDate, 4)
dtDate = DateSerial(intYear, intMonth, intDay)
If DatePart("d", dtDate) <> intDay Then GoTo IsInValid
If DatePart("m", dtDate) <> intMonth Then GoTo IsInValid
If DatePart("yyyy", dtDate) <> intYear Then GoTo IsInValid
Exit Function
IsInValid:
ValidateDate = False
End Function
... this will ensure that anything related to leap years etc. will still work correctly and it will ensure that all entries are validated correctly.
If you place:
03332000
in cell A1 and run:
Sub CheckDate()
Dim s As String, d As Date
s = Range("A1").Text
d = DateSerial(CInt(Right(s, 4)), CInt(Mid(s, 3, 2)), CInt(Left(s, 2)))
MsgBox s & vbCrLf & d
End Sub
You will get:
So even though a valid month can only be in the range [1-12], Excel is trying to "help" you by interpreting the 33 as a projection of future date. For example, if the month was entered as 13, Excel will treat it as December of the following year!
You can't rely on error-handling for this. You need checks like:
Sub CheckDate2()
Dim s As String, d As Date
Dim dd As Integer, mm As Integer, yr As Integer
s = Range("A1").Text
yr = CInt(Right(s, 4))
mm = CInt(Mid(s, 3, 2))
dd = CInt(Left(s, 2))
If yr = 0 Or yr < 1900 Then
MsgBox "year is bad"
Exit Sub
End If
If dd = o Or dd > 31 Then
MsgBox "day is bad"
Exit Sub
End If
If mm = 0 Or mm > 12 Then
MsgBox "month is bad"
Exit Sub
End If
d = DateSerial(yr, mm, dd)
MsgBox s & vbCrLf & d
End Sub
You can also do other checks like looking at the length of the field, etc.

Use of NETWORKDAYS function

I have to find the number of working days between two dates which should exclude weekends and National Holidays.
I am using function NETWORKDAYS in vba, this excludes weekends but I want to exclude Some National Holidays as well.
How to use this function NETWORKDAYS(startDate, endDate, [holidays]) for National holidays. It says it accepts [holidays] as a list. I have all the national holidays in an array. how can I use it with this function via VBA ??
Please find the code snippet.
Public Function dataFromInputSheetHolidayDates() As Variant
Dim holidayDates As Integer
Dim holidaydatesArray(20) As Variant
holidayDates = Sheets("InputSheet").Cells(Rows.Count, "D").End(xlUp).Row
For countDate = 0 To holidayDates - 1
holidaydatesArray(countDate) = Format(Sheets("InputSheet").Cells(countDate + 2, "D").Value, "DD-MMM-YY")
Next countDate
dataFromInputSheetHolidayDates = holidaydatesArray
End Function
holidayList = dataFromInputSheetHolidayDates()
Sheets("Estimation").Range("Z" & taskcounter).Formula = "=NETWORKDAYS(X" &
taskcounter & ",Y" & taskcounter &","& holidayList & ")"
Sheets("Estimation").Range("AB" & taskcounter).Formula = "=NETWORKDAYS(X" &
taskcounter & ",AA" & taskcounter &"," & holidayList & ")"
Change these 2 lines in your code:
Dim holidayDates As Long
holidaydatesArray(countDate) = Sheets("InputSheet").Cells(countDate + 2, "D")
In VBA Integer is up to 32767, which is not quite enough for dates. Furthermore, holidaydatesArray should have a numeric value and not some text format.
Pretty much similar problem as this one - workday holiday argument doesn't accept array
If you are trying to create a flexible formula through VBA, where the holidays are on different worksheet, try this solution:
Public Sub TestMe()
Dim holidayLists As Range
Set holidayLists = Worksheets(2).Range("D1:D10")
With Worksheets(1)
.Range("A1").Formula = "=NETWORKDAYS(B1, C1," & holidayLists.Parent.Name & "!" _
& holidayLists.Address & ")"
End With
End Sub
There the holidayLists.Parent.Name & "!" & holidayLists.Address would refer correctly to the worksheet's name of the holidays.

Convert date to a number

I have written a macro which reads the cell content and opens corresponding files as per the cell value.
For example, if I provide 20140522 in a cell, it opens the file "C:\Files\20140522.csv".
However, instead of providing in the above format if I provide it as 22/05/2014 or more generally today's date, how can I convert it into above format in the vba script itself ?. This is because all my files are in the format shown in example only. Following is my macro code
Sub Open()
num=Cells(1,1).Value
ActiveWorkbook.Open(FileName:="C:\Files\" & num & ".csv")
End Sub
You can use Format:
num = Format(Cells(1,1).Value, "yyyymmdd")
Consider:
Sub dural()
Dim d As Date, sDate As String
d = Date
sDate = CStr(Year(d) & Format(Month(d), "00") & Format(Day(d), "00"))
ActiveWorkbook.Open Filename:="C:\Files\" & sDate & ".csv"
End Sub

Resources