How to get the difference between 2 times in SSRS - sql

I want to get the difference between 2 columns that have a time datatype in SSRS
FormatDateTime(dateadd(DateInterval.Minute, datediff(DateInterval.Minute, Fields!TimeFrom.Value, Fields!TimeTo.Value), 0) ,"hh:mm")
I tried this but it didn't work and is there a way to sum it up ?

You can use a custom code for it. You can refer this article for more detail about it.
Using custome code in SSRS
The following custom code will be help to handle your issue
Public Function GetFormatedTime(byval dblSeconds as double) as String
Dim result as String
Dim Hours, Minutes, Seconds As Integer
Seconds = dblSeconds
Hours = Seconds / 3600
Seconds = Seconds Mod 3600
Minutes = Seconds / 60
Seconds = Seconds Mod 60
result=Hours.ToString.PadLeft(2, "0"c) & ":" & Minutes.ToString.PadLeft(2, "0"c) & ":" & Seconds.ToString.PadLeft(2, "0"c)
return result
End Function
This function takes second as parameter. For example ;
code.GetFormatedTime(3699)
expresion returns
01:02:09

Related

Extract two numbers from string using formula

I have formula to extract numbers from Google XML response, that can be:
9 часов 24 минут
10 h 0 min
9 h 20 min
11 h 13 min
10 Std 55 min
9 timmar 5 min
19 min
Here is current formula (value is in BZ1):
=IFERROR(IF(VALUE(IF(FIND("min";BZ1;1)=11;MID(BZ1;FIND("min";BZ1;1)-2;1);MID(BZ1;FIND("min";BZ1;1)-3;2)))<30; VALUE(LEFT(BZ1;FIND("h";BZ1;1)-2))&","&5;VALUE(LEFT(BZ1;FIND("h";BZ1;1)-2))+1);"")
Formula rounds hours and minutes to hours, for example
1 h 39 min -> 2
10 h 12 min -> 10,5
9 h 20 min -> 9,5
There is a problem that it is not able to take in consideration language changes for hours and min.
Is there any possibility to make it work so that it will:
If there is only number (case 19 min) -> extract number
If there are two numbers (case 1 h 39 min) -> extract first number as hours, then from last two spaces number as minutes
EDIT:
Check how many numbers in cell (target in CA25):
SUM(LEN(CA25)-LEN(SUBSTITUTE(CA25;{1;2;3;4;5;6;7;8;9};)))>1
If more than 1
LEFT(CA25;(FIND(" ";CA25;1)-1))&TRIM(MID(SUBSTITUTE(CA25;" ";REPT(" ";50));100;50))
If less than 1
LEFT(CA25;SUM(LEN(CA25)-LEN(SUBSTITUTE(CA25;{"0";"1";"2";"3";"4";"5";"6";"7";"8";"9"};""))))
All together
=IF(SUM(LEN(CA25)-LEN(SUBSTITUTE(CA25;{1;2;3;4;5;6;7;8;9};)))>1;LEFT(CA25;(FIND(" ";CA25;1)-1))&TRIM(MID(SUBSTITUTE(CA25;" ";REPT(" ";50));100;50));LEFT(CA25;SUM(LEN(CA25)-LEN(SUBSTITUTE(CA25;{"0";"1";"2";"3";"4";"5";"6";"7";"8";"9"};"")))))
This gives as output:
Now these need to be converted to hours and rounded up to one hour
EDIT 2:
Here is formula (target BZ1):
=IFERROR(IF(LEN(BZ1)-LEN(SUBSTITUTE(BZ1;" ";""))>2;LEFT(BZ1;(FIND(" ";BZ1;1)-1))+IF(TRIM(MID(SUBSTITUTE(BZ1;" ";REPT(" ";50));100;50))<60;1;1);IF(LEFT(BZ1;SUM(LEN(BZ1)-LEN(SUBSTITUTE(BZ1;{"0";"1";"2";"3";"4";"5";"6";"7";"8";"9"};""))))<60;1;1));"")
Here is a small user defined function:
Option Explicit
Public Function Tyme(inpt As String) As Double
Dim arr, U As Long
Tyme = 0
arr = Split(inpt, " ")
U = UBound(arr)
If U = 0 Then Exit Function
If U = 1 Then
Tyme = CDbl(arr(0))
Else
Tyme = CDbl(arr(0)) + CDbl(arr(2)) / 60#
End If
End Function
It:
is language-independent
returns an un-rounded floating point value (hours)
Some examples:
User Defined Functions (UDFs) are very easy to install and use:
ALT-F11 brings up the VBE window
ALT-I
ALT-M opens a fresh module
paste the stuff in and close the VBE window
If you save the workbook, the UDF will be saved with it.
If you are using a version of Excel later then 2003, you must save
the file as .xlsm rather than .xlsx
To remove the UDF:
bring up the VBE window as above
clear the code out
close the VBE window
To use the UDF from Excel:
=Tyme(A1)
To learn more about macros in general, see:
http://www.mvps.org/dmcritchie/excel/getstarted.htm
and
http://msdn.microsoft.com/en-us/library/ee814735(v=office.14).aspx
and for specifics on UDFs, see:
http://www.cpearson.com/excel/WritingFunctionsInVBA.aspx
Macros must be enabled for this to work!
NOTES:
rounding should be applied outside the udf
it would be easy to modify the udf to handle seconds as well
it would be easy to modify the udf to return true Excel time rather than floating point hours
May I suggest you use a VBA function? Seeing as in your examples there is always a space between the numbers and other characters, this should do it:
Public Function TimeInHoursRoundedUp(rng as Range)
Dim var As Variant: var = Split(rng, " ")
Dim item As Variant
Dim hour As Integer: hour = 0
For Each item In var
If IsNumeric(item) Then
If hour = 0 Then hour = hour + item Else hour = hour + 1
End If
Next item
TimeInHoursRoundedUp = hour
End Sub
Then in your excel sheet you could simply write =TimeInHoursRoundUp() and input the cell reference inside the brackets.

VBA generating a random unique alpha-numeric string

I need to create a Unique-ID (string) for each record as I am developing an application which allows users to access a unique URL like:
http://URL.com/BXD31F
The code below works to create the URLIDs:
Public Function getURLID(ID As Double) As String
Randomize
Dim rgch As String
rgch = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ"
Dim i As Long
For i = 1 To 5
getURLID = getURLID & Mid$(rgch, Int(Rnd() * Len(rgch) + 1), 1)
Next
End Function
How can I ensure that the URLID created is unique? Do I need to query the database to ensure it has not been generated before? The table has 5 million records. A dlookup query would exceed the limitations of my MSAccess database.
I have considered using the timestring to generate the URLID:
Format(Now, "yymmddhhmmss")
However, I only want a simple 5 character string.
How can I ensure that the URLID created is unique?
You can't. And it won't be. Look into cryptographically secure hashing algorithms... and even those are never "secure" forever. Note, hashing is something for which VBA has absolutely zero built-in support, but you can leverage .NET for that.
Another option could be to get the OS to generate Globally Unique IDentifiers (GUID); these would be unique, ...but much longer than a handful of characters.
Good luck!
Ensuring that a string is unique with VBA could be done somehow differently. E.g., take the date time, which is unique every second and give it:
format(now, "YYMMDDHHNS")
As far as it would be too obvious, consider changing it a bit. E.g., remove a random contant number from the datetime, let's say 181387 (as it is a prime number) and pass convert it to a hex. Then it would be quite ok:
Function UniqueString() As String
Const someNumber = 181387 'it is a prime number
UniqueString = Hex(Format(Now, "YYMMDDHHNS") - someNumber)
End Function
The above does not seem to work for 32-bit machines. Thus, you may consider splitting the parts of the date to separate numbers and hex-ing them separately:
Function UniqueString32() As String
Const primeNumber = 23
Application.Wait Now + #12:00:02 AM# 'waiting 2 seconds
UniqueString32 = Hex(Format(Now, "YY")) _
& Hex(Format(Now, "MM")) _
& Hex(Format(Now, "DD")) _
& Hex(Format(Now, "HH")) _
& Hex(Format(Now, "NS") - primeNumber)
End Function
Just make sure there is at least 1 second before calling the function, calling it in the same time zone. Plus, it is a good idea to think about the daylight saving time in advance. In general, it is not a great idea, there would be quite a lot of problems popping up, but for vba and ms-access it would be ok.
I managed to solve my own problem. We need to check to see if the URLID already exists in the table. The challenge is that the URLID is not written into the table until the query has completely executed. Using 6 of the possible 24 characters will give us about 191 million possibilities (24 to the power of 6). As we only need to create 5 million IDs, there is a small chance for duplicate records.
This is how I did it:
Step 1 - Generate Random a URLID for the 5 million rows using the original code
Step 2 - Identify duplicates and update to null using query below
UPDATE URLIDs SET URLIDs.URL = Null
WHERE (((URLIDs.URL) In (SELECT [URL] FROM [URLIDs] As Tmp GROUP BY [URL] HAVING
Count(*)>1 )));
Step 3 - Generate new URLID for the nulls identified in Step 2. This time, checking to see if they already exist in the table. See code below:
Public Function getURLID(roll As Double) As String
Randomize
Dim rgch As String
rgch = "ABCDEFGHJKLMNPQRSTUVWXYZ"
Dim i As Long
For i = 1 To 6
getURLID = getURLID & Mid$(rgch, Int(Rnd() * Len(rgch) + 1), 1)
Next
Do Until URLIDExists(getURLID) = False
getURLID = ""
For i = 1 To 6
getURLID = getURLID & Mid$(rgch, Int(Rnd() * Len(rgch) + 1), 1)
Next
Loop
End Function
Function below used to see if URL exists
Public Function URLIDExists(URLID As String) As Boolean
Dim RS1
Dim strQuery As String
strQuery = "SELECT * from [URLIDs] where [URL]='" & URLID & "'"
Set RS1 = CurrentDb.OpenRecordset(strQuery)
If RS1.RecordCount > 0 Then
URLIDExists = True
Else
URLIDExists = False
End If
Set RS1 = Nothing
End Function
I repeated steps 2 and 3 until there are were no more duplicates. Each time checking against the existence of the already confirmed URLID. Eventually there will be no more duplicate URLIDs.

How do I make my percentages have 2 decimal points?

I have looked at other posts about this but i just can't get my head around it and wanted to ask specifically for my scenario. I have written a Visual Basic console application and I am trying to get my percentages to have two decimal places on them as they're just rounding up to the nearest whole number. Here is the code :
Console.Write("Enter the percentage you want to work out: ")
Dim Percentage As Integer
Percentage = Console.ReadLine()
Console.Write("What would you like to work out " & Percentage & "% of? ")
Dim Number As Integer
Number = Console.ReadLine()
Dim PercentageNumberResult As Integer
PercentageNumberResult = Number / 100 * Percentage
Console.Write(Number & " ÷ 100 × " & Percentage & " = " & PercentageNumberResult)
Console.ReadLine()
Any help would be appreciated, thanks!
The problem is due to PercentageNumberResult being an integer.
Make PercentageNumberResult a double :
Dim PercentageNumberResult As Double
PercentageNumberResult = Number / 100 * Percentage
You could then use Math.Round if needed. Also you should turn on Option Strict this will help solving the problem.
If you want to convert a number to a String then you call ToString on that number. If you want a specific format then you pass the appropriate format specifier as an argument when calling ToString. You should read the relevant documentation to learn all the possible format specifiers.
In this case, you display a number as a percentage using the "p" or "P" specifier and you can add a number to specify the number of decimal places. e.g.
Dim x = 13
Dim y = 1000
Dim z = x / y
Dim s = z.ToString("P2")
After executing that code, s will contain "1.30%".
If you don't actually want the "%" symbol in the output then you can multiply by 100 and use a different format specifier, e.g.
Dim x = 13
Dim y = 1000
Dim z = 100 * x / y
Dim s = z.ToString("N2")
After executing that code, s will contain "1.30".

Summing up Hours and Minutes in MS Access - How to deal with huge datasets

So I have a Table in MS Access 2010 which looks like this:
Date Pers. ID Dauer Tätigkeit
10.04.2016 10 01:15
11.05.2016 5 05:00
...
I want to get the total hours of "Dauer Tätigkeit". All entries in the "Dauer Tätigkeit" are in the Date Format.
The formula below is supposed to do the job for listing the end in a Format like '1346:30'. It actually does the job for small datasets.
The dataset I have to work with though has around 800 entries with an hourly average of 3 hours. So i am expecting to get a number in the ballpark of around 2400 to 8000 hours, if i fill every line with 23:59 it should at the max give me a number under 20.000.
I get a number well south of 1 million.
The error dissapears when the total of Hours is smaller than roughly 500 (I tested this by halfing the number of entries twice, not further). So I think, I am having an overflow problem somewhere.
Question now is where. The obvious point where this could happen is the "Int" just at the beginning, but removing it from the formula doesn't solve it.
=Format(Int(Summe([Dauer Tätigkeit]))*24+Stunde(Summe([Dauer Tätigkeit]));"00")
& ":" & Format(Minute(Summe([Dauer Tätigkeit]));"00")
My questions now are:
Is there a syntax problem?
Is it an overflow problem?
Can a cast to LongInt solve it? If yes, how to implement it into the formula?
Am I asking the right questions?
Always handle dates as dates, not strings, not long, neither currency.
This function will do:
Public Function FormatHourMinute( _
ByVal datTime As Date, _
Optional ByVal strSeparator As String = ":") _
As String
' Returns count of days, hours and minutes of datTime
' converted to hours and minutes as a formatted string
' with an optional choice of time separator.
'
' Example:
' datTime: #10:03# + #20:01#
' returns: 30:04
'
' 2005-02-05. Cactus Data ApS, CPH.
Dim strHour As String
Dim strMinute As String
Dim strHourMinute As String
strHour = CStr(Fix(datTime) * 24 + Hour(datTime))
' Add leading zero to minute count when needed.
strMinute = Right("0" & CStr(Minute(datTime)), 2)
strHourMinute = strHour & strSeparator & strMinute
FormatHourMinute = strHourMinute
End Function
For your example, the output will be:
Result = FormatHourMinute(#23.59# * 800)
' Result -> 19186:40
And your expression will be:
=FormatHourMinute(Summe([Dauer Tätigkeit]))

Formatting an idiomatically pronounceable time string

I have programmed a form in Visual Basic which displays the current system time (hh:mm:ss) in a label called "DigitalTime".
Now for the hard part: How do I program a second label ("WordTime") to use the current time (from "DigitalTime") and show it in the "WordTime" label in words like this:
Example 1: (time is 22:50) I want label "WordTime" to show "10 minutes to 11".
Example 2: (time is 13:15) I want label "WordTime" to show "15 minutes past 1".
For the minutes 0-30 I want it to display "... minutes past ...". For the minutes 31-59 I want it to display "... minutes to ...".
It turns out that it isn't that hard thanks to the wonderful ToString formatters available for DateTime in .NET and using String.Format. The DateTime structure in general has all you need to know on this stuff. One caveat and a gotcha, to subtract time from a current DateTime we Add negative amounts of time. There is no SubtractMinutes method on DateTime, only AddMinutes, so you add negative time.
With all that said something like this below. Ideally you'd just make it a function, but I left it fairly basic so it wouldn't get confusing.
10 minutes to 11:
Dim _textToMinute As String = String.Empty
If DateTime.Now().Minute > 30 Then
_TextToMinute = "Past"
Else
_textToMinute = "To"
End If
Dim _minutesTillNextHour = (DateTime.Now().AddHours(1).AddMinutes(-DateTime.Now().Minute) - dateTime.Now).Minutes
Dim _nextHour = DateTime.Now().AddHours(1).ToString("%h")
label1.Text = String.Format("{0} minutes {1} {2}", _minutesTillNextHour, _textToMinute, _nextHour)
15 minutes past 1
label1.Text = String.Format("{0} minutes {1} {2}", DateTime.Now().Minute, _textToMinute, DateTime.Now().ToString("%h"))
When the minutes is 30,it is common practice to use the word "half", as in "half past 6". Here's a simple little function that takes that into account and returns a formatted string that can be assigned wherever you need it:
Function TimeInCommonLang(ByVal input As DateTime) As String
Dim minutes As String = ""
Dim indicator As String = ""
If input.Minute <= 30 Then
indicator = "past"
If input.Minute = 30 Then
minutes = "half"
Else
minutes = input.Minute.ToString & " minutes"
End If
Else
indicator = "to"
minutes = (60 - input.Minute).ToString & " minutes"
input = input.AddHours(1)
End If
Return String.Format("{0} {1} {2}", minutes, indicator, input.ToString("%h"))
End Function