I have the following code that runs without issue on some laptops and then others it will error out with a Type Mismatch. In Column AA are Dates with format (mm/dd/yyyy) and Column AB has the respective Times with format (hh:mm:ss).
I am subtracting the date and time from Now(). I am unable to really troubleshoot the issue because it works fine on my laptop. For others, it errors out. CLng(CDate(Now())) has a value but the other two induce type mismatch. I've tried the two lines below and also another which concatenated the date and time, then performed CLng(CDate(.
'If CLng(CDate(Now())) - CLng(CDate(Range("AA" & i).Value)) + CLng(CDate(Range("AB" & i).Value)) >= 7 Then
If CLng(CDate(Now())) - CLng(CDate(FMT(Range("AA" & i), "mm/dd/yyyy"))) + CLng(CDate(FMT(Range("AB" & i), "hh:mm:ss"))) >= 7 Then
where FMT is a public function:
Public Function FMT$(ByVal Value, ByVal strFormat)
FMT = VBA.Format$(Value, strFormat)
End Function
I am requesting my colleague to send me a screenshot of his region date/time settings.. I was thinking this could be the case. I've read other questions similar to this but not able to figure it out. Thanks in advance.
If columns AA and AB contain text rather than dates and times, try using the following statement:
If Now() - (DateValue(Range("AA" & i)) + TimeValue(Range("AB" & i))) >= 7 Then
This will probably still be problematic if the users have a local date setting of, for instance, dd/mm/yyyy but your columns are storing a string representing a date in some other locale's date setting. If that is the case, you may need to parse the fields and do it as follows:
Dim myDateStr As String
Dim myTimeStr As String
Dim myDateTime As Date
myDateStr = Range("AA" & i)
myTimeStr = Range("AB" & i)
myDateTime = DateSerial(CInt(Mid(myDateStr, 7, 4)), CInt(Mid(myDateStr, 1, 2)), CInt(Mid(myDateStr, 4, 2))) + _
TimeSerial(CInt(Mid(myTimeStr, 1, 2)), CInt(Mid(myTimeStr, 4, 2)), CInt(Mid(myTimeStr, 7, 2)))
If Now() - myDateTime >= 7 Then
You can use the Value2 property of the Range object to get the numerical representation of a DateTime. Try:
If CDbl(Now()) - (Range("AA" & i).Value2 + Range("AB" & i).Value2) >= 7 Then
Just be sure to convert Now() to Double, otherwise it will use just the date part of the DateTime.
I find it easier to work with the numerical representation of the DateTime, as it allows you to bypass the regional settings.
Related
I am struggling to find some concrete answers to creating formulas with dynamic references to cells that will not always be in the same position especially using R1C1...
I have a sheet with 4 tables that generate the data for a daily/Hourly heatmap for x devices (Which is a Variable number depending on how many are online)
I have to generate 168 data points for each device (Mon 00:00am, Mon 01:00, Mon 02:00 > Sun 23:00) for 4 metrics (672 per device) which when complete will be compiled into SQL script, Thats all relatively straight forward and is working within other areas of this project using dynamic table positions.
The trouble I am experiencing comes from trying to Create an SQL insert String. The insert string itself is:
="INSERT INTO [dbo].[Heatmap Stats] (Creation_Date, Site_Id, Day, Hour, Humidity, Temperature, PIRCount, Cleaning_Seconds) VALUES ("&TODAY()-2&", "&$A2811&", "&B$1&", "&B$2&", "&B3&", "&B705&", "&B1407&", "&B2109&");"
Realistically, my main interest is having the final 3 references (B705, B1407, B2109) as dynamic in this formula - as these start positions will be relative to the qty of devices it is crunching data for... These only work for the specific data set I am creating this for... I have tried setting this up using a number of variables such as cell, and address, I have tried referencing the cells using number variable and Range(Cells(),Cells())
Set sI = Range("$A3").Cell 'Constant start position, bound to column
Set dI = Range("B$1").Cell 'Constant start position, bound to row
Set hI = Range("B$2").Cell 'Constant start position, bound to row
Set hU = Range("B3").Cell 'Constant start position
'These 3 cells
Set tE = Range(Cells((iR / 2) + 3, 2), Cells((iR / 2) + 3, 2)).Cell
Set fF = Range(Cells(((iR / 3) * 2) + 4, 2), Cells(((iR / 3) * 2) + 4, 2)).Cell
Set cM = Range(Cells(((iR / 4) * 3) + 4.5, 2), Cells(((iR / 4) * 3) + 4.5, 2)).Cell
Range("B2811").Value = "=INSERT INTO [dbo].[Heatmap Stats] (Creation_Date, Site_Id, Day, Hour, Humidity, Temperature, PIRCount, Cleaning_Seconds) VALUES (& TODAY() - 2, " & sI & ", " & dI & ", " & hI & ", " & hU & ", " & tE & ", " & fF & ", " & cM & ");"
I can confirm the variables and their values are generated correctly (and yes the 4.5 is non-conventional but believe it or not it solves a problem when dealing with odd numbers that don't divide well..) - It is always my attempt at a dynamic variable formula that generates a runtime 1004 Error and those variables are used elsewhere
Recording the initial input of the formula returns the following in R1C1:
"=""INSERT INTO [dbo].[Heatmap Stats] (Creation_Date, Site_Id, Day, Hour, Humidity, Temperature, PIRCount, Cleaning_Seconds) VALUES (""&TODAY()-2&"", ""&RC1&"", ""&R1C&"", ""&R2C&"", ""&R[-2808]C&"", ""&R[-2106]C&"", ""&R[-1404]C&"", ""&R[-702]C&"");"""```
Due to the volume of double quotations and nested quotations ("") I found this quite difficult to insert variables into and mostly had it appear in the editor as part of the statement itself, not as variables:(
Can anyone help me to form this SQL statement through a dynamic formula? either R1C1 or .formula?
In vba,I am trying to convert datetime stamp(1899-12-30T00:00:00.000+0000) from oracle server into dd-mm-yyyy. I need to have a date format which can be recognised by excel and display it in a specific manner using cell formatting (like excel is parsing the date from sql server into dd-mm-yyyy type on its own using cell formatting but unable to recognise the oracle format for the same).
For j = 1 To colCount
mainWorkBook.Sheets("sheet1").Range(colToLetter(j) & 1).Value = node(0).ChildNodes(j - 1).tagName
Next j
For i = 0 To rowCount - 1
For j = 1 To colCount
If IsDate(node(i).ChildNodes(j - 1).Text) Then
mainWorkBook.Sheets("sheet1").Range(colToLetter(j) & i + 2).Value = CDate(node(i).ChildNodes(j - 1).Text)
Else
mainWorkBook.Sheets("sheet1").Range(colToLetter(j) & i + 2).Value = node(i).ChildNodes(j - 1).Text
End If
Next j
Next i
Date values are handled differently in vba, excel and oracle.
Do you really need pre 1900 dates?
Value ranges:
vba: 1 January 100, to 31 December 9999
Date variables are stored as IEEE 64-bit (8-byte) floating-point numbers
see https://learn.microsoft.com/en-us/office/vba/language/reference/user-interface-help/date-data-type
oracle: year -4712 to 9999 (excluding year 0)
different datatypes available depending on your needs:
DATE, TIMESTAMP, TIMESTAMP WITH TIME ZONE, and TIMESTAMP WITH LOCAL TIME ZONE
see https://docs.oracle.com/cd/B19306_01/server.102/b14200/sql_elements001.htm#SQLRF00204
Excel: 01.01.1900 - 31.12.9999
converting 0 to a date => 00.01.1900
converting 1 to a date => 01.01.1900
...
converting 2958465 to a date => 31.12.9999
I you only want to display the contents of the oracle database you can easily just display the textual content. If you want to calculate with the dates you might want to add a shift to do it in excel or you could do the calculation in vba and only display the results as strings.
If you need "historical" dates in your solution and want to calculate with it search for the different available options: "excel date pre 1900"
see also http://www.creativedeletion.com/2016/04/29/programmers-know-dates.html
see also https://en.wikipedia.org/wiki/Time_formatting_and_storage_bugs
If I understand correctly you simply want to convert a string to a valid date; the DateSerial functions offers a reliable way:
Function timeStampOracle2VBA(myDate) As Date
Dim Tokens ' i.e. As Variant to allow split
tokens = Split(Split(myDate, "T")(0), "-", 3) ' limit split results to 3 tokens
Dim dat
dat = DateSerial(Val(tokens(0)), Val(tokens(1)), Val(tokens(2))) ' arguments year, month, date
timeStampOracle2VBA = dat ' return function value
End Function
Example call
Sub test()
Debug.Print Format(timeStampOracle2VBA("1999-12-30T00:00:00.000+0000"), "dd-mm-yyyy")
End Sub
I have the following date in B cell. Actually this is not in the date format.
2015-11-01-01.13.34.737000
that has to be changed into the following format:
11/01/2015 01:13:34 AM
I'm not so familiar in excel formulas. Can anyone help me to bring the expected output? Actually, I tried changing the date format using format cells but no luck and also tried some excel formulas.
-Thanks in advance
If your original value is in cell A1, then as written, this works:
= MID(A1, 6, 2 ) & "/" & MID(A1, 9, 2) & "/" & LEFT(A1, 4) & " " & SUBSTITUTE(MID(A1, 12, 8), ".", ":") & " AM"
If you need the formula to 12-hour time and append AM or PM, then obviously you need to extract that 2 digits of the input value and check whether it's >= 12, append the right string, and change the hour before you output it. By the time you've understood what the above is doing, you may begin to see how you could do that. However, since it's a bit more complex, here:
= MID(A1, 6, 2 ) & "/" & MID(A1, 9, 2) & "/" & LEFT(A1, 4) & " " & RIGHT("0" & MOD(MID(A1, 12, 2) - 1, 12) + 1, 2) & ":" & SUBSTITUTE(MID(A1, 15, 5), ".", ":") & IF(NUMBERVALUE( MID(A1, 12, 2) ) < 12, " AM", " PM")
The MOD is needed to wrap around after 12 hours, and the add/subtract 1 acrobatics are because we write hours from 1 to 12, not 0 to 11. The right("0" & foo, 2) bit simply ensures that 1-digit numbers are 0-padded to 2 digits. This seems to work, but I didn't test it totally exhaustively.
=--SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(A1,"-"," ",3),"-","/"),".",":"),":",".",3)
The above converts your original string into a string with this format:
2015/11/01 01:13:34.737000
The double unary at the beginning then converts that string to a real Excel date/time which can be formatted however you wish.
Hey I am thinking about a solution for my problem for hours now. I've searched the web, too and was able to find some approaches but none of them does work for my problem.
I have one cell with data that appears like this:
(Monday#100%[00:00-24:00]);(Tuesday#100%[00:00-24:00]);(Wednesday#100%[00:00-24:00]);(Thursday#100%[00:00-24:00]);(Friday#100%[00:00-24:00]);(Saturday#100%[00:00-24:00]);(Sunday#100%[00:00-24:00])
The problem is, that this string is not consistent. It could also look like this:
(Monday#125%[00:00-04:00]);(Monday#90%[04:00-08:00]);(Monday#90%[08:00-12:00]);(Monday#115%[12:00-16:00]);(Monday#120%[16:00-20:00]);(Monday#115%[20:00-24:00]);(Tuesday#125%[00:00-04:00]);(Tuesday#90%[04:00-08:00]);(Tuesday#90%[08:00-12:00]);(Tuesday#115%[12:00-16:00]);(Tuesday#120%[16:00-20:00]);(Tuesday#115%[20:00-24:00]);(Wednesday#125%[00:00-04:00]);(Wednesday#90%[04:00-08:00]);(Wednesday#90%[08:00-12:00]);(Wednesday#115%[12:00-16:00]);(Wednesday#120%[16:00-20:00]);(Wednesday#115%[20:00-24:00]);(Thursday#125%[00:00-04:00]);(Thursday#90%[04:00-08:00]);(Thursday#90%[08:00-12:00]);(Thursday#115%[12:00-16:00]);(Thursday#120%[16:00-20:00]);(Thursday#115%[20:00-24:00]);(Friday#125%[00:00-04:00]);(Friday#90%[04:00-08:00]);(Friday#90%[08:00-12:00]);(Friday#115%[12:00-16:00]);(Friday#120%[16:00-20:00]);(Friday#115%[20:00-24:00]);(Saturday#125%[00:00-04:00]);(Saturday#90%[04:00-08:00]);(Saturday#90%[08:00-12:00]);(Saturday#115%[12:00-16:00]);(Saturday#120%[16:00-20:00]);(Saturday#115%[20:00-24:00]);(Sunday#125%[00:00-04:00]);(Sunday#90%[04:00-08:00]);(Sunday#90%[08:00-12:00]);(Sunday#115%[12:00-16:00]);(Sunday#120%[16:00-20:00]);(Sunday#115%[20:00-24:00])
The structure of the string is
You have a day of the week followed by an "#"
after the at (#) you have a number that can be between 0 and 999
after that you have a time of the day in brackets []
You can have up to 6 different time frames of one day (not more, but less)
each time frame cluster is separated by ; and within normal brackets ()
So this is my starting position. What I want is to extract the numbers between # and % and list them chronologically (Monday to Sunday, hours of the day).
I was able to extract the number between # and % for each day of the week with this formula
=MID(B3;SEARCH("Monday#";B3)+7;SEARCH("%";B3)-SEARCH("Monday#";B3)-7)
But this only works if each day of the week is mentioned only ones.
I am out of ideas of how I could get it to work when having more time frames per day. Appreciate any help.
Thanks,
Ramon
Try an set of iterative searches, where the next search starts at the position found for the previous result. ie:
in cell B6 put =SEARCH("]",$B$3,B5+1)
in cell C6 put =MID($B$3,SEARCH("(",$B$3,B5+1)+1,SEARCH("#",$B$3,B5+1)-SEARCH("(",$B$3,B5+1)-1)
in cell D6 put =MID($B$3,SEARCH("[",$B$3,B5+1)+1,SEARCH("]",$B$3,B5+1)-SEARCH("[",$B$3,B5+1)-1)
in cell E6 put =MID($B$3,SEARCH("#",$B$3,B5+1)+1,SEARCH("%",$B$3,B5+1)-SEARCH("#",$B$3,B5+1)-1)
(Note that B5 needs to be empty (or 0) for this to start correctly)
You can then fill down as far as needed to pick up each term. If they are out of order, then you can order on column D then C (the time then the day).
This might get you started.
Sub Extractor()
Dim data() As String, i As Integer, rw As Integer
rw = 3
data = Split(Range("A1"), ";")
For i = 0 To UBound(data)
Range("A" & rw) = VBA.Mid$(data(i), 2, InStr(1, data(i), "#") - 2) 'Day
Range("B" & rw) = VBA.Mid$(data(i), InStr(1, data(i), "#") + 1, InStr(1, data(i), "%") - InStr(1, data(i), "#") - 1) '% number
Range("C" & rw) = VBA.Mid$(data(i), InStr(1, data(i), "[") + 1, InStr(1, data(i), "]") - InStr(1, data(i), "[") - 1) 'Time
rw = rw + 1
Next i
End Sub
Notes:
Assumes your string is in A1
Prints your data in columns A, B, and C starting in row 3
You can use Text-to-Columns feature of excel, with ) as a delimiter. Than transpose the columns into rows to get something like this:
(Monday#125%[00:00-04:00]
;(Monday#90%[04:00-08:00]
;(Monday#90%[08:00-12:00]
;(Monday#115%[12:00-16:00]
;(Monday#120%[16:00-20:00]
...
;(Sunday#115%[20:00-24:00]
Then apply formulas.
Edit:
Using just Find and Mid you can achieve this:
The idea behind find and mid is always the same.
Ex. for finding ( is =FIND("(";[Text]).
Ex. for extracting Day is =MID([Text];[#[Pos(]]+1;[#[Pos'#]]-[#[Pos(]]-1)
I debug in code, and I see that the value is in correct format, it just get and set the value only, and it seem like excel take the data as datetime instead of normal string,
I try to use NumberFormat and format it to either 1 of this (#, text, number, general) neither 1 is working, any help will be great
ActiveSheet.Range("D" & i).Value = arr(i, 4)
Update 1
Sorry to not mention arr, arr is multi dimension array, it store the column that I read from , I just get the value from excel, and the store in range by looping
Try this
ActiveSheet.Range("D1").Value = "'" & arr(1, 4)
I found the solution, although it look stupid
I change the format to
.NumberFormat = "yyyy/mm/dd"
and I get the value I want