Difference time between two string not time of day in vba - vba

I don't find a solution for this problem, I have two string with this format :
string1 = "23:19:03" (hh:mm:ss)
string2 = "27:08:03" (hh:mm:ss)
I'll need calculate time difference between this two string like
string1 = "23:19:03"
string2 = "27:08:03"
diff = 3:49:00 (h:m:s)
UPDATE
I found a solution :
fell free to use my code with mention me, thanks
Public Function timediff(ByVal time1 As String, ByVal time2 As String) As String
'Author: © Copyright 2017 Audisio Francesco **************************
'Description: Time diffence betweem two string no time of day!!,the format of this two string is ([h]:mm:ss) like excel function
' time2 must be greater than time1
Dim ore1, ore2, min1, min2, sec1, sec2, tot1, tot2, tot, ore, apsec, min, sec As Double
Dim aladin1() As String
Dim aladin2() As String
'Dim time1, time2 As String
'genero secondi totali
aladin1 = Split(time1, ":")
ore1 = Val(aladin1(0)) 'Ore
ore1 = ore1 * 3600
min1 = Val(aladin1(1)) 'minuti
min1 = min1 * 60
sec1 = Val(aladin1(2)) 'secondi
sec1 = sec1
aladin2 = Split(time2, ":")
ore2 = Val(aladin2(0)) 'Ore
ore2 = ore2 * 3600
min2 = Val(aladin2(1)) 'minuti
min2 = min2 * 60
sec2 = Val(aladin2(2)) 'secondi
sec2 = sec2
'prendo i totali
tot1 = ore1 + min1 + sec1
tot2 = ore2 + min2 + sec2
tot = tot2 - tot1
ore = Int(tot / 3600)
apsec = tot - (3600 * ore)
min = Int(apsec / 60)
sec = apsec - (min * 60)
result = (ore & ":" & min & ":" & sec)
timediff = result
End Function
Use:
string1 = "23:19:03"
string2 = "27:08:03"
ore1 = timediff(time1, time2)
ore1 = 3:49:0

you could use this helper function
Function GetDiffTime(string1 As String, string2 As String) As String
GetDiffTime = GetTime(GetSeconds(string2) - GetSeconds(string1))
End Function
which, on its turn, uses the following functions:
Function GetTime(seconds As Long) As String
Dim rest As Long
rest = seconds \ 3600
GetTime = GetTime & Format(rest, "00")
seconds = seconds - rest * 3600
rest = seconds \ 60
GetTime = GetTime & ":" & Format(rest, "00")
seconds = seconds - rest * 60
GetTime = GetTime & ":" & Format(seconds, "00")
End Function
Function GetSeconds(strng As String) As Long
Dim timeParts As Variant
Dim iPart As Integer
timeParts = Split(strng, ":")
For iPart = UBound(timeParts) To LBound(timeParts) Step -1
GetSeconds = GetSeconds + CInt(timeParts(iPart)) * 60 ^ (UBound(timeParts) - iPart)
Next
End Function

Related

NaN result when converting Bytes To Megabytes

how can I fix my method of converting Bytes To Megabytes not to get as a Result NaN.
This is my method:
Public Function BytesToMegabytes(bytes As Long) As String
Dim dblAns As Double = (bytes / 1024) / 1024
If dblAns = 0 Then
Return "0"
End If
Dim significantFigures = 4
Dim magnitude = Math.Floor(Math.Log10(dblAns)) 'In this Line I get the NaN
Dim v As Double = 10 ^ (magnitude - significantFigures + 1)
dblAns = Math.Floor(dblAns / v) * v
Dim ci = New CultureInfo("")
ci.NumberFormat.NumberDecimalSeparator = ","
ci.NumberFormat.NumberGroupSeparator = "'"
Return dblAns.ToString("#,##0.###", ci)
End Function
With Dim usedInklData = BytesToMegabytes(-3271356861) I get the correct result.
and with Dim usedInklData = BytesToMegabytes(-776150324) I get the NaN value.
Please suggest how I could correct this.
Thanks to everyone for their help.
How about you remember if your input is negative and flip the result if it is, after doing the calculation in positive numbers:
Public Function BytesToMegabytes(bytes As Long) As String
Dim isNeg = bytes < 0
If isNeg Then bytes *= -1
Dim dblAns As Double = (bytes / 1024) / 1024
If dblAns = 0 Then
Return "0"
End If
Dim significantFigures = 4
Dim magnitude = Math.Floor(Math.Log10(dblAns)) 'In this Line I get the NaN
Dim v As Double = 10 ^ (magnitude - significantFigures + 1)
dblAns = Math.Floor(dblAns / v) * v
Dim ci = New CultureInfo("")
ci.NumberFormat.NumberDecimalSeparator = ","
ci.NumberFormat.NumberGroupSeparator = "'"
If isNeg Then dblAns *= -1
Return dblAns.ToString("#,##0.###", ci)
End Function

Arithmetic operation resulted in an overflow - Vb.Net

Hi I am getting the following error when computing GMT Time using nanoseconds as a long.
System.OverflowException: 'Arithmetic operation resulted in an overflow.'
Is there another data type that would work better with big values?
Private Sub gmtime(ByVal iSeconds As Object, ByVal iNanoseconds As Long, ByRef Timestamp As String)
Dim time As Object
Dim islpyr, lpcnt As Long
Dim t As Object
Dim i As Object
Dim ystart As Long
Dim y As Long
Dim sph As Object 'seconds per hour
Dim spd As Object 'seconds per day
Dim spy As Object 'seconds per year
Dim tm_sec As Long
Dim tm_min As Long
Dim tm_hour As Long
Dim tm_mday As Long
Dim tm_mon As Long
Dim tm_year As Long
Dim tm_wday As Long
Dim tm_yday As Long
Dim tm_isdst As Long
Dim mons(11) As Long
Dim temp As Object
Dim iMicroSeconds As Long
Dim iZeroCount As Long
Dim strZero As String
Dim strMicro As String
Dim iMicroData As Long
mons(0) = 31
mons(1) = 28
mons(2) = 31
mons(3) = 30
mons(4) = 31
mons(5) = 30
mons(6) = 31
mons(7) = 31
mons(8) = 30
mons(9) = 31
mons(10) = 30
mons(11) = 31
sph = CDec(60 * 60)
spd = CDec(24 * sph)
spy = CDec(365 * spd + 6 * sph) 'a year is about 365.25 days
tm_isdst = 0
time = CDec(iSeconds)
If time < 0 Then
time = time * (-1)
End If
i = CDec(time)
i = Fix(i / spd) Mod 7 + 4
While i >= 7
i = i - 7
End While
tm_wday = i
temp = Fix(time / spd)
temp = temp * spd
i = time - temp
tm_hour = Fix(i / sph) Mod 24
tm_min = Fix(i / 60) Mod 60
tm_sec = i Mod 60
y = Fix(time / spy)
y = y + 370
time = Fix(time / spd)
Do
islpyr = 0
If ((y Mod 4) = 0) And (((y Mod 100) <> 0) Or ((y Mod 400) = 0)) Then
islpyr = 1
End If
lpcnt = Fix(y / 4)
lpcnt = lpcnt - Fix(y / 100)
lpcnt = lpcnt + Fix(y / 400)
lpcnt = lpcnt - 89
ystart = (y - 370) * 365 + lpcnt
If ystart > time Then
y = y - 1
End If
Loop While ystart > time
time = time - ystart
If time = 365 Then
time = 0
y = y + 1
End If
If islpyr Then
time = time + 1
End If
tm_yday = time
time = time + 1
For i = 0 To 10
t = mons(i)
If (i = 1) And (islpyr = 1) Then
t = t + 1
End If
If time <= t Then
Exit For
End If
time = time - t
Next i
tm_year = y - 300 + 1900
tm_mon = i + 1
tm_mday = time
strZero = "."
iZeroCount = 6
iMicroSeconds = Fix(iNanoseconds / 1000)
iMicroData = iMicroSeconds
While iMicroSeconds <> 0
iMicroSeconds = Fix(iMicroSeconds / 10)
If (iMicroData Mod 10) = 0 Then
iMicroData = iMicroSeconds
End If
If iZeroCount <> 0 Then
iZeroCount = iZeroCount - 1
End If
End While
For i = 1 To iZeroCount
strZero = strZero + "0"
Next i
If Fix(iNanoseconds / 1000) <> 0 Then
strMicro = strZero + CStr(Fix(iNanoseconds / 1000))
Else
strMicro = strZero
End If
Timestamp = CStr(tm_year) + "-" + CStr(tm_mon) + "-" + CStr(tm_mday) + " " + CStr(tm_hour) + ":" + CStr(tm_min) + ":" + CStr(tm_sec) + strMicro
End Sub
It wouldn't let me add the code as the post is mostly code. The nanoseconds values are coming from a waveform file and this function is used to process it into GMT time.
The function is called on a loop for each line of the file and returns this error mid-way through the loop.
The value is '1.5518651852110167E+270' when it hits the error
I'm sorry but there's no way to put a 10^270 number inside ANY variable.
The biggest variable for numbers is Long that holds:
signed 64-bit (8-byte) integers ranging in value from
-9,223,372,036,854,775,808 through 9,223,372,036,854,775,807
(9.2...E+18).
From Long DataType
I sueggest you to avoiding counting time in nanoseconds instead use seconds, minutes, or even days if your TimeSpan is too big.
Counting time in nanoseconds is pointless.
Remarks
If you couldn't avoid using nanoseconds because your file is in nanoseconds your only option is to convert you nanoseconds value in a DateTime format on every line and hope that the value will be shorter than 9.2E+18
Otherwise you could use a BigInteger and use it to calculate a DateTime for every line of your file.
Just for the curiosity: You would need a 896 bytes unsigned DataType to store a 1.5*10^270 inside it.

How to calculate difference between 2 dates when it goes to past? VBA, EXCEL

I have a problem with calculating difference between 2 dates where first is older than second.
For example: I want to find difference between
5.5.2015 and 1.11.2014
I used function
=IF((A(DATEDIF(B12,$W$3,"M")<=12,RANK(Q12,Q:Q)<=11)),Q12;0)
but the function is limited only to situations where the second date is higher than the first one.
I want to know whether B12 is within last 12 months from given date. If it is, then I want to calculate with it.
Is there any way to calculate backwards in excel or VBA?
Thank you.
I know this is an old post already but for anyone who needs this...
Function FindDateDiff(myDate1 As Date, myDate2 As Date) As String
Dim myYears As Long, myMonths As Long, myDays As Long
Dim yearString As String, monthString As String, dayString As String, FinalString As String
If myDate1 > myDate2 Then
myYears = Year(myDate1) - Year(myDate2)
myMonths = Month(myDate1) - Month(myDate2)
myDays = Day(myDate1) - Day(myDate2)
If myDays < 0 Then
myMonths = myMonths - 1
myDays = Day(WorksheetFunction.EoMonth(myDate1, 0)) - Abs(myDays) - 1
End If
Else
myYears = Year(myDate2) - Year(myDate1)
myMonths = Month(myDate2) - Month(myDate1)
myDays = Day(myDate2) - Day(myDate1)
If myDays < 0 Then
myMonths = myMonths - 1
myDays = Day(WorksheetFunction.EoMonth(myDate2, 0)) - Abs(myDays) - 1
End If
End If
If myMonths < 0 Then
myYears = myYears - 1
myMonths = 12 - Abs(myMonths)
End If
If myYears = 0 Then
yearString = ""
ElseIf myYears = 1 Then
yearString = myYears & " year, "
ElseIf myYears > 1 Then
yearString = myYears & " years, "
End If
If myMonths = 0 Then
monthString = ""
ElseIf myMonths = 1 Then
monthString = myMonths & " month, "
ElseIf myMonths > 1 Then
monthString = myMonths & " months, "
End If
If myDays = 0 Then
dayString = ""
ElseIf myDays = 1 Then
dayString = myDays & " day"
ElseIf myDays > 1 Then
dayString = myDays & " days"
End If
FinalString = yearString & monthString & dayString
If Right(FinalString, 2) = ", " Then FinalString = Left(FinalString, Len(FinalString) - 2)
FindDateDiff= FinalString
End Function
Just paste this function in a new module in the workbook and you can start calling this function. '=FindDateDiff(A1,B1)'
This function only require 2 dates as arguments and the order doesn't matter.
I've tested this function with both UK and US format, both works exactly the same.
I used DateDiff before, but the calculation for days and months returns an incorrect value and could be very confuse sometimes.
In VBA use the same function.
NoOfDays = DateDiff("D", DATE1, DATE2)
NoOfDays returns either positive or negative value depending on the dates
I have it solved by using ISERROR
=IF(ISERROR(DATEDIF(RC[-16],R3C23,""M"")<=12),0,RC[-1])

Time Calculation in Excel VBA

I am getting time as 23300000 i.e. hhMMssmm format as string
and I want to calculate difference of such two values.
Here hh is hours, MM is minutes, ss is seconds, and mm is 60th of second.
Using VBA for Excel 2003
This UDF will return the absolute value of the difference in seconds
Public Function tDiff(s1 As String, s2 As String) As Double
'
' calculates the absolute value of the differences
' returns the answer in seconds
'
Dim hrs As Double, mins As Double, secs As Double, sixt As Double
Dim tVal1 As Double, tVal2 As Double
hrs = CDbl(Mid(s1, 1, 2)) * 60 * 60
mins = CDbl(Mid(s1, 3, 2)) * 60
secs = CDbl(Mid(s1, 5, 2))
sixt = CDbl(Mid(s1, 7, 2)) / 60
tVal1 = hrs + mins + secs + sixt
hrs = CDbl(Mid(s2, 1, 2)) * 60 * 60
mins = CDbl(Mid(s2, 3, 2)) * 60
secs = CDbl(Mid(s2, 5, 2))
sixt = CDbl(Mid(s2, 7, 2)) / 60
tVal2 = hrs + mins + secs + sixt
If tVal1 > tVal2 Then
tDiff = tVal1 - tVal2
Else
tDiff = tVal2 - tVal1
End If
End Function
How about something like this:
Public Sub test()
Dim ms1 As Double
Dim ms2 As Double
ms1 = ToSeconds(23142700)
ms2 = ToSeconds(23311500)
Debug.Print "Difference between dates in seconds: " & ms2 - ms1
End Sub
Public Function ToSeconds(number As Long) As Double
Dim hh As Long
Dim mm As Long
Dim ss As Long
Dim ms As Long
ms = (number Mod (100 ^ 1)) / (100 ^ 0)
ss = (number Mod (100 ^ 2) - ms) / (100 ^ 1)
mm = (number Mod (100 ^ 3) - ss * (100 ^ 1) - ms) / (100 ^ 2)
hh = (number Mod (100 ^ 4) - mm * (100 ^ 2) - ss * (100 ^ 1) - ms) / (100 ^ 3)
ToSeconds = ms * 1 / 60 + ss + mm * 60 + hh * 60 * 60
End Function
The ToSeconds() function converts your number to seconds, and you can do your calculations based on that.
While this solution may not be as short as the others, I believe it is very easy to understand. Not everything here may be necessary, but you may find some of it useful in the future.
The run sub routine allows you to run the test function with your specified values.
The test function tests the timeDiff & timeSum logic.
The timeDiff function finds the time-difference between t1 and t0.
The timeSum function finds the time-sum of t1 and t0.
The asDuration function removes the AM/PM suffix from a time value.
The asMilitary function converts 12-hour format to 24 hour-format.
The concat function I created to more easily concatenate strings.
Sub Main() 'Run Test
MsgBox Test("0:29:0", "23:30:0")
End Sub
Function Test(startT As Date, endT As Date) 'Test timeDiff & timeSum logic
Dim nextShift As Date, prevShift As Date, hours As Date
hours = timeDiff(endT, startT)
prevShift = timeDiff(startT, "0:30:0")
nextShift = timeSum("0:30:0", endT)
Test = concat("Start -", startT, "", "End - ", endT, "", "Duration -", asDuration(hours), "", "Next Shift: ", nextShift, "", "Prev Shift: ", prevShift)
End Function
Function timeDiff(t1 As Date, t0 As Date) As Date 'Return Time1 minus Time0
Dim units(0 To 2) As String
units(0) = Hour(t1) - Hour(t0)
units(1) = Minute(t1) - Minute(t0)
units(2) = Second(t1) - Second(t0)
If units(2) < 0 Then
units(2) = units(2) + 60
units(1) = units(1) - 1
End If
If units(1) < 0 Then
units(1) = units(1) + 60
units(0) = units(0) - 1
End If
units(0) = IIf(units(0) < 0, units(0) + 24, units(0))
timeDiff = Join(units, ":")
End Function
Function timeSum(t1 As Date, t0 As Date) As Date 'Return Time1 plus Time0
Dim units(0 To 2) As String
units(0) = Hour(t1) + Hour(t0)
units(1) = Minute(t1) + Minute(t0)
units(2) = Second(t1) + Second(t0)
If units(2) >= 60 Then
units(2) = units(2) Mod 60
units(1) = units(1) + 1
End If
If units(1) >= 60 Then
units(1) = units(1) Mod 60
units(0) = units(0) + 1
End If
units(0) = IIf(units(0) >= 24, units(0) Mod 24, units(0))
timeSum = Join(units, ":")
End Function
Function asDuration(time As Date) As String 'Display as duration; Remove AM/PM suffix from time
time = asMilitary(time)
asDuration = Left(time, Len(time))
End Function
Function asMilitary(time As Date) As String 'Convert 12-hour format to 24-hour-format
asMilitary = Hour(time) & ":" & Minute(time) & ":" & Second(time)
End Function
Function concat(ParamArray var() As Variant) As String 'Return arguments of function call concatenated as a single string
For Each elem In var()
concat = IIf(elem <> "", concat & elem & " ", concat & vbNewLine)
Next
End Function

Normal Distributed Random Number in VB.NET

Is there anybody know how to make normal distributed random number in vb.net?
thank you
From this forum post :
Usage:
GaussNumDist(Mean, Standard Deviation, Sample Size)
Code example below, which will populate GaussNumArray() with the sample of numbers, whose distribution will have the mean and standard deviation specified:
Imports System.Math
Module Module1
Friend GaussNumArray() As Double
Friend intICell As Long
Friend Function GaussNumDist(ByVal Mean As Double, ByVal StdDev As Double, ByVal SampleSize As Integer)
intICell = 1 'Loop variable
ReDim GaussNumArray(SampleSize)
Do While (intICell < (SampleSize + 1))
Call NumDist(Mean, StdDev)
Application.DoEvents()
Loop
End Function
Sub NumDist(ByVal meanin As Double, ByVal sdin As Double)
'---------------------------------------------------------------------------------
'Converts uniform random numbers over the region 0 to 1 into Gaussian distributed
'random numbers using Box-Muller algorithm.
'Adapted from Numerical Recipes in C
'---------------------------------------------------------------------------------
'Defining variables
Dim dblR1 As Double
Dim dblR2 As Double
Dim mean As Double
Dim var As Double
Dim circ As Double
Dim trans As Double
Dim dblY1 As Double
Dim dblY2 As Double
Dim Pi As Double
Pi = 4 * Atan(1)
'Get two random numbers
dblR1 = (2 * UniformRandomNumber()) - 1
dblR2 = (2 * UniformRandomNumber()) - 1
circ = (dblR1 ^ 2) + (dblR2 ^ 2) 'Radius of circle
If circ >= 1 Then 'If outside unit circle, then reject number
Call NumDist(meanin, sdin)
Exit Sub
End If
'Transform to Gaussian
trans = Sqrt(-2 * Log(circ) / circ)
dblY1 = (trans * dblR1 * sdin) + meanin
dblY2 = (trans * dblR2 * sdin) + meanin
GaussNumArray(intICell) = dblY1 'First number
'Increase intICell for next random number
intICell = (intICell + 1)
GaussNumArray(intICell) = dblY2 'Second number
'Increase intICell again ready for next call of ConvertNumberDistribution
intICell = (intICell + 1)
End Sub
Friend Function UniformRandomNumber() As Double
'-----------------------------------------------------------------------------------
'Outputs random numbers with a period of > 2x10^18 in the range 0 to 1 (exclusive)
'Implements a L'Ecuyer generator with Bays-Durham shuffle
'Adapted from Numerical Recipes in C
'-----------------------------------------------------------------------------------
'Defining constants
Const IM1 As Double = 2147483563
Const IM2 As Double = 2147483399
Const AM As Double = (1.0# / IM1)
Const IMM1 As Double = (IM1 - 1.0#)
Const IA1 As Double = 40014
Const IA2 As Double = 40692
Const IQ1 As Double = 53668
Const IQ2 As Double = 52774
Const IR1 As Double = 12211
Const IR2 As Double = 3791
Const NTAB As Double = 32
Const NDIV As Double = (1.0# + IM1 / NTAB)
Const ESP As Double = 0.00000012
Const RNMX As Double = (1.0# - ESP)
Dim iCell As Integer
Dim idum As Double
Dim j As Integer
Dim k As Long
Dim temp As Double
Static idum2 As Long
Static iy As Long
Static iv(NTAB) As Long
idum2 = 123456789
iy = 0
'Seed value required is a negative integer (idum)
Randomize()
idum = (-Rnd() * 1000)
'For loop to generate a sequence of random numbers based on idum
For iCell = 1 To 10
'Initialize generator
If (idum <= 0) Then
'Prevent idum = 0
If (-(idum) < 1) Then
idum = 1
Else
idum = -(idum)
End If
idum2 = idum
For j = (NTAB + 7) To 0
k = ((idum) / IQ1)
idum = ((IA1 * (idum - (k * IQ1))) - (k * IR1))
If (idum < 0) Then
idum = (idum + IM1)
End If
If (j < NTAB) Then
iv(j) = idum
End If
Next j
iy = iv(0)
End If
'Start here when not initializing
k = (idum / IQ1)
idum = ((IA1 * (idum - (k * IQ1))) - (k * IR1))
If (idum < 0) Then
idum = (idum + IM1)
End If
k = (idum2 / IQ2)
idum2 = ((IA2 * (idum2 - (k * IQ2))) - (k * IR2))
If (idum2 < 0) Then
idum2 = idum2 + IM2
End If
j = (iy / NDIV)
iy = (iv(j) - idum2)
iv(j) = idum
If (iy < 1) Then
iy = (iy + IMM1)
End If
temp = AM * iy
If (temp <= RNMX) Then
'Return the value of the random number
UniformRandomNumber = temp
End If
Next iCell
End Function
End Module
You can use following line
Dim x1 as Double = MathNet.Numerics.Distributions.Normal.Sample(MEAN, STDEV)
Math.Net Numeric package can be installed using following NuGet command
Install-Package MathNet.Numerics -Version 4.9.0
You can found more information on NuGet site