Compare all rows of a particular column - vb.net

Private Shared Function ValidateDate(dataTable As DataTable) As Boolean
Dim Currentdate As Date = Date.Now()
Dim Rows As New List(Of String)
Dim result As Boolean = True
For Each Row As DataRow In dataTable.Rows
If Not Currentdate Is Then
Next
Return result
End Functionhere
I want to compare rows of datecolumn of DataTable with the current date and return whether or not it's matches the current date.

code:
Private Shared Function ValidateDate(dataTable As DataTable) As Boolean
Dim Currentdate As Date = Today
Dim result As Boolean = True
For Each row As DataRow In dataTable.Rows
If Not CDate(row.Item("ReportDate")) >= Currentdate Then
result = False
Exit For
End If
Next
Return result
End Function
Thank you for your responses .I used this method to validate date in every row of datecolumn

Maybe this could help (not tested but should work)...This approach gives you a list with the rows who matched your criteria
Dim Currentdate As Date = Today
Dim lst as New List(of DataRow)
For each row as DataRow in datatable.Rows
If CDate(row.Items(index or columname)) = currentdate Then
lst.Add(row)
Next
return lst
Notice you have time in date datatype, which will be 0:00:00 if you dont give it explicitly.
(Should be no Problem, if all valuesa are only dates "with default 0:00:00 time") If not you will **get only true if date & time are the same **!
So you should use Today instead of Date.Now().. Every time you call Date.Now() you get the actual date & actual time. With Today you get actual date and time = 0:00:00.

Related

Count days within overlapping date ranges in VB.NET

I have a large amount of date FROM and TO pairs, and I need to count all the days within them. But if two ranges are overlapping then the overlapping days should not be counted twice.
Here's the code that counts all days that I have:
Dim total_days_used = 0
For Each row As DataRow In MY_DATA.Tables(0).Rows
Dim total_days As Double = 0
Dim date_from = MY_FROM_DATE_FROM_DATA
Dim date_to = MY_TO_DATE_FROM_DATA
Dim span = date_to - date_from
total_days = span.TotalDays '=4
total_days_used += total_days
Next
I can't figure out an easy way to subtract the overlapping days though or even keep track of them. I guess that would be one way to go, the other would be to combine overlapping ranges until I end up with a set of ranges where there are no overlaps but that seems way too complicated as well. There should be a simple way to do this?
Something like this should work.
We first order the ranges to know if the last overlaps the current.
And then count the overlapping days and substract that from the total.
+1 days if you want the range to be inclusive otherwise remove that.
Private Sub Main()
Dim ranges = New List(Of Range)() From { _
{New Range(New DateTime(2000, 1, 1), New DateTime(2000, 1, 30))}, _
{New Range(New DateTime(2000, 1, 28), New DateTime(2000, 2, 3))} _
}
CountNonOverlappingsDays(ranges).Dump() '34 days
End Sub
Private Function CountNonOverlappingsDays(ranges As IEnumerable(Of Range)) As Integer
Dim isFirst = True
Dim last As Range = Nothing
Dim overlapping As Integer = 0
Dim total As Integer = 0
For Each current In ranges.OrderBy(Function(r) r.[To])
total += CInt((current.[To] - current.From).TotalDays) + 1 '+1 if we want Inclusive count
If isFirst Then
isFirst = False
last = current
Continue For
End If
If (last.From <= current.[To]) AndAlso (last.[To] >= current.From) Then
Dim start = current.From
Dim [end] = last.[To]
overlapping += CInt(([end] - start).TotalDays) + 1 '+1 if we want Inclusive count
End If
last = current
Next
Return total - overlapping
End Function
Public Class Range
Public Sub New([from] As DateTime, [to] As DateTime)
[From] = [from]
[To] = [to]
End Sub
Public Property [From]() As DateTime
Get
Return m_From
End Get
Set
m_From = Value
End Set
End Property
Private m_From As DateTime
Public Property [To]() As DateTime
Get
Return m_To
End Get
Set
m_To = Value
End Set
End Property
Private m_To As DateTime
End Class
Use the following (or similar DateRange class).
Class DateRange
Implements IEnumerable(Of DateTime)
Public Sub New(startDate As DateTime, endDate As DateTime)
me.StartDate = startDate
me.EndDate = endDate
End Sub
Public ReadOnly Property StartDate() As DateTime
Public ReadOnly Property EndDate() As DateTime
Public Function GetEnumerator() As IEnumerator(Of DateTime) Implements IEnumerable(of DateTime).GetEnumerator
Return Enumerable.Range(0, 1 + EndDate.Subtract(StartDate).Days).[Select](Function(offset) StartDate.AddDays(offset)).GetEnumerator()
End Function
Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
Return GetEnumerator()
End Function
End Class
The important part of this class is that it is enumerable. That is, it returns the sequence of dates between the start and end dates (inclusive), when used in a for each loop (among other things).
Then you can use code like this to get what you want:
Dim ranges = New List(Of DateRange)()
ranges.Add(New DateRange(#2017/1/1#,#2017/1/10#))
ranges.Add(New DateRange(#2017/1/8#,#2017/1/20#))
Dim merged = ranges.SelectMany(Function(r) r.AsEnumerable()).Distinct().OrderBy(Function(dt) dt)
Console.WriteLine($"{merged.Count()} days: ")
For Each [date] As DateTime In merged
Console.WriteLine([date].ToShortDateString())
Next
Console.ReadLine()
This uses the LINQ SelectMany function to flatten the lists of dates (created by the IEnuemrable DateRange) from all the DateRange instances in the list to a single list of DateTime. It then gets the distinct (unique) values, and sorts the list.
The output shows output from a list containing 2 DateRange instances. The first is from Jan 1, 2017 to Jan 10, 2017, the second from Jan 8, 2017 to Jan 20, 2017. These ranges overlap on the 8th, 9th, and 10th. As you can see, those overlapped dates are only included once.
The following output is produced:
20 days:
1/1/2017
1/2/2017
1/3/2017
1/4/2017
1/5/2017
1/6/2017
1/7/2017
1/8/2017
1/9/2017
1/10/2017
1/11/2017
1/12/2017
1/13/2017
1/14/2017
1/15/2017
1/16/2017
1/17/2017
1/18/2017
1/19/2017
1/20/2017
Try this:
Dim range As New List(Of DateTime)()
For Each row As DataRow In MY_DATA.Tables(0).Rows
Dim date_from = MY_FROM_DATE_FROM_DATA
Dim date_to = MY_TO_DATE_FROM_DATA
range.AddRange(Enumerable.Range(0, (date_from-date_to).TotalDays).Select(d => date_from.AddDays(d))
Next
Dim total_days_used As Integer = range.Distinct().Count()
The magic is in two parts. The first part uses Enumerable.Range() to actually project all of the dates in each range, so we can add them to a list. The second part then just takes the distinct members of that list and counts them.

Strange Date Parsing Results

I am trying to make a small helper app to assist in reading SCCM logs. Parsing the dates has been pretty straightforward until I get to the timezone offset. It is usually in the form of "+???". literal example: "11-01-2016 11:44:25.630+480"
DateTime.parse() handles this well most of the time. But occasionally I run into a time stamp that throws an exception. I cannot figure out why. This is where I need help. See example code below:
Dim dateA As DateTime = Nothing
Dim dateB As DateTime = Nothing
Dim dateStr_A As String = "11-07-2016 16:43:51.541+600"
Dim dateStr_B As String = "11-01-2016 11:44:25.630+480"
dateA = DateTime.Parse(dateStr_A)
dateB = DateTime.Parse(dateStr_B)
MsgBox(dateA.ToString & vbCrLf & dateB.ToString)
IF run it would seem dateStr_B is an invalid time stamp? Why is this? I've tried to figure out how to handle the +480 using the 'zzz' using .ParseExact() format as shown here Date Formatting MSDN
Am I missing something with the timezone offset? I've searched high and low but these SCCM logs seem to use a non standard way of representing the offset. Any insight would be greatly appreciated
The problem is that +480 is indeed an invalid offset. The format of the offset from UTC (as produced when using the "zzz" Custom Format Specifier) is hours and minutes. +600 is 6 hours and 0 minutes ahead of UTC, which is valid. +480 would be 4 hours and 80 minutes ahead of UTC, which is invalid as the number of minutes can't be more than 59.
If you have some external source of date and time strings that uses an offset that is simply a number of minutes (i.e. +600 means 10 hours and +480 means 8 hours), you will need to adjust the offset before using DateTime.Parse or DateTime.ParseExact.
[Edit]
The following function takes a timestamp with a positive or negative offset (of any number of digits) in minutes, and returns a DateTime. It throws an ArgumentException if the timestamp is not in a valid format.
Public Function DateTimeFromSCCM(ByVal ts As String) As DateTime
Dim pos As Integer = ts.LastIndexOfAny({"+"c, "-"c})
If pos < 0 Then Throw New ArgumentException("Timestamp must contain a timezone offset", "ts")
Dim offset As Integer
If Not Integer.TryParse(ts.Substring(pos + 1), offset) Then
Throw New ArgumentException("Timezone offset is not numeric", "ts")
End If
Dim hours As Integer = offset \ 60
Dim minutes As Integer = offset Mod 60
Dim timestamp As String = ts.Substring(0, pos + 1) & hours.ToString & minutes.ToString("00")
Dim result As DateTime
If Not DateTime.TryParse(timestamp, result) Then
Throw New ArgumentException("Invalid timestamp", "ts")
End If
Return result
End Function
Thank you for the insight. I had a feeling I would need to handle this manually. I just wanted to make sure I wasn't missing something simple in the process. My knowledge of the date and time formatting is a bit lacking.
As such, I have altered my code so that it handles the offset. Granted I will have to add some more input validation in the final product.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim dateA As DateTime = Nothing
Dim dateB As DateTime = Nothing
Dim dateStr_A As String = correctOffset("11-07-2016 16:43:51.541+600")
Dim dateStr_B As String = correctOffset("11-07-2016 16:43:51.541+480")
dateA = DateTime.Parse(dateStr_A)
dateB = DateTime.Parse(dateStr_B)
MsgBox(dateA.ToString & vbCrLf & dateB.ToString)
End Sub
Public Function correctOffset(ByVal ts As String)
Dim offset As Integer = CInt(ts.Substring(ts.Length - 3))
Dim offHour As Integer = offset / 60
Dim offMin As Integer = offset - (offHour * 60)
Dim strhour As String = Nothing
Dim strmin As String = Nothing
If offHour <= 9 Then
strhour = "0" & CStr(offHour)
Else
strhour = CStr(offHour)
End If
If offMin <= 9 Then
strmin = "0" & CStr(offMin)
Else
strmin = CStr(offMin)
End If
Return ts.Substring(0, ts.Length - 3) & strhour & ":" & strmin
End Function

Find consecutive date range which a specific date falls within

Given a list of date ranges...We'll call empTimeOffPeriods
6/2/2016, 6/3/2016, 6/4/2016
6/8/2016, 6/9/2016, 6/10/2016, 6/11/2016
I need to find which consecutive date range a specific date (empRequestedOffDate) falls within
So,
6/4/2016 would fall withing the 6/2/2016-6/4/2016 Range
6/9/2016 would fall withing the 6/8/2016-6/11/2016 Range...etc.
my empTimeOffPeriodsis already sorted.
I'm doing this in VB.net
'Find all approved future events for team employee
empPtoDates = EventsManager.GetEventPaidTimeOffList(empDTO.UserId).FindAll(Function(x) x.EventDate >= DateTime.Today And x.Status = 1)
empOverLappingDates = empPtoDates.**'NOT SURE WHAT TO DO HERE**
'Build "EventType: (PeriodStart-PeriodEnd)"
If empPtoDates.Count > 0 Then
stbEventRanges.Append(empEvent).Append(": ")
stbEventRanges.Append(empOverLappingDates.First.EventDate.ToShortDateString()).Append("-")
stbEventRanges.Append(empOverLappingDates.Last.EventDate.ToShortDateString())
End If
So, here's my solution
Public Function FindDateRanges(ByRef listOfDates As List(Of DateTime)) As List(Of DefinedDateRange)
'Find approved date ranges
Dim DateRange = New DefinedDateRange(Nothing)
Dim DefDateRanges As New List(Of DefinedDateRange)
If listOfDates.Count > 0 Then
DateRange = New DefinedDateRange(listOfDates(0), listOfDates(0)) 'First start/end date
If listOfDates.Count > 1 Then 'Only one time off date in list
For index As Integer = 1 To listOfDates.Count - 1
If listOfDates(index) = listOfDates(index - 1).AddDays(1) Then
DateRange.dtEnd = listOfDates(index)
Else
DefDateRanges.Add(DateRange)
DateRange = New DefinedDateRange(listOfDates(index), listOfDates(index)) 'Next Start/end date
End If
Next
DefDateRanges.Add(DateRange)
Else
DefDateRanges.Add(DateRange)
End If
End If
Return DefDateRanges
End Function
Class DefinedDateRange
Public dtStart As DateTime, dtEnd As DateTime
Public Sub New(dateStart As DateTime, Optional dateEnd As DateTime = Nothing)
Me.dtStart = dateStart
Me.dtEnd = dateEnd
End Sub
End Class

get the sorted date in vb

i am writing simple program to get the sorted date . But it does not work.
Dim filepath As String = FileStr
Dim directoryPath As String = System.IO.Path.GetDirectoryName(filepath)
for Each file As String In System.IO.Directory.GetFiles(directoryPath)
Dates = {
Date.Parse(System.IO.Path.GetFileNameWithoutExtension(file))
}.ToList
Next
Dates.Sort()
ComboBox1.DataSource = Dates
It only show one date ..where there are more than 10 date. and also the loop is working
I declare the List as global
You're replacing the content of your list in every loop
Dim filepath As String = FileStr
Dim directoryPath As String = System.IO.Path.GetDirectoryName(filepath)
for Each file As String In System.IO.Directory.GetFiles(directoryPath)
Dates.Add(Date.Parse(System.IO.Path.GetFileNameWithoutExtension(file)))
Next
Dates.Sort(AddressOf SortDate)
ComboBox1.DataSource = Dates
UPDATE: Sorting issue
Then as a seperate function add:
Function SortDate(ByVal a As DateTime, ByVal b As DateTime)
Dim result As Integer = a.Year.CompareTo(b.Year)
If result = 0 Then
a.Month.CompareTo(b.Month)
If result = 0 Then
a.Day.CompareTo(b.Day)
End If
End If
Return result
End Function
Your loop replaced the value of Dates each time, so you get only one date.
Change the loop like this:
Dates = System.IO.Directory.GetFiles(directoryPath)
.Select(Function(file) Date.Parse(System.IO.Path.GetFileNameWithoutExtension(file)))
.ToList

How can i change color of particular row in datagridview, where a cell value is first timestamp of each day?

I have a datagridview filled with series of reports ordered in date and time for about an year
List is like below
27/1/2015 10:56:32 AM
27/1/2015 11:56:41 AM
27/1/2015 12:54:42 PM
28/1/2015 8:54:54 AM
28/1/2015 9:02:39 PM
29/1/2015 11:02:47 AM
29/1/2015 9:03:00 PM
30/1/2015 9:03:00 PM
How can I highlight or change color of that particular row, where each new day series begins? i mean highlighting row
where new day begins, 27, 28th etccc. So far i am trying like this
Private Sub myFindRow()
Dim sTime As DateTime = Me.myDataset.myReportTable.Compute("Max(reporttime)", "")
Dim eTime As DateTime = Me.myDataset.myReportTable.Compute("Min(reporttime)", "")
Dim cTime As DateTime = sTime
For Each Day As DateTime In Enumerable.Range(0, (eTime - sTime).Days).Select(Function(i) sTime.AddDays(i))
changeRowColor()
Next Day
End Sub
Private Sub changeRowColor()
For Each myRow As DataGridViewRow In Me.myDatagridView.Rows
Dim myTime As DateTime
myTime = myRow.Cells(2).Value
Next
End Sub
but not getting any idea to proceed futher. any guidence?
I don't think you need to compute anything. I would change the color of the first row then I would loop all rows and compare the date with the previous row. If the day are different then I would change the row color.
Something like this
Private Sub myFindRow()
' Change the color of the first row
For rowIndex As Integer = 1 To Me.myDatagridView.Rows.Count-1
Dim curRow As DataGridViewRow = Me.myDatagridView.Rows(i)
Dim prevRow As DataGridViewRow = Me.myDatagridView.Rows(i-1)
If CType(curRow.Cells(2).Value, DateTime).Date <> CType(prevRow.Cells(2).Value).Date Then
' Change the color of row curRow
End If
Next
End Sub