简体   繁体   中英

Writing a date from Excel VBA to a worksheet gives the wrong value

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

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM