This is my first time asking in Stack Overflow :)
I have a program that lets the user pick a date in a combobox and display it on the label. The other parts of the code for that is fine but I cant make exception for months with special days (like february which only has 29 days in leap years).
I tried using the If/Else statement so that when the users click the years 2016,2012,2008 and 2004 and february it will display on the combobox named "day" 1 to 29 and if the users click february but not the specified dates it will display 1 to 28:
If month.SelectedItem = "Feb" And year.SelectedItem = "2016" Or "2012" Or "2008" Or "2004" Then
Dim jkl As Integer
For jkl = 1 To 29
day.Items.Add(jkl)
Next
ElseIf month.SelectedItem = "Feb" Then
Dim poi As Integer
For poi = 1 To 28
day.Items.Add("poi")
Next
End If
But unfortunately when i debug it, when i select dates other than the specified in the first If statement the combo box named day only displays 29 instead of 28. I tried changing the order of the conditions, changing the separator of the numbers to "&" but it is still the same.
I hope someone gets to the bottom of this. I feel like its in my structure that is wrong but even if I change the order everytime and it is still displaying the same bug.
I tried searching here but I cant find one like my condition even remotely similar.
Turn Option Strict On, it will help you detect these errors right away. VB does not handle If statement like this, what you wrote doesn't do what you think it does. You need to specify both side every time.
If month.SelectedItem = "Feb" And (year.SelectedItem = "2016" Or year.SelectedItem = "2012" Or year.SelectedItem = "2008" Or year.SelectedItem = "2004") Then
As for your logic, there are formula to detect leap day. It might be better to use it instead.
Lastly, near the end, you add the string and not the variable value.
day.Items.Add(poi)
I think you should use here the DateTime functions:
DateTime.DaysInMonth(year, month)
Docs
Dim dateString As String = String.Format("{0} 1 2001", month.SelectedItem)
Dim dDate As Date = DateTime.Parse(dateString)
Dim numberOfMonth As Integer = DateAndTime.Month(dDate)
For jkl = 1 To DateTime.DaysInMonth(numberOfMonth, year.SelectedItem)
day.Items.Add(jkl)
Next
Personally, i would have made a nested If
if month.SelectedItem = "Feb" then
if year.SelectedItem = "2016" Or "2012" Or "2008" Or "2004" Then
Dim jkl As Integer
For jkl = 1 To 29
day.Items.Add(jkl)
Next
else
Dim poi As Integer
For poi = 1 To 28
day.Items.Add("poi")
Next
end if
Related
I have a spreadsheet containing dates in English format:
12 Feb 2015
13 Oct 2016
etc.
However, since my MS Excel is in French, it doesn't take them as dates but rather as strings.
I need to do some parsing with those values, so I run my procedure but something annoying happens. VBA, set in English no matter the OS/Microsoft language, gets the 12 Feb 2015 as a date and so, when I print it back, it returns me the French date (12-févr-2015, read as 12/02/2015). This stops me comparing that value with the previous 12 Feb 2015.
Is there anyway I can ask VBA not to take the initiative of interpreting my string as a date?
Here is a simplified version of my code + test case (but I guess you won't be able to see the issue if running it on an English Excel):
Put the string 12 Feb 2015 in the Range A1 of your spreadsheet
Run the following code:
Sub test()
myVal = Range("A1").Value
Range("A2").Value = myVal
End Sub
The value in Range("A2") will be a date in your Excel language, and not a string as it was before.
Note: I have thought of writing Range("A2").Value = "'" & myVal to let the value be a String instead of a date, but it doesn't make me possible to later compare 12 Feb 2015 with '12 Feb 2015 and, anyway, 12 Feb 2015 becomes a date already when it's read by myVal = Range("A1").Value.
If you want to retain the string, just use Text in place of Value, and define the storage variable as a string. Like so
Sub test()
Dim myVal as String
myVal = Range("A1").Text
Range("A2").Value = myVal
End Sub
Text is read only, so still using Value to write to the new cell. Docs which include an example for the difference between Value and Text: https://msdn.microsoft.com/en-us/library/office/ff840217.aspx
I have cells that can either contain time in this format:
1625 (16 for 2016 and 25 for week 25)
Or in this format
2016-Q2 (Q2 means quarter 2 if the year)
When converting I want quarters to be the mid week of the quarter
2016-Q1 = 1608
2016-Q2 = 1620
2016-Q3 = 1633
2016-Q4 = 1646
I dont want to convert the times in the cell its in. I want to convert it to YYWW format for a formula for a timeline in another sheet. So I use help cells with the converted value and reference those instead of the values in the other sheet.
I have done this with nested if functions resulting in mile long formulas because the timeline needs to be very long and the time can very well be 2025-Q3.
a =IF('Gulpilspuls NT'!U4="2016-Q1";1608;IF('Gulpilspuls NT'!U4="2016-Q2";1620;IF('Gulpilspuls NT'!U4="2016-Q3";1633;IF('Gulpilspuls NT'!U4="2016-Q4";1646;IF('Gulpilspuls NT'!U4="2017-Q1";1708;IF('Gulpilspuls NT'!U4="2017-Q2";1720;IF('Gulpilspuls NT'!U4="2017-Q3";1733;IF('Gulpilspuls NT'!U4="2017-Q4";1746;IF('Gulpilspuls NT'!U4="2018-Q1";1808;IF('Gulpilspuls NT'!U4="2018-Q2";1820;IF('Gulpilspuls NT'!U4="2018-Q3";1833;IF('Gulpilspuls NT'!U4="2018-Q4";1846;IF('Gulpilspuls NT'!U4="2019-Q1";1908;IF('Gulpilspuls NT'!U4="2019-Q2";1920;IF('Gulpilspuls NT'!U4="2019-Q3";1933;IF('Gulpilspuls NT'!U4="2019-Q4";1946;IF('Gulpilspuls NT'!U4="2020-Q1";2008;IF('Gulpilspuls NT'!U4="2020-Q2";2020;IF('Gulpilspuls NT'!U4="2020-Q3";2033;IF('Gulpilspuls NT'!U4="2020-Q4";2046;IF('Gulpilspuls NT'!U4="2021-Q1";2108;IF('Gulpilspuls NT'!U4="2021-Q2";2120;IF('Gulpilspuls NT'!U4="2021-Q3";2133;IF('Gulpilspuls NT'!U4="2021-Q4";2146;IF('Gulpilspuls NT'!U4="2022-Q1";2208;IF('Gulpilspuls NT'!U4="2022-Q2";2220;IF('Gulpilspuls NT'!U4="2022-Q3";2233;IF('Gulpilspuls NT'!U4="2022-Q4";2246;IF('Gulpilspuls NT'!U4="2023-Q1";2308;IF('Gulpilspuls NT'!U4="2023-Q2";2320;IF('Gulpilspuls NT'!U4="2023-Q3";2333;IF('Gulpilspuls NT'!U4="2023-Q4";2346;IF('Gulpilspuls NT'!U4="2024-Q1";2408;IF('Gulpilspuls NT'!U4="2024-Q2";2420;IF('Gulpilspuls NT'!U4="2024-Q3";2433;IF('Gulpilspuls NT'!U4="2024-Q4";2446;IF('Gulpilspuls NT'!U4="2025-Q1";2508;IF('Gulpilspuls NT'!U4="2025-Q2";2520;IF('Gulpilspuls NT'!U4="2025-Q3";2533;IF('Gulpilspuls NT'!U4="2025-Q4";2546;IF('Gulpilspuls NT'!U4="2026-Q1";2608;IF('Gulpilspuls NT'!U4="2026-Q2";2620;IF('Gulpilspuls NT'!U4="2026-Q3";2633;IF('Gulpilspuls NT'!U4="2026-Q4";2646;IF('Gulpilspuls NT'!U4="2027-Q1";2708;IF('Gulpilspuls NT'!U4="2027-Q2";2720;IF('Gulpilspuls NT'!U4="2027-Q3";2733;IF('Gulpilspuls NT'!U4="2027-Q4";2746;IF('Gulpilspuls NT'!U4="2028-Q1";2808;IF('Gulpilspuls NT'!U4="2028-Q2";2820;IF('Gulpilspuls NT'!U4="2028-Q3";2833;IF('Gulpilspuls NT'!U4="2028-Q4";2846;IF('Gulpilspuls NT'!U4="2029-Q1";2908;IF('Gulpilspuls NT'!U4="2029-Q2";2920;IF('Gulpilspuls NT'!U4="2029-Q3";2933;IF('Gulpilspuls NT'!U4="2029-Q4";2946;IF('Gulpilspuls NT'!U4="2030-Q1";3008;IF('Gulpilspuls NT'!U4="2030-Q2";3020;IF('Gulpilspuls NT'!U4="2030-Q3";3033;IF('Gulpilspuls NT'!U4="2030-Q4";3046;IF('Gulpilspuls NT'!U4="2031-Q1";3108;IF('Gulpilspuls NT'!U4="2031-Q2";3120;IF('Gulpilspuls NT'!U4="2031-Q3";3146;IF('Gulpilspuls NT'!U4="2031-Q4";3146;IF('Gulpilspuls NT'!U4="2032-Q1";3208;IF('Gulpilspuls NT'!U4="2032-Q2";3220;IF('Gulpilspuls NT'!U4="2032-Q3";3233;IF('Gulpilspuls NT'!U4="2032-Q4";3246;IF('Gulpilspuls NT'!U4="2033-Q1";3308;IF('Gulpilspuls NT'!U4="2033-Q2";3320;IF('Gulpilspuls NT'!U4="2033-Q3";3333;IF('Gulpilspuls NT'!U4="2033-Q4";3346;IF('Gulpilspuls NT'!U4="2034-Q1";3408;IF('Gulpilspuls NT'!U4="2034-Q2";3420;IF('Gulpilspuls NT'!U4="2034-Q3";3433;IF('Gulpilspuls NT'!U4="2034-Q4";3446;IF('Gulpilspuls NT'!U4="2035-Q1";3508;IF('Gulpilspuls NT'!U4="2035-Q2";3520;IF('Gulpilspuls NT'!U4="2035-Q3";3533;IF('Gulpilspuls NT'!U4="2035-Q4";3546;IF('Gulpilspuls NT'!U4="2036-Q1";3608;IF('Gulpilspuls NT'!U4="2036-Q2";3620;IF('Gulpilspuls NT'!U4="2036-Q3";3633;IF('Gulpilspuls NT'!U4="2036-Q4";3646;IF('Gulpilspuls NT'!U4="2037-Q1";3708;IF('Gulpilspuls NT'!U4="2037-Q2";3720;IF('Gulpilspuls NT'!U4="2037-Q3";3733;IF('Gulpilspuls NT'!U4="2037-Q4";3746;IF('Gulpilspuls NT'!U4="2038-Q1";3808;IF('Gulpilspuls NT'!U4="2038-Q2";3820;IF('Gulpilspuls NT'!U4="2038-Q3";3833;IF('Gulpilspuls NT'!U4="2038-Q4";3846;'Gulpilspuls NT'!U4))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))
As you can clearly see this method is not the best. I cant make it this long because nested if functions can only contain 64 levels of nesting. Do you guys have a better suggestion for this?
The formula has to work with both formats of time entry and I need it to be able to convert all the cells 1:1 meaning 1 cell in the calendar has to be 1 converted cell in the other spot that I can use for the formula. If the cell in the calendar does not have YYYY-Q1234? it should just show what it is instead as you can see at the end of my formula.
Here is your formula.
=IF(AND(LEN(C6)=4,ISERROR(FIND("-",C6))),C6,MID(C6,3,2)&INDEX({"08",20,33,46},RIGHT(C6,1)))
Make sure there is no excess space in your data. Not like this "2016-Q1 ", but like this "2016-Q1".
EDIT: I just realized that if the original is in the format of YYWW, that you do NOT want it changed to the mid quarter week number. So we simplify the formulas:
=IF(ISNUMBER(-A1),A1,MID(A1,3,2) & CHOOSE(RIGHT(A1,1),"08",20,33,46))
and if you want YYWW to always be rendered as numeric:
=1*IF(ISNUMBER(-A1),A1,MID(A1,3,2) & CHOOSE(RIGHT(A1,1),"08",20,33,46))
And here are the results for various samples:
EDIT: If you need to check for blanks, you can do this simply:
=IF(LEN(A1)=0,"",1*IF(ISNUMBER(-A1),A1,MID(A1,3,2) & CHOOSE(RIGHT(A1,1),"08",20,33,46)))
However, if a 0 will not result in a downstream problem, you can use the original, shorter formula, and merely use a custom format to suppress zero returns: 0;;
And if you need to check for other conditions for which you don't want to process, you can perform similar actions.
something like this should do it, however, mid way through Q1, is week 6, so you'll need to adjust if your year doesn't start at 1/1
Function get_week(strInput As String) As String
Dim strQ As String
Dim bytQ As Byte
Dim dblMultiplier As Double
Dim intWeekNumber As Integer
strQ = Split(strInput, "-")(0)
bytQ = CByte(Right(strQ, 1))
dblMultiplier = (bytQ - 1) / 4
intWeekNumber = (dblMultiplier * 52)
intWeekNumber = intWeekNumber + (13 / 2)
get_week = Split(strInput, "-")(1) & "-" & CStr(intWeekNumber)
End Function
Let me try again
="20"&LEFT(N5,2)&IF(MOD(N5,100)<=8,"-Q1",IF(MOD(N5,100)<=20,"-Q2",IF(MOD(N5,100)<=33,"-Q3",if(MOD(N5,100)<=46,"-Q4","-Q1"))))
Should work for everything past year 2000 ;)
I am writing a medication administration app. The main table name is ResidentMedications. The second table name is Resident24HourTable. My main form is ResidentMedicationsExtended, with a subform Resident24HourPeriod. Resident24HourPeriod contains 24 check boxes, one for each hour in the day. (12A, 1A, 2A, 3A etc).
Within the ResidentMedicationsExtended form is a combo box [Frequency]. For simplicity sake, let's say "Q4H" is selected, for "4 times per day". Another field [First Dose] allows the user to enter the time the resident will receive their first daily dose. We'll say 6:00 AM.
I have a command button that I want to check the appropriate times in the subform based on the Frequency and First Dose fields. So far, I have written the following:
Private Sub Command90_Click()
If Me.FirstDose = "12:00:00 AM" Then
Forms!ResidentMedicationsExtended.Form.Resident24HourTable![12A] = True
ElseIf Me.FirstDose = "1:00:00 AM" Then
Forms!ResidentMedicationsExtended.Form.Resident24HourTable![1A] = True
ElseIf Me.FirstDose = "2:00:00 AM" Then
Forms!ResidentMedicationsExtended.Form.Resident24HourTable![2A] = True
ElseIf Me.FirstDose = "3:00:00 AM" Then
Forms!ResidentMedicationsExtended.Form.Resident24HourTable![3A] = True
and so on and so forth - many many lines. I know I can write separate lines for each time, write more to make checkboxes False, etc. Obviously, doing it this way will result in a zillion or so lines of code, and I have yet to calculate the rest of the days medication times.
Is there a Loop or something I can use instead? I've read loads of posts and haven't been able to come up with a solution.
I thank you in advance for your time!
4 times in a day means [once every 6 hours]. In your dropdown boxes, you should display the text description, but for the key, use values that make it easier to do the math. Use the period between occurrances, in terms of hours. Then it will be easier to use a loop to run through the occurrances (until you have covered a 24-hour period).
Another alternative would be to use date calculation functions like CDate(), DateAdd() and DatePart() to calculate time values.
So, for your example: 4 times a day. Your list value would be 6 (6 hour intervals)
Private Sub Command30_Click()
Dim totalHours as integer
Dim interval as integer
interval = *** the value from your interval dropdown, eg 6 (hours) ***
Dim nextDose as integer
nextDose = Me.FirstDose ' text was 12 am, but stored in 24 hour format as 0
While totalHours < 24
Forms!ResidentMedicationsExtended.Form.Resident24HourTable![nextDose] = True
nextDose = nextDose + interval
totalHours = totalHours + interval
Wend 'or End While
Use Hour() and TimeValue() to convert "1:00:00 AM" to 1, etc., then use this number to identify the Control:
Dim hrFirst As Integer
hrFirst = Hour(TimeValue(Me.FirstDose)) 'returns 0 for 12am, 1 for 1am
hrFirst = IIF(hrFirst = 0, 12, hrFirst)
Forms!ResidentMedicationsExtended.Form.Resident24HourTable.Controls(hrFirst & "A") = True
I have 3 textboxes (day, month, year) and I want to check if input is e.g. day has to be from 1 to 31 and so on.
My code is:
If InputDan.Text < "1" Or InputDan > "31" Then Warning.Text = "Not a valid day input." Else Warning.Text = ""
Also I have day and month input limited to 2 characters and year to 4.
It works fine with numbers from 10 to 31 and it properly puts an warning message when input is 0 or 32 and on.
Here's the problem...
When I put in numbers from 4 to 9 it puts on a warning message, as I figured out later that program considers empty space after one character input as 0.
So if I enter 4 the program will read it as 40, and so on.
Can I solve this problem with converting String input as Int somehow?
You need to parse the numbers to integer before you can compare them, otherwise >"11" will compare them alphabetically and not by their numerical order.
Dim day As Integer
Dim valid As Boolean = Int32.TryParse(InputDan.Text, day)
Now you know if that input was a correct number and you could show a warning if it was not.
I would suggest a different approach to check whether or not the input was a correct day since you must take the number of days in that month into account(also leap years, different calendars etc). So use the current culture's calendar and look if the number of days is correct for the given month in this way:
Dim daysInMonth = CultureInfo.CurrentCulture.Calendar.GetDaysInMonth(year, month)
If day > daysInMonth OrElse day < 1 Then
' show warning '
End If
(assuming you have already checked the year and month part with Int32.TryParse)
Better than doing this from the code behind, asp.net has already validations here is an example of a textbox that represents the day, and it has to be between 1 and 31:
<asp:TextBox ID="TextBox2" runat="server"></asp:TextBox>
<asp:RangeValidator ID="RangeValidator1" runat="server"
ErrorMessage="You have to insert a valid day" ControlToValidate="TextBox2" MaximumValue="31" MinimumValue="1"></asp:RangeValidator>
check it out
Your problem is, that "9" (the string) IS "larger" than "31". Because sorting is done on the first char, then the second and so on.
Dim Value As Integer
' is there an (integer) NUMBER in the textbox?
If Integer.TryParse(InputDan.Text, Value) Then
If Value > 0 AndAlso Value < 31 Then
' do something
Else
MessageBox.Show("please enter a number!")
End If
Else
MessageBox.Show("please enter a number!")
End If
With "TryParse" you can test if a String can be converted to an Integer (or Double, Single, whatever implements a TryParse method) and if it can be converted, the value is stored in the second parameter.
You should use Strict on" to avoid the coding problems - basically you are comparing strings against each other. They do NOT behave like Integers for comparisons.
Try like this: (Assuming framework above/or 3.5)
If Not IsNumeric(InputDan.Text) OrElse _
Not Enumerable.Range(1, 31).Contains(CInt(InputDan.Text)) Then
Warning.Text = "Not a valid day input."
Else
Warning.Text = ""
End If
It will first validate the input must be a number and then will validate if it lies within range of 1 and 31. I assume Days can not be 1.5 so I called CInt.
OrElse is what we call ShortCircuit. The second condition will not evaluate if the first one failed.
Long story short:
I need the inverted function of WeekdayName(), in the following terms:
You provide a week day name (e.g. Sunday)
You get the correspondent week day number (that depends which is the first week day as returned in WeekdayName, e.g., you get 1 for Sunday if Sunday is the first day of the week)
Background:
I'm using date functions in vb.net. So far so good. I'm using the function WeekdayName() in order to set the titles for tab pages in a TabControl. My custom control (kind of calendar control) holds the mentioned TabControl and it has the option of choosing which day of the week you want to diplay.
If you want to display ALL days, the TabControl will have TabPages filled by iterating upon the WeekdayName() function mentioned above (localized and managed by the system calendar and capitalized by me).
If you set only Tuesday and Friday, you will have two tab pages with those titles and sorted as [Tuesday | Friday]. If you decide to add Wednesday, now you should have 3 tab pages: [Tuesday | Wednesday | Friday], and so on...
In order to keep tabs sorted, when I need to insert a tab to be shown I want to provide the tab's title to check against the new-to-insert weekday name and in that way have the order resolved.
I believe one workaround is to create a fake date object with the tab's title string in it in order to have a, for instance, "Sunday" date and then use: Weekday() but I was hoping an API solution.
NOTE: This is not: how to get the day number from a date.
EDIT:
As we disscused with #jmshapland, a custom code approach using the default localization and system settings could be:
Function WeekdayNumber(day as String)
' The following initialization does not necessary go in this function.
' The idea is to have a mapping between key day name and index in the
' same order as the WeekdayName() method with the default system settings
Dim weekdayNamesCollection as Collection = New Collection()
For i = 1 to WEEKDAYS
Dim wDay as String = WeekdayName(i)
' add the day with a key with the same name
weekdayNamesCollection.add(wDay, wDay)
Next i
If weekdayNamesCollection.ContainsKey(day) Then
Return weekdayNamesCollection.IndexOfKey(day) + 1
End If
' Raise an error as the string 'day' is not in the collection
End Sub
I didn't test this out as I am in a computer without any framework and/or IDE. But basically, the idea is to return the index where the weekday name is stored in the collection (previously, it was stored in the system settings order as WeekdayName().
I don't think there's a built-in function for it. But if you are using WeekdayName then you should use it for your purpose.
Public Function WeekDayNumber(ByVal weekName As String) As Integer
Dim weekNames As New Dictionary(Of String, Integer)
For i As Integer = 1 To 7
weekNames.Add(WeekdayName(i), i)
Next
Return weekNames(weekName)
End Function
Sorry if this is formatted poorly, I never work with VB usually just C#. However, this should do what you are looking for... If you want the first day of the week to return as 0 instead of 1 just remove the + 1 from the return statement.
Private Function FindDayOfWeek(day As String) As Integer
Dim daysOfWeek = CultureInfo.CurrentCulture.DateTimeFormat.DayNames
Dim counter As Integer = Array.IndexOf(daysOfWeek, WeekdayName(1))
Dim numericDay As Integer
For i As Integer = 0 To 6
If counter > 6 Then
counter = 0
End If
If daysOfWeek(counter) = day Then
numericDay = i
Exit For
End If
counter += 1
Next
Return numericDay + 1
End Function
By using val() function, will give Day of Week number from 0 to 6 :
intDayofWeek = val(System.DateTime.Now.DayOfWeek)