Data types in VB and .NET
This article presents a technical look into the numeric data types supported by classic Visual Basic, VBA, VB.NET and the .NET framework. There are surprising peculiarities in several types. A conversion diagram shows how to achieve lossless type conversion.
How to store numbers in your programs? How to avoid Overflow or loss of decimals? How to work with dates? This article summarizes the elementary numeric data types in classic Visual Basic, Visual Basic for Applications, Visual Basic .NET and other .NET languages.
Reasonable development experience is assumed. This is no introduction to programming. You may find some of the information especially handy if you intend to migrate from VB6 to a .NET language.
Data type summary
With numeric data types we mean the elementary builtin types intended to store integer numbers, decimal numbers, flags and dates.
The following table shows numeric data types sorted by their storage requirements in bits and the numeric range they support. The VB6/VBA data types are used in classic VB and Visual Basic for Applications. The .NET data types are offered by the .NET framework versions from 2.0 to 4.0. The VB.NET data types are aliases for the underlying .NET data types, available in Visual Basic versions from 2005 to 2010.
Bits  VB6/VBA  .NET  VB.NET  Min value  Max value 

(1)  Boolean  Boolean  1  0  
8  SByte  128  127  
8  Byte  Byte  0  255  
16  Integer %  Int16  Short  32768  32767 
16  UInt16  UShort  0  65535  
32  Long &  Int32  Integer %  2,147, 
2,147, 
32  UInt32  UInteger  0  4,294, 

64  Currency @  922,337, 
922,337, 

64  VBA7: LongLong ^  Int64  Long &  9,223, 
9,223, 
64  UInt64  ULong  0  18,446,744, 

128  Decimal  Decimal  @  7.92E+28 *  7.92E+28 * 
32  Single !  Single  !  3.4028235 
3.4028235 
64  Double #  Double  #  1.80E+308 **  1.80E+308 ** 
Date and time  
64  Date  657434 
2958465 

64  DateTime  Date  9,223, 
7,767, 

64  TimeSpan  9,223, 
9,223, 
* Decimal: ±79,228,162,514,264,337,593,543,950,335
** Double: ±1.79769313486231570E+308
Data type specifics
Boolean
Boolean is really a flag and not a numeric data type. The storage size is 16 bits in VB6 and varies by platform in .NET.
Integer and Long
Integer and Long have the same name and type character in VB6/VBA and VB.NET, but they are different data types altogether. To stay clear one can use Int16, Int32 and Int64 in .NET.
Currency
Currency is a 64bit integer divided by 10000. It is only available in VB6/VBA. In VB.NET one can replace it with Decimal, which provides more capability.
LongLong
Introduced with Office 2010, LongLong is a 64bit signed integer that is available in VBA7 running on a 64bit platform. It is unsupported in VB6, VBA6 and on 32bit platforms.
Decimal
Decimal is a signed 96bit integer, which is divided by a scaling factor. The scaling factor varies from 1 to 1E+28. A Decimal can represent 29 decimal digits: integers and decimal numbers with max 28 decimal places. The binary representation consists of a 1bit sign, a 96bit integer number and the scaling factor. The smallest nonzero Decimal is ±1E−28 = ±0.0000000000000000000000000001. The storage size is 128 bits, but not all the bits are used for the number.
VB6 supports Decimal with the Variant data type. You cannot declare a variable to be of type Decimal. You can, however, create a Variant whose subtype is Decimal using the CDec
function.
Single
The value closest to zero is ±1.401298E45.
VB6: The maximum Single is 3.4028235E+38. It rounds down to 3.402823E+38 when displayed. The latter is also the maximum Single literal you can write in VB6 code.
.NET: NaN
, PositiveInfinity
and NegativeInfinity
are special values of Single.
Double
The value closest to zero is ±4.94065645841247E324 in VB6 and ±4.94065645841246544E324 in .NET.
VB6 stores max 1.7976931348623157E308. It rounds down to 1.79769313486231E+308 when displayed. The latter value is also the maximum literal number you can write in VB6 code. The absolute maximum is 1.7976931348623158077E308, which equals 1.7976931348623157E308 due to rounding.
.NET: NaN, PositiveInfinity and NegativeInfinity are special values of Double.
Date and time values
Dates and times are closely related to numeric data types, especially in VB6.
VB6 date and time
VB6 stores dates and times in the Date data type. Date can store either the calendar date, the time of day, or both. The range covered is midnight #1/1/0100#
to #12/31/9999 11:59:59 PM#
in the Gregorian calendar. The underlying data type is Double. Use CDbl(T)
to convert a Date to its numeric representation and CDate(n)
to convert a number to a Date.
The integral part of a Date represents the day. The value zero is equal to #12/30/1899#
. This is the Epoch. The value 1 is equal to one day, or 24 hours. A week equals 7 and a year is either 365 or 366. Sample dates: #1/1/1900#
= 2, #1/1/2000#
= 36526, #1/1/2100#
= 73051.
The time of day is in the decimal fraction. An hour is equal to 1/24, a minute is 1/1440 and a second is 1/86400. Noon is 0.5. Noon on #1/1/1900#
equals 2.5 and so on. The maximum precision in VB6 time functions is 1 second, whose numeric value is 0.0000115740740740741. You can even store fractions of a second, but VB6 has no functionality for the fractions.
Peculiarities with historical dates in VB6
The integral part is the date, the fraction is the time: date.time. That's easy. Things get odd when the value is negative. This is on or before #12/30/1899#
.
With modern dates time always runs forwards, as you would suspect. With negative historical dates time actually runs backwards! Midnight #1/1/1800#
equals −36522, but noon #1/1/1800#
is −36522.5 (less than midnight!) and one second before midnight is −36522.9999884259 (even less). At midnight the clock jumps forward to −36521, which equals #1/2/1800#
. The decimal fraction still shows the time and the integral part is the date, but each second decrements the clock while each new day increments it, not just by 1, but by almost 2. Negative times are really counterintuitive.
To make things worse, time values for #12/30/1899#
are ambigous in two ways. First, a time value without a date equals that time on #12/30/1899#
. This means that 0.5 is either noon or noon on #12/30/1899#
, depending on context. Zero is either midnight or #12/30/1899#
or midnight on #12/30/1899#
. The other ambiguity is that all time values come in double for #12/30/1899#
. 0.5 is noon #12/30/1899#
, but 0.5 is noon #12/30/1899#
as well. The integral part is the date, the fraction is the time.
Another surprise is here: #12/30/1899 11:59:59 PM#
 #12/29/1899 11:59:59 PM#
= 2.99997685185185. Not 1, what you normally would expect for a 24hour period. Be careful when working with historical dates.
Expressions for VB6 date/time
Good expressions:
Get date without time: Fix(T)
Get time without date: Abs(TFix(T))
Get time difference in days: DateDiff("s", T1, T2)/86400
Avoid these:
Get date without time: Int(T)
– Wrong for historical dates
Get time without date: TInt(T)
– Wrong for historical dates
Get time difference in days: T2T1
– Wrong for historical dates with time
Bug with DateDiff: DateDiff("s", 0.5, 0.5)
= 1 second, even though it should be 0 seconds.
.NET date and time
DateTime represents dates and times with a 64bit value, which includes 62 bits for the date/time and 2 bits for time zone information (the Kind property). The range covered is midnight #1/1/0001#
to #12/31/9999 11:59:59.9999999 PM#
in the Gregorian calendar. Date/time is stored as "ticks". Each tick equals 100 nanoseconds. The supported range of ticks is from 0 to 3,155,378,975,999,999,999. The "raw" numeric range of the data type is larger because of the time zone field. The value zero is equal to #1/1/0001#
. The smallest nonzero time is 1 tick = 100ns.
TimeSpan represents a time interval (duration), either positive or negative. It can also represent the time of day unrelated to a particular date. TimeSpan is a 64bit type whose underlying numeric range is equal to that of Int64. Time is stored as ticks of 100 nanoseconds each. The range covered is −10675199.02:48:05.4775808 to 10675199.02:48:05.4775807 as measured in days, hours, minutes, seconds and fractions of a second. This is approximately ±29228 years, which means a TimeSpan can go over the date range supported by DateTime.
DateTimeOffset is a structure representing a DateTime value along with its time difference to UTC. This structure is outside the scope of this article.
Data type conversion diagram
The following diagram shows the possible data type conversions in VB6 and .NET.
Numeric data type conversions
pdf
There are two considerations when converting a value from a data type to another: magnitude and precision.
 Magnitude: An error may occur if the converted value is too large (or too small) to fit in the target data type.
 Precision: Loss of precision may occur when converting to a Single or Double. In this case, magnitude is preserved, but some less significant digits may be lost. Loss of precision does not cause a runtime error but it may lead to erroneous results.
Data types in VB and .NET
URN:NBN:fife201012093072