VBA - Checking date string validity - vba

I have a string in the following format in Excel.
07/12/2015 08:00 - 08/12/2015 09:00
I want to check if the current date fits between the two (these dates are validity dates, meaning I have to check if the current date is bigger than the first date and smaller than the second date).
I sometimes also have this string without hours, so like:
07/12/2015 - 08/12/2015
so I have to check that as well (just without the hours).
I split the dates using the Split function to split by the "-" character. However, I'm not sure how to do the check because I've never worked with dates.
Can anyone show me how to do this? It seems that it'd be complicated with the check for the hours.

You can try this :
Dim mydate as String, splitdate as Variant
mydate = "07/12/2015 08:00 - 08/12/2015 09:00"
splitdate = Split(mydate, "-")
If Date < splitdate(0) And Date > splitdate(1) Then MsgBox "Is Between"
In case there will be some issues with understanding date formats, you can still use Cdate function -
If Date < CDate(splitdate(0)) ...

Assuming, that you String is located in A1, and the Date you want to check for is in B1, then put this formula in C1:
=IF(AND(B1>=DATEVALUE(LEFT(A1,10)),B1<=DATEVALUE(MID(A1,FIND("-",A1)+2,10))),TRUE,FALSE)
This works for both cases, if you are only interested if the date lies between the dates (thus excluding the time).

Use cdate function. You wrote you already used the split function, so all you need to do is put the separate date strings into date variables using cdate ('c' stands for cast).
So
Dim d1 as Date
Dim d2 as Date
d1 = CDate(splitstring(0))
d2 = CDate(splitstring(1))
Then you can check the given date.

With the CDate() conversion function and Trim (to get rid of useless spaces), here is a boolean function that you can easily use to test if you are in the time lapse described by your string.
Here is how to use it :
Sub test_Gilbert_Williams()
Dim TpStr As String
TpStr = "08/12/2015 08:00 - 08/12/2015 09:00"
'TpStr = "07/12/2015 - 08/12/2015"
MsgBox Test_Now_Date_Validity(TpStr)
End Sub
And the function :
Public Function Test_Now_Date_Validity(Date_Lapse As String) As Boolean
Dim A() As String, _
Date1 As Date, _
Date2 As Date
If InStr(1, Date_Lapse, "-") Then
A = Split(Date_Lapse, "-")
Debug.Print Trim(A(0)) & " " & CDate(Trim(A(0)))
Debug.Print Trim(A(1)) & " " & CDate(Trim(A(1)))
If CDate(A(0)) > CDate(A(1)) Then
Date1 = CDate(A(1))
Date2 = CDate(A(0))
Else
Date1 = CDate(A(0))
Date2 = CDate(A(1))
End If
If Now > Date1 And Now < Date2 Then
Test_Now_Date_Validity = True
Else
Test_Now_Date_Validity = False
End If
Else
Exit Function
End If
End Function

Related

Format interval as "YMD" format with the format being a parameter in the function

The following is my code:
Option Explicit
Public Function StudyDuration(ByVal Start As Date, Format As String, Optional ByVal Graduation As Date, Optional ByVal Expected As Date) As String
Dim TillGraduation As Integer
StudyDuration = Graduation Or Expected - Start
TillGraduation = DateDiff("ymd", Date, Expected)
If Graduation = 0 And Expected = 0 Then Graduation = Date
Range("B1").Value = Start
Range("B2").Value = Graduation
Range("B3").Value = Expected
Range("B4").Value = StudyDuration
Range("B5").Value = TillGraduation
If Graduation = 0 And Expected > Start Then
StudyDuration = Expected - Start And TillGraduation = DateDiff("ymd", Date, Expected)
MsgBox ("Study Length" & " is" & Range("B4").Value & vbNewLine & Range("B5") & "till Graduate")
End If
End Function
However, the cell B1 keeps showing the date 1/7/1900. Can anyone tell me how should I correct it?
Thanks a lot!
I believe that functions are not allowed to modify cell values. A function is only supposed to return a value that will set the value for the cell that is called from.
If you want to modify cell values, then you should look at using a Sub instead.
BTW, your function makes no use of the Format parameter.

Read the correct week number from a calendar date

I have below dates in an Excel column, as you can see.
Sprint 1 takes from 10.04 to 21.04 this means 2 weeks and between brackets they are specified week 15 and 16 which is correct but for Sprint 2, who also starts in 10.04 but takes until 05.05 it means 7 weeks, but are displayed also the weeks from the Sprint1.
"Sprint1 (CW15-16/2017)
[10.04.2017 - 21.04.2017]
Sprint2 (CW15-16/2017)
[10.04.2017 - 05.05.2017]"
What I have until now is:
'reading the first CW of the sprint based on the date
SprintFristCW = Left(planning_wb.Worksheets(SprintPlanningTable).Cells(2, i + 1).Value, 9)
'reading the last CW of the Sprint based on the date
SprintEndCW = Right(planning_wb.Worksheets(SprintPlanningTable).Cells(2, i + Sprintlength).Value, 9)
SprintCW = Left(SprintFirstCW, 4) & "-" & Right(SprintEndCW, 7)
But SprintEndCW is not reading correct the week number.
So I need to read the correct week number in which each sprint ends and print it.
Don't create huge procedures. Small is beautiful. Create functions that feed into your Main procedure. Here is an example. The procedure TestExtraction calls the function ExtractWeeks. Therefore ExtractWeeks needs not be part of the procedure that calls it, making the code easier to understand and maintain.
Private Sub TestExtraction()
Dim Fun As Long
Dim DateString As String
Dim StartDate As Date, EndDate As Date
DateString = ActiveCell.Value
' the DateString is re-defined here for testing purposes
DateString = "[10.04.2017 - 05.05.2017]"
Fun = ExtractWeeks(DateString, StartDate, EndDate)
If Fun < 0 Then
Debug.Print "Invalid date"
Else
With Application
DateString = "(CW" & .WeekNum(StartDate)
If Year(StartDate) <> Year(EndDate) Then _
DateString = DateString & "/" & Year(StartDate)
DateString = DateString & " - " & .WeekNum(EndDate) & "/" & Year(EndDate) & ")"
End With
Debug.Print DateString
Debug.Print Fun & " weeks"
End If
End Sub
Private Function ExtractWeeks(ByVal DateString As String, _
StartDate As Date, _
EndDate As Date) As Long
' 24 Oct 2017
' return the number of weeks between dates (rounded up)
' return -1 if one of the dates is unreadable
Dim Dates() As String
Dim i As Integer
Dates = Split(Mid(DateString, 2, Len(DateString) - 2), "-")
On Error Resume Next
For i = 0 To 1
Dates(i) = Replace(Trim(Dates(i)), ".", Application.International(xlDateSeparator))
Next i
StartDate = DateValue(Dates(0))
EndDate = DateValue(Dates(1))
If Err Then
ExtractWeeks = -1
Else
ExtractWeeks = Int((StartDate - EndDate) / 7) * -1
End If
End Function
The point is that not everything that looks like a date is a date Excel can understand. The Function ExtractWeeks converts the "dates' from your worksheet into real dates and returns these dates to the calling procedure. It also returns -1 in case of error which you can use to trap such errors. In my example, the function returns the number of weeks (or -1). You might let it return the CW string my calling procedure constructs. You will find it easy to move the process of constructing that string to the function and let the function return "" in case of error instead of -1. Perhaps you can exclude the possibility of errors in the dates. This is a question of how you integrate the function into your Main.

Comparing dates with different date format in system

I need to compare two Dates. They are in text format and they look like 30.05.2016, because they are extracted from other program.
The problem is that on one system I got different date formatting (5/30/2016), than on another (30/5/2016).
I would like to know whether my thinking is in right direction, if not what should I do.
Firstly I will check which formatting do I have.
If (5/30/2016) then I will do
1. Replace "." to "/"
2. CDate(value)
3. NumberFormat = "General"
4. Comparing date1 < date2
If (30/5/2016) then I will do
1. DateValue(Replace "." to "/")
2. NumberFormat = "General"
3. Comparing date1 < date2
I am still thinking how to write this code, and your help on this stage would be nice.
This assumes that the date are actually in Text format. The first UDF() handles US-style dates:
Public Function IsD1LessThanD2(d1 As String, d2 As String) As Boolean
' US Date format
IsD1LessThanD2 = CDate(Replace(d1, ".", "/")) < CDate(Replace(d2, ".", "/"))
End Function
The second UDF() handles European format:
Public Function IsD1LessThanD2_E(d1 As String, d2 As String) As Boolean
' European Date format
ary1 = Split(d1, ".")
ary2 = Split(d2, ".")
d1 = DateValue(ary1(1) & "/" & ary1(0) & "/" & ary1(2))
d2 = DateValue(ary2(1) & "/" & ary2(0) & "/" & ary2(2))
IsD1LessThanD2_E = d1 < d2
End Function
You can format both strings to the Date format
Dim date1, date2 As Date
' string1 in the format 5/30/2016
date1 = Format(string1, "mm/dd/yyyy")
' string2 in the format 30/5/2016
date2 = Format(string2, "dd/mm/yyyy")
And then you can simply compare the dates.

How can I convert a long date with time to a different format in VBA?

I have data for a date that looks like this: "2015-02-11T19:41:50-08:00"
I would like to know if there is already a function that exists in VBA which can convert the above data to the format of something like "02/11/2015 11:41 AM PST"
I attempted the following code playing around with the format function but was unable to get VBA to recognize the format as a date:
testdate = "2015-02-12T22:57:05-08:00"
newdate = Format(testdate, "mm/dd/yyyy hh/nn/ss AM/PM")
Debug.Print newdate
The output was still "2015-02-12T22:57:05-08:00"
Thanks for the help.
Edit:
I was able to resolve the problem by taking your suggestions to use the mid() function since the dates are in fixed format. I decided to keep the military time in the final version.
Here is my code for anyone curious:
Function convertDate(orderdate)
'takes the date formatted as 2015-02-06T08:26:00-08:00
'and converts it to mm/dd/yyyy hh/nn/ss UTC format
'2015-02-06T08:26:00-08:00
orderyear = Mid(orderdate, 1, 4)
ordermonth = Mid(orderdate, 6, 2)
orderday = Mid(orderdate, 9, 2)
orderhour = Mid(orderdate, 12, 2)
orderminute = Mid(orderdate, 15, 2)
ordersecond = Mid(orderdate, 18, 2)
newdate = ordermonth & "/" & orderday & "/" & orderyear
newtime = orderhour & ":" & orderminute & ":" & ordersecond
'Debug.Print newdate
convertDate = newdate & " " & newtime & " UTC"
End Function
Because your input isn't a true date none of Excel or VBA's date methods will work with it. Your best bet is to break the string down into parts, work with them individually, and then join it all back up again - for example:
testdate = "2015-02-12T22:57:05-08:00"
'// The letter T is redundant, so let's split the string here into an array:
dateArr = Split(testdate, "T")
'// Part 1 of the array can be easily converted with CDate() and Format()
dateArr(0) = Format(CDate(dateArr(0)), "mm/dd/yyyy")
'// Part 2 of the array will need to be broken down further:
dateArr(1) = Format(TimeValue(Split(dateArr(1), "-")(0)) - _
TimeSerial(Left(Split(dateArr(1), "-")(1), 2), _
Right(Split(dateArr(1), "-")(1), 2), 0), "hh:mm:ss")
'// The above line does the following:
'// 1) Split the second part of the array again, using the "-" as the delimiter
'// 2) Convert the first part of this (22:57:05) to a time using TimeValue()
'// 3) Convert the second part (08:00) to hours & minutes using TimeSerial()
'// 4) Minus the latter from the former (which can only be done if both are a valid time)
'// 5) Wrap all that into a Format() method to show "hh:mm:ss" instead of a Double.
'// Join the two parts back together and add "PST" on the end.
newdate = Join(dateArr, " ") & " PST"
Debug.Print newdate
'// Output will display "02/12/2015 14:57:05 PST"
N.B. I have chosen not to include "AM" or "PM" because your time is in 24hr format anyway so I don't see the relevance...
It's not converting because of the "T" and because of the tacked on time range at the end. You can ditch the "T" and truncate off the trailing range and it will convert.
Public Sub Example()
Const testValue As String = "2015-02-12T22:57:05-08:00"
Dim dateValue As Date
Dim stringValue As String
Dim subVal As Date
Dim hyphenPos As Long
stringValue = testValue
Mid(stringValue, 11&, 1&) = " "
hyphenPos = InStrRev(stringValue, "-")
subVal = Mid$(stringValue, hyphenPos + 1&)
dateValue = CDate(Left$(stringValue, hyphenPos - 1&)) - subVal
End Sub
Couple of ideas:
The sample date you have 2015-02-12T22:57:05-08:00 is not a real date (I think)
I think the following will give you the closest format to what you are looking for (you will need to define the range.Range.NumberFormat = "[$-409]h:mm:ss AM/PM"
Your best bet is concating "PST" to a date datatype formatted to your needs.
Sub DebugPrintDate()
Dim testdate As Date: testdate = Now
newdate = Format(testdate, "mmm/dd/yyyy hh:mm AM/PM") & " PST"
Debug.Print newdate
End Sub
Ouput:
Never mind the "févr". My system locale is France.
If you want to define a particular date, make sure to wrap the date in two #s.
Example:
Dim someDateAndTime As Date = #8/13/2002 12:14 PM#

Excel VBA Set Variable to Equal Values between Dates

In Excel using VBA, I need to set a variable to equal a list of all the dates between a start and end date (similar to equaling a range containing multiple values). The catch is only the start and end date are in a range, non of the values in between.
In SQL Server I've used the Sys.Columns table to generate a list of dates between two dates that are not actually stored on that table. Is there a way to do something similar here without having each date between the start and end date written somewhere? I googled for a couple hours and didn't find anything on how to do this.
What I'm attempting to do is have a variable I can do a For Each loop on. So for each date I will check if it exists in another worksheet, if it does nothing will happen, if it does not it will be added.
I've tried:
Dim DatesInSettings As Date
DatesInSettings = StartDate To EndDate
For Each Date In DatesInSettings
'Insert commands here
Next DatesInSetting
But that clearly isn't the answer. Help?
This searches Sheet2 for dates between the start date and end dates on Sheet1 - in cells A1 and B1:
Sub RunDates()
Dim StartDate As Date
Dim EndDate As Date
Dim i As Date
StartDate = Sheet1.Range("A1")
EndDate = Sheet1.Range("B1")
For i = StartDate To EndDate
If WorksheetFunction.CountIf(Sheet2.Range("A1:A5"), i) > 0 Then
Debug.Print i; "- date found"
Else
Debug.Print i; "- date not found"
End If
Next i
End Sub
The following subroutine calls a dictionary that will store all the dates between two given endpoints. Then it uses a simple existence comparison to check if the dates on your list is inside the dictionary's items. If it's not, it's going to print them out as not in the list.
Modify accordingly to suit your needs. ;)
CODE:
Sub GetListOfDates()
Dim StartDate As Date, EndDate As Date
Dim DictOfDates As Object, DateToCheck As Variant, ListOfDates As Variant
Dim Iter As Long
Set DictOfDates = CreateObject("Scripting.Dictionary")
StartDate = "12/31/2013"
EndDate = "01/15/2014"
For Iter = StartDate + 1 To EndDate - 1
With DictOfDates
If Not .Exists(Iter) Then
.Add Iter, Empty
End If
End With
Next Iter
'--Print them somewhere.
'Range("A1").Resize(DictOfDates.Count, 1).Value = Application.Transpose(DictOfDates.Keys)
ListOfDates = Range("B1:B15").Value
For Each DateToCheck In ListOfDates
If Not DictOfDates.Exists(DateToCheck) Then
Debug.Print Str(DateToCheck) + " is not in the list!" '--Or whatever action you want.
End If
Next DateToCheck
Set DictOfDates = Nothing
End Sub
Let us know if this helps. :)
I solved it with a vector.
I hope it helps
Sub Dates_Vector()
Public Dates() As Date
ReDim Dates(End_Dat - Start_Date)
For x = 0 To End_Dat - Start_Date
Dates(x) = Dat_Ini + x
Next x
For Each Date In Dates
'Insert commands here
Next Date
End Sub