Which date system does VBA recognise/default to? - excel

I'm writing a vba subroutine in excel to store all date values between 2 dates in a single dimension array and then check for each value in a range on another sheet.
My problem is when the code is grabbing the date values (as an integer(or double - whichever one it is actually using)) it is storing a value 1462 greater than the date value on the sheet.
I am using the 1904 date system so I can use negative time values and i'm in Australia so dates are formatted dd/mm/yyyy.
As an example;
On the sheet:
01/01/2019 = 42004
In the code: 01/01/2019 = 43466
I understand the difference is the same as the difference between date values when using 1900 vs. 1904 date systems which leads me to believe perhaps VBA is defaulting the sheet value to be in 1900 and converting the value to 1904 again when the code is run?
This workbook is set up as follows:
Sheet1 contains dates from 01/01/2019 to 25/01/2019 in Range("A1:A25").
Sheet2 contains 01/01/2019 in cell A1 and 10/01/2019 in cell A2and a activeX commandbutton.
And the code:
Private Sub CommandButton1_Click()
Dim myStart As Long
Dim myEnd As Long
myStart = Me.Range("A1").Value
myEnd = Me.Range("A2").Value
Dim v As Variant
Dim x As Long
Dim myArr As Variant
ReDim myArr(0 To 100)
x = 0
For v = myStart To myEnd
If v = Empty Then Exit For
myArr(x) = v
Debug.Print ("v = " & v)
Debug.Print ("myArr = " & myArr(x))
x = x + 1
Next
Dim lastrow As Long
lastrow = Me.Cells(Rows.Count, 4).End(xlUp).Row
x = 0
For Each cell In Sheet1.Range("A1:A100")
Debug.Print (CDbl(cell))
If cell = myArr(x) Then
Me.Cells(lastrow, 3).Value = cell
Me.Cells(lastrow, 4).Value = Format(cell, "dd/mm/yyyy")
lastrow = lastrow + 1
End If
x = x + 1
Next
End Sub
The output for the cell values in columns 3 and 4 are as follows (first 5 rows for demonstration):
C D Sheet1.Range("A1:A5")[when displayed as number format]
1 43466 01/01/2019 42004
2 43467 02/01/2019 42005
3 43468 03/01/2019 42006
4 43469 04/01/2019 42007
5 43470 05/01/2019 42008
The dates are written into the cell as a short date format not numeric value.
Using the intimidate window I've noticed ?cdbl(DateValue(now)) = 43496 (31/01/2019) which is making me wonder which values are correct for the dates using the 1904 date system? Per the values in Sheet1 it should be 42034.
Is the issue caused by a data type or function I've used, is it as questioned earlier - the sheet is converting them to 1904 when the values are assigned to Sheet2 with VBA, is it a bug with excel or something else?
I found a question with the same problem here on mrexcel however the resolution there was change Excel to use the 1900 date system or subtract 1462 from the values in the code which I'm hoping to avoid both of.

In general, the date system in VBA is different than the date system in Excel. You can have these 3 date system options:
Excel date
Excel date with 1904 property
VBA date
This is the difference:
The dates are converted to numbers. E.g., every date is converted to a number, but the starting number is a bit different.
In Excel, the 1 is converted to 01.January.1900;
In VBA, the 1 is converted to 31.December.1899;
In Excel with 1904, the 1 is converted to 02.January.1904;
The 1904 system (or its lack) is set per Workbook. Thus, if you have 2 workbooks in Excel, one with 1904 and one without it, it would recognize them correspondingly. The system is set in:
File > Options > Advanced > Use 1904 Date System
In general, if there is a chance, that someone somehow changes your workbook with the wrong system, consider adding this check at the openning of the workbook:
Private Sub Workbook_Open()
If ThisWorkbook.Date1904 Then
MsgBox "System is 1904, consider some action!"
End If
End Sub
If you are wondering which system to choose - I can recommend never using the 1904.
Story for the adding VBA to Excel and the 1904 problem

To provide a solution to my example a colleague mentioned if you dim the date values as the date datatype the issues with the values going sheet -> vba -> sheet disappears.

Related

Run code when the rows are between a date range

I want to run a code that transfers data from one sheet to another based on the year (eg 01/01/2018 - 31/1/2018).
The sheet contains 2 columns with dates, start_date and end_date stored as dates, so I did an If statement but it doesn't seem to "understand" the dates values that I stored previously.
'Dates columns
Dim fechaIniTarget As Variant
Dim fechaFinTarget As Variant
'Ini = start / Fin = end
Set fechaIniTarget = Range("D2")
Set fechaFinTarget = Range("E2")
If fechaIniTarget.Value = "01/01/2018" And fechaFinTarget.Value = "31/12/2018" Then
' function
MsgBox "PROCESO COMPLETO"
End If
I tried parsing the dates as integer but it still doesn't work.
You compare a date fechaIniTarget.Value against a string "01/01/2018". Use a real date with the DateSerial function instead to compare date against date.
If fechaIniTarget.Value = DateSerial(2018, 1, 1) And fechaFinTarget.Value = DateSerial(2018, 12, 31) Then
Also note that you used 2 times fechaIniTarget but I guess the second one should be fechaFinTarget.
Also don't use Variant if not necessary. Instead declare your variables As Range here:
Dim fechaIniTarget As Range
Dim fechaFinTarget As Range

Excel Formula - Comparing Range of Date

how to write EXCEL VBA to make my date from 04/JUNE > 04/JUNE 23:59. i cannot use the '= date + 5/6' as i have to run the VBA many times a day and it will add my dates to tomorrow/ the day after tomorrow. i just wanna make the date to end of date. please help.
The example will be like
CELL A1 : 12/June
CELL B1 : 15/June
CELL C1 : 15/June 12:00 HRS
CELL D1 : =IF C1B2, “OUT OF RANGE”, “Okay !”)
in this case D1 will still display OUT OF RANGE.
I have loads of such to change so I was thinking of writing a VBA to automatically convert C1 from 15/JUNE -> 15/JUNE 23:59 , so that D1 will display Okay !
I tried Cdate(Range(“D1”)) + 5/6 in vba to make it 23:00 hrs and I run this macro a few times in a day and it will keep adding 23hrs to the date and made it change to another date.
About what you are talking?
About:
- "Excel Formula" or
- "EXCEL VBA"
?
About:
- "Comparing Range of Date" or
- "to make my date"
?
Assume, that VBA is...
The Date type in VBA is Double, where:
- Integer part as quantity of days from... (look F1), and
- Fractional part of day.
So, your desired "04/JUNE > 04/JUNE 23:59" will:
? DateSerial(2018, 06, 4) + ((23& * 60& * 60&) + (59& * 60&)) / 86400&
18-06-04 23:59:00
Yeah, sure, you can use TimeSerialinstead of above, but ... it didn't give you right understanding of VBA dates.
.
----------
ADD:
Sorry but will this code only work for one cell because I have lots of
cells with dates and I need VBA to extract them out and convert to
23:59 for eg I run a for loop to change like 20 cells in a row with
multiple range. And I will run the macro a few times in a day will it
add 23hrs to that date every time and cause it to change dates ?
Public Sub sp_Test_Date()
Dim rSel As Range
Dim i&
Const H23M59 As Double = 1 - 60 / 86400
Set rSel = Selection
With rSel
For i = 1 To .Cells.Count
With .Cells(i)
If IsDate(.Value) Then
.Offset(0, 1).Value = CDate(Int(.Value) + H23M59)
End If
End With ' .Cells(i)
Next
End With ' rSel
End Sub
i tried modifying it to below and it failed me :(
`
Dim x As Integer
Dim test1 As Date
Dim schdWS, compWS As Worksheet
Const H23M59 As Double = 1 - 60 / 86400
Set schdWS = Sheet1
Set compWS = Sheet11
lastrow = schdWS.Cells(Rows.Count, 8).End(xlUp).Row
For x = 20 To lastrow
If IsDate(schdWS.Cells(x, 3).Value) Then
Cells(x, 3).Value = CDate(Int(Cells(x, 3).Value + H23M59))
End If
'test1.NumberFormat = "dd/mm/yyyy"
'schdWS.Cells(x, 3).FormulaR1C1 = test1 & " 23:59"
Next x
End Sub
`

Calculating Attendance dates for Students using VBA Excel

I need a little help with resolving a VBA code for an school assignment.
Dim i As Long
Dim LastStudent As Long
Records.Sheets("Student").Activate
LastStudent = Cells(Rows.Count, 1).End(xlUp).Row
For i = 2 To LastStudent
If (DateDiff("d", Date, Attendance_rng.Range("I" & i).Value) > 80) Then
.Range("K15").Value = WorksheetFunction.CountIfs(Attendance_rng.Range("A:A"), RollNo, Attendance_rng.Range("D:D"), "ACTIVE")
End If
Next
I tried to execute the above code snippet. I don't see any errors but I don't get any data output either.
I want to count the number of days (Today's date - date in column I for each student), if that value is > 80 then record the day count in cell K15 for each student(Roll Number) from column A where the G Column data is "Active".
Note:
Column I has the Weekly recorded attendance dates

Table of run times stored as strings converted to values manipulated and converted back

I keep a running log in an excel worksheet that is part of a larger exercise workbook. I am trying to set up the worksheet so I don't have to manually do the math every time I enter a new run. I enter the and want the worksheet to calculate the unfinished lap for me (the portion of the run after the last mile that my runners watch won't give me a lap time for, say .25 miles) I am using an odd notation for the times which I would be willing to change if necessary but I am most concerned with it being readable so I don't want to change it to something that makes the excel work easier but bothers me when I am looking through my runs. Here is a what it looks like:
Date Distance TotTime Avg Time 1 2 3 4 5 6 7 8 9 10 UnfinLap
10/2 2.3 mi 19'35" 8'31" 8'28" 8'53" 2'14"
What I want to do is for each cell in the UnfinLap column I want it to convert the total time into a value, convert and subtract each lap time, then finally convert it back into a string in my chosen format. And the runs vary in length so a 5.2 mile run would have 5 columns with values. I have neither a large amount of experience with excel or VBA but I am pretty quick to learn and have some programming experience so I took a shot at creating a macro for this without much success.
Sub Lap_Time_Function()
'
' Lap_Time_Function Macro
' This converts the times to value, does the math then converts back
'
' Variable Declarations
Dim TotMins As Integer
Dim TotSecs As Integer
Dim LapMins As Integer
Dim LapSecs As Integer
Dim LoopCounter As Integer
Dim UnfinishedLap As String
Dim wb As Workbook
Dim ws As Worksheet
' Initial values set
LoopCounter = 7
TotMins = WorksheetFunction.Value(WorksheetFunction.Left(Cells(ActiveCell.Row, 2), 2))
TotSecs = WorksheetFunction.Value(WorksheetFunction.Mid(Cells(ActiveCell.Row, 2), 4, 2))
wb = ActiveWorkbook
ws = wb.Sheets("Run Log")
' Calculate time of unfinished lap by subtracting current finished lap from total time
Do While Not IsEmpty(Cells(ActiveCell.Row, LoopCounter))
LapMins = WorksheetFunction.Value(WorksheetFunction.Left(Cells(ActiveCell.Row, LoopCounter), 2))
LapSecs = WorksheetFunction.Value(WorksheetFunction.Mid(Cells(ActiveCell.Row, LoopCounter), 4, 2))
TotMins = TotMins - LapMins
TotSecs = TotSecs - LapSecs
LoopCounter = LoopCounter + 1
Loop
UnfinishedLap = CStr(TotMins) & CStr(Chr(39)) & CStr(TotSecs) & CStr(Chr(34))
Cells(ActiveCell.Row, 17) = UnfinishedLap
End Sub
If there is a simpler solution or anyone can point out what I'm doing wrong I would greatly appreciate it.
You don't need VBA at all.
Excel formula to convert from m'ss" (in A1) to Excel time:
=TIMEVALUE("0:"&SUBSTITUTE(SUBSTITUTE(A1;"'";":");"""";""))
Excel formula to convert from Excel time (in B1) to m'ss":
=TEXT(B1;"[m]'ss")&""""
Using such functions, you can do arithmetic with Excel times.

Macro to move data with changing date

Sorry if this isn't explained overly well, im a macro newbie so im not sure if this one is even possible..
I'm looking to create a weekday table for some simple statistic reporting that automatically creates a new row each day, and removes the oldest, showing the data for the current day and 6 days previous. Ideally i'd like the current day at the top of the table, and each day the entered data in the corresponding row moves down 1 row creating space for the new day's stats.
As some background info on what im trying to do.. im basically creating a friendly UI display (offline HTML) of the data recorded in a very simple 5 column (stats) by 7 row (weekdays) table. This database will need to be updated by multiple people with limited technical ability, so im basically trying to make it as easy as possible for them to enter stats each day without having to worry about also updating to correct dates and making sure they are replacing the right days data etc. In theory, it would be great to automate the process of updating the table each day to create space for them to enter the current days data, pushing yesterdays data down one row (and if the cell ranges for the whole table always the same, it should allow me to automate the updates to the offline HTML display as well).
Any ideas?
This should get you started:
Sub WeekdayTable()
Dim tbl As Range
Dim r As Integer
Set tbl = Range("A1:E7") 'Define your table, 5 columns x 7 rows. Modify as needed.
For r = tbl.Rows.Count To 2 Step -1
tbl.Rows(r).Value = tbl.Rows(r - 1).Value
Next
'empty out row 1
tbl.Rows(1).Clear
'Assuming the column 1 contains valid DATE values, _
' we can use the DateAdd function to print the next date:
tbl.Cells(1, 1) = DateAdd("d", 1, tbl.Cells(2, 1))
End Sub
First give a name to the date header cell. (Click the cell. Look at the top left of the screen where the cell coordinates appear. "A1", "B2", etc...
In that textbox, type the header name: "MyDateHeader"
then, use this macro (you can add it to the workbook open event, or activate)
Sub YourMacro()
Dim DateHeader As Range
Set DateHeader = Range("MyDateHeader")
Dim FirstDateCell As Range
Set FirstDateCell = DateHeader.Offset(1, 0)
Dim MyDay As Integer, MyMonth As Integer, MyYear As Integer
Dim CurrDay As Integer, CurrMonth As Integer, CurrYear As Integer
MyDay = Day(FirstDateCell.Value)
MyMonth = Month(FirstDateCell.Value)
MyYear = Year(FirstDateCell.Value)
CurrDay = Day(Date)
CurrMonth = Month(Date)
CurrYear = Year(Date)
If (MyDay <> CurrDay) Or (MyMonth <> CurrMonth) Or (MyYear <> CurrYear) Then
FirstDateCell.EntireRow.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromRightOrBelow
DateHeader.Offset(1, 0).Value = Date 'Careful, FirstDateCell has moved down.
DateHeader.Offset(8, 0).EntireRow.Clear
End If
End Sub

Resources