I wanna have a drop down that lets me select "Week Commencing Monday the 20th" going back 10 Mondays but I'm not sure how to go about doing this.
I've used date.now(), etc. before but not sure how to do this one.
Thanks,
Billy
UPDATED CODE
Public Sub GetMondays()
Dim dtMondays As New DataTable()
dtMondays.Columns.Add("Date")
Dim i As Integer = 1
While (dtMondays.Rows.Count < 11)
Dim Day As DateTime = Today.AddDays(-i)
If Day.DayOfWeek = 1 Then
dtMondays.Rows.Add(Day)
End If
i += 1
End While
drpDate.DataSource = dtMondays
drpDate.DataBind()
End Sub
You could come up with a formula for calculating the dates of the previous Mondays, but why not do something simple:
Begin loop.
Subtract one day.
Check if it is Monday.
If so, add to a list.
If the list contains 10 elements, exit loop.
Go back to start of loop.
I'm sure you can implement that. It's not that fastest way, but it's simple and probably fast enough for most purposes. If you want to optimize it, you can do so, but it's probably not worth your time unless this is being executed many times per second.
Let's work through it. I'll do this in C# but hopefully some enterprising young polyglot can do the translation for me and score the accepted answer.
DateTime.Today gets you today's date. DateTime.Today.DayOfWeek gets you today's "day of the week" as an enum, where Sunday is 0 and Saturday is 6.
So we can get the latest Monday using:
var lastMonday = DateTime.Today.AddDays(1 - (int)DateTime.Today.DayOfWeek);
edit There's one little glitch here, in that if today is Sunday you'll be getting tomorrow's date, not last Monday's. There's probably some really tricky mathematical way to get around that, but it's just as easy to throw in an extra check:
if (lastMonday > DateTime.Today) lastMonday = lastMonday.AddDays(-7);
Then we just need to get ten of them:
var lastTenMondays = from i in Enumerable.Range(0, 10)
select lastMonday.AddDays(i * -7);
I was searching for something similar, only that I wanted to display the upcoming Mondays. This thread helped in some way. Thanks!
Even though this thread is old, for any one coming across, this may be helpful:
Public Sub Form5_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim nextMondays = DateTime.Today.AddDays(1 - CInt(DateTime.Today.DayOfWeek))
Dim i As Integer = 1
If nextMondays < DateTime.Today Then
nextMondays = nextMondays.AddDays(+7)
End If
For i = 0 To 14
ComboBox1.Items.Add("Mon. " + nextMondays.AddDays(i * +7))
Next i
End Sub
It's probably late but might be helpful for others.
You can do what Mark said but instead of continuing the loop once you find a Monday you can then subtract 7 (or add if you want to find the next 10 mondays) days and get the other monday and you can do this 10 times
* Begin loop.
* Subtract one day.
* Check if it is Monday.
o If so, add to a list.
o (in a for i = 1 to 10 loop) add 7 days and add to list (end for loop)
* Go back to start of loop.
this might save up some time.
Related
I am still learning basic programming, literally off Visual Basic 2012 v11.
Here is what I am stumped on:
I made a stupid-simple Table-Top Role-Playing Character Log application.
I made a simple dice roller/"random number" procedure and set it to fill a ListBox with each button click of "ROLL" until the max of 6 was reached. That worked fine.
However, I changed my app to link with a database to store simple character information for all of the people playing,etc. Which means I now have separate dataset TextBoxes for each click of "ROLL". Would someone please advise me on the best way to populate one TextBox per button click with a maximum of 6 clicks, please?
I was using a loop to fill the ListBox with exactly 6 entries, and started that line of thought for filling the TextBoxes, but my late-night tired brain cannot find a way to fill ONE box EACH TIME instead of all boxes every single time.
THANK YOU FOR YOUR HELP!
My Code:
Private Sub btnRoll_Click(sender As Object, e As EventArgs) Handles btnRoll.Click
'Roll a character stat up to 6 and add it to the lisbox
'D20 is standard die, but stats below 6 are forgiven for this campagin
Dim Dice As New Random
Dim DiceRoll As Integer = Dice.Next(6, 20)
Dim intCount As Integer = 0
Dim Stat As String = Convert.ToString(DiceRoll)
Do While intCount < 7
Loop
End Sub
I don't believe you've included enough information to give an informed answer.
From my understanding, you'd like to take the result of the roll, and input it into one of several textboxes (you haven't given a number of textboxes, but you'd like it done in less than 6 clicks).
Depending on what the different fields will be, you may want to include your calculations within the loop, along with this, to specify the output and then roll again X times within the loop:
Do While intcount < 7
Select Case intcount
Case 1
txtBox1 = stat
Case 2
txtBox2 = stat
Case 3
txtBox3 = stat
Case 4
txtBox4 = stat
Case 5
txtBox5 = stat
Case 6
txtBox6 = stat
Case Else
'Nothing if not specified with other arguments.
'Roll again
stat = Convert.ToString(Dice.Next(6,20))
Loop
I'm trying to delete files that are more than six months old. This is my code. It recognizes the files, but does not delete.
Private Sub DeleteOldBackup()
'deletes files older than six months from backup
Try
For Each fi As IO.FileInfo In New IO.DirectoryInfo(BACKUP).GetFiles()
If DateDiff(DateInterval.Month, Now, fi.CreationTime) > 6 Then
fi.Delete()
End If
Next
Catch ex As Exception
Call WriteToErrorLog("DeleteOldBackup", ex)
SendErrorEmail("Long Term Report Storage failed in DeleteOldBackup")
End Try
End Sub
DateDiff subtracts from the second date the first date. Passing the highest date in the first position returns a negative number.
Just swap the positions of the two dates
If DateDiff(DateInterval.Month, fi.CreationTime, Now ) > 6 Then
Keep also present that this calculation is wrong. For example
Dim d1 = new DateTime(2014,1,1)
Dim x = DateDiff(DateInterval.Month, d1, Now)
Console.WriteLine(x)
The code above prints 6 but actually there are more than 6 months between the first of january and today. Perhaps you should use DateInterval.Day and check against something like 180 days to have a better approximation of 6 months
I'm working on a timetabling piece of code. I am using a system of university modules and events associated to those modules, ie
Module CSC3039
Event1 - Lecture
Event2 - Lecture
Event3 - Practial etc
I need to check the times of each event in the module against each other and compare for clashes. The clashes do not need to be rectified, just highlighted. The table I will use is Events containing Event_ID (PK), Module_code (FK), Start_Date_Time, End_Date_Time plus other fields that don't matter here. I have figured out that I need to implement a For Each statement, ultimately resulting in an if statement such as:
if (startTime1 <= endTime2 or endTime1 >= startTime2) CLASH
My problem is trying to figure out the actual for loop here. I don't know what to write to declare my start times and end times. I presume it is a case of taking event1 and getting its start and end and then checking if event 2, 3 or 4 fit the above if statement. I'm trying to get this but could really use some guidance.
EDIT... Based on suggestions below I have implemented the following code:
'return all relevant tables from the Modules database, based on the module code entered by the user.
Dim eventTime = (From mods In db.Modules
Join evnt In db.Events On mods.Module_code Equals evnt.Module_code
Join rm In db.Rooms On rm.Room_ID Equals evnt.Room_ID
Join build In db.Buildings On build.Building_code Equals rm.Building_code
Where ((mods.Module_code = initialModCode) And (evnt.Room_ID = rm.Room_ID))
Select evnt.Event_ID, evnt.Module_code, evnt.Event_type, evnt.Start_Date_Time, evnt.End_Date_Time, build.Building_code, rm.Room_Number)
'use the gridview to display the result returned by the above query
gdvEventsTable.DataSource = eventTime
gdvEventsTable.DataBind()
Dim listClashes As New List(Of Array)
For i As Integer = 0 To eventTime.Count - 1
For j As Integer = i + 1 To eventTime.Count - 1
If (eventTime.ToList(i).Start_Date_Time < eventTime.ToList(j).End_Date_Time) And (eventTime.ToList(i).End_Date_Time > eventTime.ToList(j).Start_Date_Time) Then
MsgBox("Clash", MsgBoxStyle.MsgBoxSetForeground, "")
listClashes.Add(eventTime)
Else
MsgBox("No Clash", MsgBoxStyle.MsgBoxSetForeground, "")
End If
Next
Next
When trying to add an event to my array list I have noticed, in debug, that no events are sent to the list.
If you want to compare all the pairs of events that are in an array or some kind of a collection, you can use a loop like:
Dim ModuleEventArray() As ModuleEvent
'...
For i As Integer = 0 To ModuleEventArray.Length - 1
For j As Integer = i + 1 To ModuleEventArray.Length - 1
'test if ModuleEventArray(i) overlaps with ModuleEventArray(j)
Next
Next
ModuleEvent here would be another class or structure that has fields startTime and endTime. The test
if (startTime1 <= endTime2 or endTime1 >= startTime2)
is not enough to test for overlap, but maybe you can figure out the correct test yourself :)
EDIT:
Since I see you use some sort of collection, not array, the code you need should be something like:
For i As Integer = 0 To eventTime.Count - 1
For j As Integer = i + 1 To eventTime.Count - 1
If (eventTime.Item(i).Start_Date_Time < eventTime.Item(j).End_Date_Time) And (eventTime.Item(i).End_Date_Time > eventTime.Item(j).Start_Date_Time) Then
MsgBox("Clash")
Else
MsgBox("No Clash")
End If
Next
Next
Before you write your code, you need to first decide what your algorithm is going to be. For example, if you use the naive method your presume, the code is indeed straightforward (basically 2 nested loops) but the complexity if O(n²).
Depending on how much data you have, whether it is in a database, how likely you expect clashes to be, whether you always have the full list of events at the start or you need to find clashes incrementally, etc... different solutions might be preferred. One consideration is whether you need to partition the list into non-clashing sets of events or just produce a yes/no answer (one one for each event) stating whether there is a clash.
You might consider doing something different instead, like sorting the list by start time before you start comparing. That will allow you to walk the list only once.
My comparisons are coming from the database. Prior to the code below I have a query which returns all the records from my Events table, based on the user input of a Module_Code. This code will show the clashes, through a msgbox. I will be changing it to populate a list. It's not the prettiest and will probably lead to a lot of duplication but it achieves my main objective.
For Each evnt In eventTime
Dim startTime1 = evnt.Start_Date_Time
Dim endTime1 = evnt.End_Date_Time
For Each evat In eventTime
Dim startTime2 = evat.Start_Date_Time
Dim endTime2 = evat.End_Date_Time
If (startTime1 < endTime2) And (endTime1 > startTime2) Then
MsgBox("Clash")
Else
MsgBox("No Clash")
End If
Next
Next
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)
I have a program below that doesn't seem to be doing what I want it to do. In general, the pseudocode is: enter the number of miles (miles.text), click button, check: is the mileage entered equal to or less than the mileage radius (milestotextbox) in the database? If so, grab the truckload rate that corresponds to that radius (truckloadratetext) and display it in a textbox called "rate" (rate.text) and if not, continue looking until EOF. I've shown the code below. It lets me enter the mileage but won't check and display the result.
The data in the table looks like this:
ID MILESTO TRUCKLOADRATE
1 50 200
2 100 300
3 200 700
4 300 800
So if someone enters a mileage like 10, I want it to take the truckload rate of $200. If someone enters 250, the rate would then be 800. I'm not too hung up right now about what happens if a mileage is out of range. Just trying to figure out why the mechanics of something like this isn't working. It's my first time using records with a LOOP command so I'm trying to keep it straightforward with my program.
What could I be doing wrong? Thank you in advance and hope all has a great New Years!
Public Class Form1
Private Property EOF As Boolean
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'TODO: This line of code loads data into the '_test_2DataSet.test' table. You can move, or remove it, as needed.
Me.TestTableAdapter.Fill(Me._test_2DataSet.test)
End Sub
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Do Until EOF()
If Val(MilestoTextBox.Text) <= Val(Miles.Text) Then
rate.Text = TruckloadTextBox.Text
End If
Loop
End Sub
End Class
I neither know where you set the EOF variable nor do i understand its purpose. Have a look at following example which shows how to loop all rows of a DataTable(ORDER BY MILESTO ASC) to find the closest value greater than the given value:
Dim mileAge = Int32.Parse(Miles.Text)
Dim rate = 0
For Each row In _test_2DataSet.test
If mileAge <= row.MILESTO Then
rate = row.TRUCKLOADRATE
Exit For
End If
Next
If rate <> 0 Then
TxtRate.Text = rate.ToString
End If
If you cannot order by MILESTO initially or you simply want to see another approach that is not a database query, try this LINQ-To-DataSet approach:
rate = (From r In _test_2DataSet.test Order By r.MILESTO
Where mileAge <= r.MILESTO
Select r.TRUCKLOADRATE).FirstOrDefault
If you want to query the database, follwoing SQL returns the nearest TRUCKLOADRATE that is greater/equal than the #MileAge-parameter:
SELECT TOP (1) TRUCKLOADRATE
FROM Test
WHERE (MILESTO >= #MileAge)
ORDER BY MILESTO - #MileAge
Add a query to your DataAdapapter that returns a single value and has a meaningful name like getTruckloadRateByMileAge. Then it's that simple:
Dim loadRate = DirectCast(daTest.getTruckloadRateByMileAge(mileAge), Decimal)
Sorry for the delay in answering the question here and I want to thank everyone who answered, especially Tim.
In summary, Where a user wants to search through a dataset and compare a user-inputted value against some kind of index (in my case, if a mileage entered is less than or equal to some boundary value) and get the corresponding record that satisfies that criteria, the solution that works (thank you Tim!) is:
Dim mileAge = Int32.Parse(Miles.Text)
Dim rate = 0
For Each row In _test_2DataSet.test
If mileAge <= row.MILESTO Then
rate = row.TRUCKLOADRATE
Exit For
End If
Next
If rate <> 0 Then
TxtRate.Text = rate.ToString
End If
In the example, mileage is converted to a value that can be used to compare against a column in the dataset called MILESTO, which is a mile radius that corresponds to a price for transporting goods called TRUCKLOADRATE. The program iterates through each row in the dataset until the condition that mileage <= row.MILESTO is satisfied.
My original thought was using a search until EOF and this method works better.
Thanks all and again my apologies for the delay in summing this up for other users.