Reputation: 2623
When I write a date from VBA into an Excel worksheet, sometimes the value on the worksheet ends up being one less (one day earlier) than I expect. Here's an example that I've tested on a multiple computers with Excel 2003, 2007, and 2010. From the immediate window:
?Format(41652.9999999963, "yyyy-mm-dd hh:mm:ss")
> 2014-01-14 00:00:00
[A1].value = CDate(41652.9999999963)
?Format([A1].value, "yyyy-mm-dd hh:mm:ss")
> 2014-01-13 00:00:00
[A1].value = CDbl(CDate(41652.9999999963))
?Format([A1].value, "yyyy-mm-dd hh:mm:ss")
> 2014-01-14 00:00:00
What exactly triggers this?
EDIT:
Okay, let me be more clear that this isn't a rounding issue. If I go up or down one fraction of a second I get the correct time. It's just that if I hit near this exact number the date goes off by an entire day:
[A1].value = CDate(41652.99999)
?Format([A1].value, "yyyy-mm-dd hh:mm:ss")
> 2014-01-13 23:59:59
[A1].value = CDate(41652.999999999996)
?Format([A1].value, "yyyy-mm-dd hh:mm:ss")
> 2014-01-13 00:00:00
[A1].value = CDate(41652.999999999997)
?Format([A1].value, "yyyy-mm-dd hh:mm:ss")
> 2014-01-14 00:00:00
[A1].value = CDate(41653.00001)
?Format([A1].value, "yyyy-mm-dd hh:mm:ss")
> 2014-01-14 00:00:01
Upvotes: 6
Views: 1101
Reputation: 1
Both cell value and cdate have enough precision to story this value: 41652.9999999963.
?CDate(41652.9999999963) = 41652.9999999963
True
[A1].Value=cdbl(CDate(41652.9999999963))
?[A1].Value= 41652.9999999963
True
So I think this should be one Excel defect when user assign the cdate to cell value.
Though we don't know the detail implementaion of it, I can guess it might be look like:
[A1].Value=StringToDate(DateToString(CDate(41652.9999999963)))
When we do
[A1].Value=CDate(41652.9999999963))
And the "DateToString" function do not do the right thing: it cut the 41652.9999999963 into two part, 41652 and .9999999963 and it use 41652 to calculate the date part("2014-1-13"), and use .9999999963 to calculate the rest part ("1 day and 0:0:0"), then finally, they are merged into one value "2014-1-13 0:0:0" but "1 day" was lost.
Upvotes: 0
Reputation: 580
As stated in Help for CDate, "CDate recognizes date literals and time literals as well as some numbers that fall within the range of acceptable dates. When converting a number to a date, the whole number portion is converted to a date. Any fractional part of the number is converted to a time of day, starting at midnight." It never says that time rounded to next day adds to dates!! I believe that this solves the mystery.
In fact you can use round yourself to get the desired result. Tests demonstrated that 9 digits are the top number for rounding, with 10 providing the undesired effect...
ex [a1]=cdate(round(41652.9999999999,8))
--> 14/01/14 00:00
[a1]=cdate(round(41652.9999999999,10))
--> 13/01/14 00:00
added code after comment:
Sub dower()
Dim v1 As Double, vdt As Date, vv As Variant, vdbl As Double
Range("a1:a6").ClearContents
v1 = 41652.9999999996
vdt = CDate(v1)
vv = CDate(v1)
vdbl = CDate(v1)
[a1] = v1
[a2] = vdt
[a3] = vv
[a4] = vdbl
vdt = CDbl(v1)
[a5] = vdt
End Sub
Upvotes: 1