Предполагая, что value
является double
, вы можете сделать:
(double)Math.round(value * 100000d) / 100000d
Это для точности 5 цифр. Количество нулей указывает количество десятичных знаков.
Недавно я был ошарашен этой маленькой «особенностью» и хотел повысить осведомленность о некоторых проблемах, связанных с функцией IsDate
в VB и VBA.
Как и следовало ожидать, IsDate
возвращает True
при передаче типа данных Date и False
для всех других типов данных, кроме строк. Для строк IsDate
возвращает True
или False
в зависимости от содержимого строки:
IsDate(CDate("1/1/1980")) --> True
IsDate(#12/31/2000#) --> True
IsDate(12/24) --> False '12/24 evaluates to a Double: 0.5'
IsDate("Foo") --> False
IsDate("12/24") --> True
IsDate
должно быть более точно названо IsDateTime
потому что он возвращает True
для строк, отформатированных как раз:
IsDate("10:55 AM") --> True
IsDate("23:30") --> True 'CDate("23:30") --> 11:30:00 PM'
IsDate("1:30:59") --> True 'CDate("1:30:59") --> 1:30:59 AM'
IsDate("13:55 AM") --> True 'CDate("13:55 AM")--> 1:55:00 PM'
IsDate("13:55 PM") --> True 'CDate("13:55 PM")--> 1:55:00 PM'
Обратите внимание из последних двух примеров выше, что IsDate
не является идеальным валидатором раз.
Мало того, что IsDate
принимает время, оно принимает время во многих форматах. Один из которых использует точку (.
) в качестве разделителя. Это приводит к некоторой путанице, потому что период может использоваться как разделитель времени, но не как разделитель даты:
IsDate("13.50") --> True 'CDate("13.50") --> 1:50:00 PM'
IsDate("12.25") --> True 'CDate("12.25") --> 12:25:00 PM'
IsDate("12.25.10") --> True 'CDate("12.25.10") --> 12:25:10 PM'
IsDate("12.25.2010")--> False '2010 > 59 (number of seconds in a minute - 1)'
IsDate("24.12") --> False '24 > 23 (number of hours in a day - 1)'
IsDate("0.12") --> True 'CDate("0.12") --> 12:12:00 AM
Это может быть проблемой, если вы анализируете строку и работаете с ней, основываясь на ее кажущемся тип. Например:
Function Bar(Var As Variant)
If IsDate(Var) Then
Bar = "This is a date"
ElseIf IsNumeric(Var) Then
Bar = "This is numeric"
Else
Bar = "This is something else"
End If
End Function
?Bar("12.75") --> This is numeric
?Bar("12.50") --> This is a date
Если вы тестируете вариант для его базового типа данных, вы должны использовать TypeName(Var) = "Date"
, а не IsDate(Var)
:
TypeName(#12/25/2010#) --> Date
TypeName("12/25/2010") --> String
Function Bar(Var As Variant)
Select Case TypeName(Var)
Case "Date"
Bar = "This is a date type"
Case "Long", "Double", "Single", "Integer", "Currency", "Decimal", "Byte"
Bar = "This is a numeric type"
Case "String"
Bar = "This is a string type"
Case "Boolean"
Bar = "This is a boolean type"
Case Else
Bar = "This is some other type"
End Select
End Function
?Bar("12.25") --> This is a string type
?Bar(#12/25#) --> This is a date type
?Bar(12.25) --> This is a numeric type
Однако, если вы имеете дело со строками, которые могут быть датами или числами (например, при разборе текстового файла), вам следует проверить, является ли это число, прежде чем проверять, является ли это датой:
Function Bar(Var As Variant)
If IsNumeric(Var) Then
Bar = "This is numeric"
ElseIf IsDate(Var) Then
Bar = "This is a date"
Else
Bar = "This is something else"
End If
End Function
?Bar("12.75") --> This is numeric
?Bar("12.50") --> This is numeric
?Bar("12:50") --> This is a date
Даже если все, что вас волнует, является ли это датой, вы, вероятно, должны убедиться, что это не число:
Function Bar(Var As Variant)
If IsDate(Var) And Not IsNumeric(Var) Then
Bar = "This is a date"
Else
Bar = "This is something else"
End If
End Function
?Bar("12:50") --> This is a date
?Bar("12.50") --> This is something else
Как @Deanna указал в комментарии ниже, поведение CDate()
также ненадежно. Его результаты варьируются в зависимости от того, передана ли строка или число:
?CDate(0.5) --> 12:00:00 PM
?CDate("0.5") --> 12:05:00 AM
Конечные и начальные нули значимы, если число передается в виде строки:
?CDate(".5") --> 12:00:00 PM
?CDate("0.5") --> 12:05:00 AM
?CDate("0.50") --> 12:50:00 AM
?CDate("0.500") --> 12:00:00 PM
Поведение также изменяется по мере приближения десятичной части строки к 60-минутной отметке:
?CDate("0.59") --> 12:59:00 AM
?CDate("0.60") --> 2:24:00 PM
Суть в том, что если вам нужно преобразовать строки в дату / время, вам нужно знайте, в каком формате вы ожидаете их, а затем переформатируйте их соответствующим образом, прежде чем полагаться на CDate()
для их преобразования.