I searched but couldn't find what I'm looking for.
How do I convert a normal Date() in ASP Classic to a string in the format dd-monthname-YYYY?
Here is an example:
Old date (mm/dd/YYYY) : 5/7/2013
New date (dd-monthname-YYYY) : 7-May-2013
Dim Dt
Dt = CDate("5/7/2013")
Response.Write Day(Dt) & "-" & MonthName(Month(Dt)) & "-" & Year(Dt)
' yields 7-May-2013
' or if you actually want dd-monthname-YYYY instead of d-monthname-YYYY
Function PadLeft(Value, Digits)
PadLeft = CStr(Value)
If Len(PadLeft) < Digits Then
PadLeft = Right(String(Digits, "0") & PadLeft, Digits)
End If
End Function
Response.Write PadLeft(Day(Dt), 2) & "-" & MonthName(Month(Dt)) & "-" & Year(Dt)
'yields 07-May-2013
I wrote an ASP Classic date handling object a while back that might be of use to you. It has a .Format() method that lets you pass in format specifiers just like the Format() function from VB/VBA. If there are any parts missing, I apologize--but this should be a giant leap forward toward natural date formatting.
Private pMillisecondMatch
Function RemoveMillisecondsFromDateString(DateString) ' Handle string dates from SQL Server that have milliseconds attached
If IsEmpty(pMillisecondMatch) Then
Set pMillisecondMatch = New RegExp
pMillisecondMatch.Pattern = "\.\d\d\d$"
pMillisecondMatch.Global = False
End If
RemoveMillisecondsFromDateString = pMillisecondMatch.Replace(DateString, "")
End Function
Function DateConvert(DateValue, ValueIfError)
On Error Resume Next
If IsDate(DateValue) Then
DateConvert = CDate(DateValue)
Exit Function
ElseIf TypeName(DateValue) = "String" Then
DateValue = RemoveMillisecondsFromDateString(DateValue)
If IsDate(DateValue) Then
DateConvert = CDate(DateValue)
Exit Function
End If
End If
DateConvert = ValueIfError
End Function
Class AspDate
Private pValue
Public Default Property Get Value()
Value = pValue
End Property
Public Property Set Value(DateValue)
If TypeName(DateValue) = "AspDate" Then
pValue = DateValue.Value
Else
Err.Raise 60020, "Class AspDate: Invalid object type " & TypeName(DateValue) & " passed to Value property."
End If
End Property
Public Property Let Value(DateValue)
pValue = DateConvert(DateValue, Empty)
End Property
Public Property Get FormattedDate()
FormattedDate = Format("yyyy-mm-dd hh:nn:ss")
End Property
Public Function Format(Specifier)
Dim Char, Code, Pos, MonthFlag
Format = "": Code = ""
If IsEmpty(Value) Then
Format = "(Empty)"
End If
Pos = 0
MonthFlag = False
For Pos = 1 To Len(Specifier) + 1
Char = Mid(Specifier, Pos, 1)
If Char = Left(Code, 1) Or Code = "" Then
Code = Code & Char
Else
Format = Format & Part(Code, MonthFlag)
Code = Char
End If
Next
End Function
Private Function Part(Interval, MonthFlag)
Select Case LCase(Left(Interval, 1))
Case "y"
Select Case Len(Interval)
Case 1, 2
Part = Right(CStr(Year(Value)), 2)
Case 3, 4
Part = Right(CStr(Year(Value)), 4)
Case Else
Part = Right(CStr(Year(Value)), 4)
End Select
Case "m"
If Not MonthFlag Then ' this is a month calculation
MonthFlag = True
Select Case Len(Interval)
Case 1
Part = CStr(Month(Value))
Case 2
Part = Right("0" & CStr(Month(Value)), 2)
Case 3
Part = MonthName(Month(Value), True)
Case 4
Part = MonthName(Month(Value))
Case Else
Part = MonthName(Month(Value))
End Select
Else ' otherwise it's a minute calculation
Part = Right("0" & Minute(Value), 2)
End If
Case "n"
Part = Right("0" & Minute(Value), 2)
Case "d"
Part = CStr(Day(Value))
If Len(Part) < Len(Interval) Then
Part = Right("0" & Part, Len(Interval))
End If
Case "h"
MonthFlag = True
Part = CStr(Hour(Value))
If Len(Part) < Len(Interval) Then
Part = Right("0" & Part, Len(Interval))
End If
Case "s"
Part = Right("0" & Second(Value), 2)
Case Else ' The item is not a recognized date interval, just return the value
Part = Interval
End Select
End Function
End Class
Function NewDate(Value)
Set NewDate = New AspDate
NewDate.Value = Value
End Function
Function NewDateWithDefault(Value, DefaultValue)
Set NewDateWithDefault = New AspDate
If Value = Empty Then
NewDateWithDefault.Value = DefaultValue
Else
NewDateWithDefault.Value = Value
End If
End Function
Here's example code using the above class:
<%=NewDate(Checkin.Parameters.Item("#DOB").Value).Format("mm/dd/yyyy")%>
To get the format you've noted above, you would do:
.Format("d-mmmm-yyyy")
Related
I am trying to assign value to a LABEL in VISIO. But it is not working. Can you help me.
After I drag and drop my component on the right click I am giving an option "ADD STATION" this will add a LABEL to the component and after that I want to get value from the Parameter window and display it into the LABEL.
I am able to generate the LABEL on a button click I want some help to display the Value.
Public Sub AddParameterToLabel(ByRef oLabel As Visio.Shape, ByRef sObjID As String, ByRef sParameterName As String, ByVal sPreText As String, ByVal bShow As Boolean)
Dim sRowName As String = "Parameter"
Dim iCurrentRow As Integer = oLabel.AddNamedRow(visSectionUser, sRowName, 0)
If (Err.Number <> 0) Then
Err.Clear()
Dim iAddRow As Integer = oLabel.AddNamedRow(visSectionUser, "VisioSucks3", 0)
oLabel.CellsSRC(visSectionUser, iAddRow, 1).RowName = sRowName
iCurrentRow = iAddRow
End If
Dim ovCell As Visio.Cell = oLabel.CellsSRC(visSectionUser, iCurrentRow, visUserValue)
Dim sParent As String = sObjID
If (Len(sObjID) > 0) Then
sParent = sObjID & DOT
End If
Dim oParam As Object.Interop.Param
oParam = g_oObject.Param(sParent & sParameterName)
Dim sPacked As String
If (Err.Number <> 0) Then
sPacked = "|-1|1|0|||||"
Else
'Add parameters with the unit conversions, as specified by the current choice
sPacked = sParameterName & "|" &
oParam.SigFigs & "|" &
oParam.MultiplierToUserUnit & "|" &
oParam.AdderToUserUnit & "|" &
"|" &
sPreText & "|" &
"|" &
"g" & oParam.SigFigs & "|" &
"User" & "|" &
oParam.UserUnitsString
End If
If Not oParam Is Nothing Then
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(oParam)
oParam = Nothing
End If
ovCell.FormulaU = FormatStringForVisioOrSQL(sPacked)
oLabel.CellsSRC(visSectionUser, iCurrentRow, visUserPrompt).Result(visNoCast) = Math.Abs(CInt(bShow))
oLabel.Cells("Actions.Action[1]").Trigger()
End Sub
The "ParameterName = Compressor.StationFrom" which I am getting here.
and the value StationFrom will be having is DOUBLE i.e 1.2,1.3 etc..
I am extending the capability of the Word report writing from VSTO to consider different languages. Therefore, instead of using the headings like "Heading 1" etc, I have used wdStyleHeading1 etc. I have built a function to assign the style to the heading. The problem is that the line 1 and line 2 below are overwriting each other. If I call the function first, I loose list number and If I call function second, I loose the format. Can you please explain where I am going wrong?
I have imported the necessary references.
Call HeadingListLevel(wrdApp, 1)
wrdApp.Selection.ParagraphFormat.Style = Word.WdBuiltinStyle.wdStyleHeading1
Below is the sub function
Sub HeadingListLevel(wrdApp As Object, HeadingLvl As Integer)
'Dim wrdHeading As String
Dim wrdHeadingNr As String
Dim i As Integer
Dim ListTemp As Word.ListTemplate
wrdHeadingNr = "%" & 1
ListTemp = wrdApp.ListGalleries(Word.WdListGalleryType.wdOutlineNumberGallery).ListTemplates(1)
For i = 1 To HeadingLvl
If i > 1 Then
wrdHeadingNr = wrdHeadingNr & "." & "%" & i
End If
Next i
'wrdHeading = "Heading " & HeadingLvl
With ListTemp.ListLevels(1)
Select Case HeadingLvl
Case 1
.LinkedStyle = Word.WdBuiltinStyle.wdStyleHeading1
Case 2
.LinkedStyle = Word.WdBuiltinStyle.wdStyleHeading2
Case 3
.LinkedStyle = Word.WdBuiltinStyle.wdStyleHeading3
Case 4
.LinkedStyle = Word.WdBuiltinStyle.wdStyleHeading4
Case 5
.LinkedStyle = Word.WdBuiltinStyle.wdStyleHeading5
Case 6
.LinkedStyle = Word.WdBuiltinStyle.wdStyleHeading6
Case 7
.LinkedStyle = Word.WdBuiltinStyle.wdStyleHeading7
End Select
.NumberFormat = wrdHeadingNr
.NumberStyle = Word.WdListNumberStyle.wdListNumberStyleArabic
End With
wrdApp.Selection.Range.ListFormat.ApplyListTemplate(ListTemplate:=ListTemp)
ListTemp = Nothing
End Sub
I discovered the answer myself. Below is the changes to the sub function. It worked well for me.
Sub HeadingListLevel(wrdApp As Object, HeadingLvl As Integer)
'Dim wrdHeading As String
Dim wrdHeadingNr As String
Dim i As Integer
Dim ListTemp As Word.ListTemplate
wrdHeadingNr = "%" & 1
ListTemp = wrdApp.ListGalleries(Word.WdListGalleryType.wdOutlineNumberGallery).ListTemplates(5)
For i = 1 To HeadingLvl
If i > 1 Then
wrdHeadingNr = wrdHeadingNr & "." & "%" & 1
End If
Next i
'wrdHeading = "Heading " & HeadingLvl
With ListTemp.ListLevels(HeadingLvl)
Select Case HeadingLvl
Case 1
.LinkedStyle = wrdApp.ActiveDocument.Styles(Word.WdBuiltinStyle.wdStyleHeading1).NameLocal
Case 2
.LinkedStyle = wrdApp.ActiveDocument.Styles(Word.WdBuiltinStyle.wdStyleHeading2).NameLocal
Case 3
.LinkedStyle = wrdApp.ActiveDocument.Styles(Word.WdBuiltinStyle.wdStyleHeading3).NameLocal
Case 4
.LinkedStyle = wrdApp.ActiveDocument.Styles(Word.WdBuiltinStyle.wdStyleHeading4).NameLocal
Case 5
.LinkedStyle = wrdApp.ActiveDocument.Styles(Word.WdBuiltinStyle.wdStyleHeading5).NameLocal
Case 6
.LinkedStyle = wrdApp.ActiveDocument.Styles(Word.WdBuiltinStyle.wdStyleHeading6).NameLocal
Case 7
.LinkedStyle = wrdApp.ActiveDocument.Styles(Word.WdBuiltinStyle.wdStyleHeading7).NameLocal
End Select
'.LinkedStyle = wrdHeading
.NumberFormat = wrdHeadingNr
.NumberStyle = Word.WdListNumberStyle.wdListNumberStyleArabic
'.StartAt = 1
'.ResetOnHigher = False
End With
wrdApp.Selection.Range.ListFormat.ApplyListTemplate(ListTemplate:=ListTemp)
ListTemp = Nothing
End Sub
I am somewhat new to vba, and I'm trying to create a somewhat more complex conditional format than access 2013 allows from the conditional formatting menu. I have a form with 22 target date and actual date fields. for each pair I need to:
if the target date is more than 7 days in the future, color it green.
If the target date is less than 7 days in the future or is today, color it yellow
If the target date in the past, color it red.
UNLESS there is an actual date it was accomplished, in which case:
If the actual date is before the target date, color both dates green
If the actual date is after the target date, color both dates red.
Because I have to do this on form load, and on the change of any date field (the target dates are calculated, but will change if other data is changed in the form), I wanted to write a public sub that takes form name, target date, and actual date as variables. I was able to code each box to do this on the local form module with 'Me.txtbox'
However, when I try to reference the form and text boxes from the public sub, it seems like I'm not properly referencing the text boxes on the form. I've tried 3 or 4 different ways of doing this (string, textbox.name, etc) and I feel like I'm close, but ...
Code that works as desired in the form module
Private Sub txtFreqReqDate_AfterUpdate()
If Me.txtFreqReqDate <= Me.txtFreqReq Then
Me.txtFreqReq.Format = "mm/dd/yyyy[green]"
Me.txtFreqReqDate.Format = "mm/dd/yyyy[green]"
ElseIf Me.txtFreqReqDate > Me.txtFreqReq Then
Me.txtFreqReq.Format = "mm/dd/yyyy[red]"
Me.txtFreqReqDate.Format = "mm/dd/yyyy[red]"
ElseIf IsNull(Me.txtFreReqDate) = True Then
If Me.txtFreqReq < Now() Then
Me.txtFreqReq.Format = "mm/dd/yyyy[red]"
ElseIf Me.txtFreqReq >= (Now()+7) Then
Me.txtFreqReq.Format = "mm/dd/yyyy[yellow]"
ElseIf Me.txtFreqReq > (Now()+7) Then
Me.txtFreqReq.Format = "mm/dd/yyyy[green]"
Else
Me.txtFreqReq.Format = "mm/dd/yyyy[black]"
End If
Else
Exit Sub
End If
End Sub
Perhaps not the prettiest, but I'm always open to constructive criticism. I'd have to write this 22+ times for each pair, changing the name of the text boxes each time. I want to write a public sub that just takes the names of the text boxes, but I can't seem to find the right combination:
Private Sub txtFreqReqDate_AfterUpdate()
FormatBoxes(Me, me.txtFreqReqDate, me.txtFreqReq)
End Sub
And in another module:
Public Sub FormatBoxes(CurrentForm As Form, txtActual as Textbox, txtTarget as Textbox)
frmName = CurrentForm.name
tbActual = txtActual.Name
tbTarget = txtTarget.Name
If frmName.tbActual <= frmName.tbTarget Then
frmName.tbTarget.Format = "mm/dd/yyyy[green]"
frmName.tbActual.Format = "mm/dd/yyyy[green]"
ElseIf frmName.tbActual > frmName.tbTarget Then
frmName.tbTarget.Format = "mm/dd/yyyy[red]"
frmName.tbActual.Format = "mm/dd/yyyy[red]"
ElseIf IsNull(frmName.tbActual) = True Then
If frmName.tbTarget < Now() Then
frmName.tbTarget.Format = "mm/dd/yyyy[red]"
ElseIf frmName.tbTarget >= (Now()+7) Then
frmName.tbTarget.Format = "mm/dd/yyyy[yellow]"
ElseIf frmName.tbTarget > (Now()+7) Then
frmName.tbTarget.Format = "mm/dd/yyyy[green]"
Else
frmName.tbTarget.Format = "mm/dd/yyyy[black]"
End If
Else
Exit Sub
End If
End Sub
Sorry if this is a bit long, I'm just at my wit's end...
Also, apologies for any typos. I had to re-type this from another machine.
You can simply use the textbox parameters directly in your sub.
It is not even necessary to pass the form as parameter.
Public Sub FormatBoxes(txtActual as Textbox, txtTarget as Textbox)
If txtActual.Value <= txtTarget.Value Then
txtTarget.Format = "mm/dd/yyyy[green]"
etc.
Note that when calling it, you need either Call or remove the parentheses.
Private Sub txtFreqReqDate_AfterUpdate()
Call FormatBoxes(me.txtFreqReqDate, me.txtFreqReq)
' or
' FormatBoxes me.txtFreqReqDate, me.txtFreqReq
End Sub
CurrentForm.name is a string. It is the Name property of the CurrentForm object. The CurrentForm object also has a controls collection in which the texboxes live. You can refer to them by name in there like CurrentForm.Controls("tbTarget") but you can also say CurrentForm.tbTarget. So you're very close and on the right track.
Change
frmName = CurrentForm.name
tbActual = txtActual.Name
tbTarget = txtTarget.Name
to
set frmName = CurrentForm
if frmName is not nothing then
set tbActual = txtActual
set tbTarget = txtTarget
end if
Alternatively if your signature on your method is
Public Sub FormatBoxes(CurrentForm As string, txtActual as string, txtTarget as string)
then your set up will look like
set frmName = forms(CurrentForm)
if frmName is not nothing then
set tbActual = frmName.controls(txtActual)
set tbTarget = frmName.controls(txtTarget)
end if
But I think the first one will work better.
I wanted to post the finished code to help out anyone else who searches for this subject. I did a couple thins to make this sub more universal.
First, Instead of using the date format, I only changed the .ForeColor, allowing me to use this sub for any type of textbox.
Public Sub FormatBoxes(txtActual As TextBox, txtTarget As TextBox, chkRequired As CheckBox, _
Optional intOption as Integer)
Dim intRed As Long, intYellow As Long, intGreen As Long, inBlack As Long, intGray As Long
intBlack = RGB(0, 0, 0)
intGray = RGB(180, 180, 180)
intGreen = RGB (30, 120, 30)
intYellow = RGB(217, 167, 25)
intRed = RGB(255, 0, 0)
If (chkRequired = False) Then
txtTarget.ForeColor = intGray
txtActual.ForeColor = intGray
If intOption <> 1 Then
txtTarget.Enabled = False
txtActual.Enabled = False
txtTarget.TabStop = False
txtActual.TabStop = False
End If
Else
If intOption <> 1 Then
txtTarget.Enabled = True
txtActual.Enabled = True
txtTarget.Locked = True
txtActual.Locked = False
txtTarget.TabStop = False
txtActual.TabStop = True
End If
If IsBlank(txtActual) = True Then
If txtTarget < Now() Then
txtTarget.ForeColor = intRed
ElseIf txtTarget > (Now() + 7) Then
txtTarget.ForeColor = intGreen
ElseIf txtTarget >= Now() And txtTarget <= (Now() +7) Then
txtTarget.ForeColor = intYellow
Else
txtTarget.ForeColor = intBlack
End If
ElseIf intOption - 1 Then
txtTarget.ForeColor = intBlack
txtActual.ForeColor = intBlack
ElseIf txtActual <= txtTarget Then
txtTarget.ForeColor = intGreen
txtActual.ForeColor = intGreen
ElseIf txtActual > txtTarget Then
txtTarget.ForeColor = intRed
txtActual.ForeColor = intRed
End If
End If
End Sub
In case you were wondering, IsBlank() is a function that checks for a null or zero length string:
Public Function IsBlank(str_in As Variant) As Long
If Len(str_in & "") = 0 Then
IsBlank = -1
Else
IsBlank = 0
End If
End Function
Thanks for all the help, and I hope this is useful for someone.
I have this form to enter new data to a table.
I would like to warn the user when he is entering an invoice number that already exist. Here is the code I have but its not working:
Private Sub CommandButton1_Click()
Dim L As Long
Dim Code As String
Dim TextBox2 As Long
Dim valFormula As String
valFormula = "=COUNTIFS($F12:$F1702,F1702,$D12:$D1702,D1702)=1"
If MsgBox("Confirm?", vbYesNo, "Confirming new invoice") = vbYes Then
With Worksheets("FACTURE")
L = Sheets("FACTURE").Range("D65535").End(xlUp).Row + 1 'Pour placer le nouvel enregistrement _ la premi_re ligne de tableau non vide
End With
With Me
Range("D" & L).Validation
.Add Type:=xlValidateCustom, _
AlertStyle:=xlValidAlertWarning, _
Formula1:="=COUNTIFS($F12:$F1702,F1702,$D12:$D1702,D1702)=1"
.InputTitle = ""
.ErrorTitle = "Duplicate alert"
.InputMessage = ""
.ErrorMessage = "This invoice number already exist. Continue?"
Range("B" & L).Value = .ComboBox2 & .ComboBox3
Range("C" & L).Value = (Now)
Range("D" & L).Value = .TextBox2
Range("E" & L).Value = .TextBox3
Range("F" & L).Value = .TextBox4
Range("G" & L).Value = .TextBox5
Range("K" & L).Value = .ComboBox1
Range("L" & L).Value = .ComboBox2
Range("M" & L).Value = .ComboBox3
Range("N" & L).Value = .TextBox9
Range("O" & L).Value = .TextBox10
Range("R" & L).Value = .TextBox39
Range("P" & L).Value = .TextBox40
Range("C" & L).Interior.ColorIndex = 0
If .OptionButton1 Then
FormatCell Range("B" & L), xlThemeColorAccent3
ElseIf .OptionButton2 Then
FormatCell Range("B" & L), xlThemeColorAccent1
ElseIf .OptionButton3 Then
FormatCell Range("B" & L), xlThemeColorAccent4
Else
FormatCell Range("B" & L), xlThemeColorAccent2
End If
End With
End If
End Sub
Any advice?
As Comintern suggested, use Find() method of Range object, with code like:
Set f = rngToSerachIn.Find(what:=factureNo, LookIn:=xlValues, lookat:=xlWhole)
where
f is a range variable where to store the range with the searched value
rngToSerachIn is the range where to search the value
factureNo is the value to search for
furthermore it seems to me your invoices will be stored in rows from 12 downwards, so it could be useful to write a generic function to get first empty cell in a given column of a given worksheet ranging from a certain row
Since it'd be a good practice to demand specific tasks to Sub/Function to improve both code readability and maintenance, you could do that for:
getting first empty row after last non empty one starting from a given row in a given column of a given worksheet
validating invoice number
filling worksheet ranges
formatting invoice cell
as follows:
Option Explicit
Private Sub CommandButton1_Click()
Dim L As Long
Dim factureWs As Worksheet
If MsgBox("Confirm?", vbYesNo, "Confirming new invoice") = vbNo Then Exit Sub
Set factureWs = Worksheets("FACTURE") '<--| set the worksheet you want to work with
L = GetLastNonEmptyRow(factureWs, "D", 12) + 1 '<--| get passed worksheet first empty row after last non empty one in column "D" from row 12 (included)
If L > 12 Then If Not CheckDuplicate(Me.TextBox2, factureWs.Range("D12:D" & L - 1)) Then Exit Sub '<--| exit if duplicated non accepted by the user
FillRanges factureWs, L '<--| fill worksheet ranges with userfom controls values
FormatInvoice factureWs.Range("B" & L) '<--| color invoice cell depending on option buttons values
End Sub
Function GetLastNonEmptyRow(ws As Worksheet, colIndex As String, firstRow As Long) As Long
Dim lastRow As Long
With ws
lastRow = .Cells(.Rows.Count, colIndex).End(xlUp).row ' <--| get last non empty row in given column
If lastRow = 1 Then If IsEmpty(.Range(colIndex & 1)) Then lastRow = 0 '<--| handle the case of an empty column
If lastRow < firstRow Then lastRow = firstRow - 1 '<--| handle the case the last non empty row is above the first passed one
End With
GetLastNonEmptyRow = lastRow
End Function
Function CheckDuplicate(factureNo As String, rng As Range) As Boolean
Dim f As Range
Set f = rng.Find(what:=factureNo, LookIn:=xlValues, lookat:=xlWhole)
If Not f Is Nothing Then
CheckDuplicate = MsgBox("This invoice number already exist!" & vbCrLf & vbCrLf & "Continue?", vbExclamation + vbYesNo, "Duplicate alert") = vbYes
Else
CheckDuplicate = True
End If
End Function
Sub FormatInvoice(rng As Range)
Dim thColor As XlThemeColor
With Me
Select Case True
Case .OptionButton1
thColor = xlThemeColorAccent3
Case .OptionButton2
thColor = xlThemeColorAccent1
Case .OptionButton3
thColor = xlThemeColorAccent4
Case Else
thColor = xlThemeColorAccent2
End Select
End With
FormatCell rng, thColor
End Sub
Sub FillRanges(ws As Worksheet, L As Long)
With ws
.Range("C" & L).Value = (Now)
.Range("D" & L).Value = Me.TextBox2
.Range("E" & L).Value = Me.TextBox3
.Range("F" & L).Value = Me.TextBox4
.Range("G" & L).Value = Me.TextBox5
.Range("K" & L).Value = Me.ComboBox1
.Range("L" & L).Value = Me.ComboBox2
.Range("M" & L).Value = Me.ComboBox3
.Range("N" & L).Value = Me.TextBox9
.Range("O" & L).Value = Me.TextBox10
.Range("R" & L).Value = Me.TextBox39
.Range("P" & L).Value = Me.TextBox40
End With
End Sub
you may find it useful and follow this pattern in your subsequent coding
I need to check if the date entered in a textbox is valid. It has to be a single textbox, so no workaround this way.
Now, I have this code:
Private Sub cmdOK_Click()
Dim dataAnalisi As Date
If IsDate(txtDataAnalisi.Value) Then
dataAnalisi = txtDataAnalisi.Value
Dim giornoAnalisi, meseAnalisi As Integer
giornoAnalisi = Format(dataAnalisi, "dd")
meseAnalisi = Format(dataAnalisi, "mm")
If giornoAnalisi <= 31 And meseAnalisi <= 12 Then
Call arrayList(dataAnalisi)
Unload Me
Else
GoTo DateError
End If
Else
DateError:
MsgBox "Inserire una data formattata correttamente!", vbCritical, "Errore nell'inserimento!"
txtDataAnalisi.SetFocus
End If
End Sub
Sorry if it has text in Italian. The function works decently, the only problem is that if I input for instance 11/14/12 (where the date is dd/mm/yy and 14 was a mistype) it inverts the day and month values. Instead, I want the sub to tell the user to check his input again! Can you help me? Thank you!
There are variations of this question every month or so. I am convinced that Excel will treat a date that is a valid American date as an American date. I have thought this for many years but others disagree.
I use functions like the one below which check for formats I believe Excel will misinterpret and convert them to an unambiguous format.
I use the English abbreviations for months. I believe French is the only language that does not permit three character abbreviations for months so perhaps you have your own set. You will have to adapt that part of the routine to your requirement.
Hopes this helps.
Function MyDateValue(ByVal DateIn As String, ByRef DateOut As Date) As Boolean
' DateIn is a value to be checked as a valid date.
' If it is a valid date, DateOut is set to its value and the function
' returns True.
' Excel misinterprets dates such as "4/14/11" as 14 April 2011. This routine
' checks for such dates and, if necessary, changes them to an unambiguous
' format before calling IsDate and DateValue.
Dim DatePart() As String
Dim MonthNum As Long
Const MonthAbbr As String = "janfebmaraprmayjunjulaugsepoctnovdec"
' Replace popular delimiters with Microsoft standard
DateIn = Replace(DateIn, "-", "/")
DateIn = Replace(DateIn, "\", "/")
DatePart = Split(DateIn, "/")
If UBound(DatePart) = 2 Then
' DateStg is three values separated by delimiters
' Check middle part
If IsNumeric(DatePart(1)) Then
MonthNum = Val(DatePart(1))
If MonthNum >= 1 And MonthNum <= 12 Then
' Middle part could be numeric month
' Convert to format Excel does not misinterpret
'Debug.Assert False
DatePart(1) = Mid(MonthAbbr, ((MonthNum - 1) * 3) + 1, 3)
DateIn = Join(DatePart, "-")
If IsDate(DateIn) Then
DateOut = DateValue(DateIn)
MyDateValue = True
Exit Function
End If
Else
' Middle part cannot be a month
'Debug.Assert False
MyDateValue = False
Exit Function
End If
Else
'Debug.Assert False
' The middle part is not a number. It could be a month abbreviation
MonthNum = InStr(1, MonthAbbr, LCase(DatePart(1)))
If MonthNum = 0 Then
' The middle portion is neither a month number nor a month abbreviation
Debug.Assert False
MyDateValue = False
Else
' The middle portion is a month abbreviation.
' Excel will handle date correctly
'Debug.Assert False
MonthNum = (MonthNum - 1) / 3 + 1
DateIn = Join(DatePart, "-")
If IsDate(DateIn) Then
'Debug.Assert False
DateOut = DateValue(DateIn)
MyDateValue = True
Exit Function
End If
End If
End If
Else
' Debug.Assert False
' Use IsDate for other formats
If IsDate(DateIn) Then
' Debug.Assert False
DateOut = DateValue(DateIn)
MyDateValue = True
Exit Function
Else
' Debug.Assert False
MyDateValue = False
End If
End If
End Function