> ## Content Index
> Fetch the complete content index at: https://nolongerset.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Dt() Function v3: Refactoring with Automated Tests
- URL: https://nolongerset.com/dt-function-v3/
- Published: 2022-12-21T03:57:32.000Z
- Updated: 2026-05-08T12:52:47.000Z
- Description: Reader Brenda Bachtold provides a more readable version of my date-wrapping function. Automated doc tests prove that her version functions the same as mine.
- Author: Mike Wolfe
- Tags: Code Library, #StringFunctions, #Import 2026-05-20 02:59

Yesterday, I [published an update](https://nolongerset.com/dt-function-v2/) to my SQL date-wrapping function, **Dt()**.

Included with the code was a set of 11 [Python-inspired doc tests](https://nolongerset.com/python-inspired-doc-tests-in-vba/). I love the doc tests concept for a few reasons:

- It's a concise and effective way to show how a function works.
- The documentation doesn't go stale.
- Writing tests is simple and easy.
- It allows for safe and confident refactoring.

That last feature is the one I want to highlight with today's article.

## Dt() Function v2: Functional But Hard to Read

For reference, here is version 2 of my **Dt()** function:

```vba
Function Dt(DateVal As Variant) As String
    Const Pound As String = "#"
    If IsNull(DateVal) Or IsEmpty(DateVal) Then
        Dt = "Null"
    Else
        Dt = Pound & Format(DateVal, "yyyy-mm-dd hh:nn:ss") & Pound
    End If
    
    If Dt Like "[#]1899-12-30 *" Then
        'Strip out the epoch date from a time-only value
        Dt = Replace(Dt, "1899-12-30 ", "")
    Else
        'Strip out the time portion from a date-only value
        Dt = Replace(Dt, " 00:00:00", "")
    End If
End Function
```

It's functional, but the logic is a bit convoluted.

## Dt() Function v3: A More Readable Version

In the [comments section](https://nolongerset.com/dt-function-v2/#commento-37d40d6949b0a9b34ce623602132e6b96d08e4fbfe7a736370faa3ee637d4a26) of that article, reader Brenda Bachtold posted a more readable version of the function:

```vba
Public Function Dt(d As Variant) As String
    Const Pound As String = "#"
    
    Select Case True
        'null or empty
        Case IsNull(d), IsEmpty(d)
           Dt = "Null"
          
        'time only
        Case Format(d, "yyyy-mm-dd") = "1899-12-30"
            Dt = Pound & Format(d, "hh:nn:ss") & Pound
          
        'date only
        Case Format(d, "hh:nn:ss") = "00:00:00"
            Dt = Pound & Format(d, "yyyy-mm-dd") & Pound
        
        Case Else
            Dt = Pound & Format(d, "yyyy-mm-dd hh:nn:ss") & Pound
    End Select
End Function
```

My first thought when I saw that function was that it's a lot easier to follow than my version. My second thought was, "I wonder if it produces identical results, especially when it comes to edge cases?"

Luckily for me, I didn't have to rely (entirely) on my ability to translate the logic in my head to know that Brenda's refactored version was a drop-in replacement for my version of the function. **All I had to do was copy and paste her code over mine and execute the doc tests.** As long as all the tests passed, then I could be sure that her version was functionally equivalent to mine.

As I expected, all eleven tests passed:

![](https://storage.ghost.io/c/eb/d7/ebd732c1-5f03-4f07-b386-5d08557e15c9/content/images/2022/12/image-42.png)

## The Value of Automated Tests

This refactoring demonstrates the value of automated tests. 

This was a relatively simple function, but you can see how automated tests would give you the confidence to tackle refactoring projects on some rather complex code.

In this case, the automated tests are [Python-inspired doc tests](https://nolongerset.com/python-inspired-doc-tests-in-vba/), but the concept applies equally to other kinds of automated tests, such as unit tests or integration tests. By having an existing set of tests that validate our expected outputs, we can safely and confidently refactor our code without worrying about breaking backwards compatibility.

**As long as the tests pass, the implementation does not matter.**

## A Caveat Regarding Test Coverage

One thing to keep in mind is that the quality and quantity of your tests matter a great deal when it comes to refactoring with confidence.

The more edge cases you can include in your test suite, the more confident you can be in your refactoring. Along those same lines, if your calling code relies on some specific output for a given set of inputs, you'll want to document that functionality with a test. That way, if you refactor that function at some point in the future, you can be sure that the refactored version will preserve that functionality.

## Full Code

Here's the full code with refactoring credit given to Brenda Bachtold. If you want to verify the doc tests, be sure to grab a copy of my `DocTests` routine [here](https://nolongerset.com/python-inspired-doc-tests-in-vba/).

```vba
' ----------------------------------------------------------------
' Procedure : Dt
' Updated   : 2022-12-20  (v3)
' Author    : Mike Wolfe (refactored by Brenda Bachtold)
' Source    : https://nolongerset.com/dt-function-v3/
' Purpose   : Wraps date values in Access date literal tokens (#)
'               and converts values to ISO string formatting for
'               maximum compatibility across back-end databases and locales
' Notes     - If passed a Null value this function will return the text 'Null';
'               this allows the function to be used to build SQL conditionals
'               without extra handling
'           - Date-only values do not include a time portion
'           - Time-only values do not include a date portion
'               (this avoids subtle bugs due to epoch differences)
' ----------------------------------------------------------------
'>>> Dt(#19-Dec-2022#)
' #2022-12-19#
'>>> Dt(#19-Dec-2022 6:00 PM#)
' #2022-12-19 18:00:00#
'>>> Dt(#6:00 PM#)
' #18:00:00#
'>>> Dt("December 19, 2022")
' #2022-12-19#
'>>> Dt(0)
' #00:00:00#
'>>> Dt(#12 AM#)
' #00:00:00#
'>>> Dt(DateSerial(2018, 2, 4))
' #2018-02-04#
'>>> Dt("Gibberish")
' #Gibberish#
'>>> IsNull(Dt(Null))
' False
'>>> "_" & Dt(Null) & "_"
' _Null_
'>>> Dt("Null")
' #Null#
Public Function Dt(d As Variant) As String
    Const Pound As String = "#"

    Select Case True
        'null or empty
        Case IsNull(d), IsEmpty(d)
           Dt = "Null"

        'time only
        Case Format(d, "yyyy-mm-dd") = "1899-12-30"
            Dt = Pound & Format(d, "hh:nn:ss") & Pound

        'date only
        Case Format(d, "hh:nn:ss") = "00:00:00"
            Dt = Pound & Format(d, "yyyy-mm-dd") & Pound

        Case Else
            Dt = Pound & Format(d, "yyyy-mm-dd hh:nn:ss") & Pound

    End Select
End Function
```

### Referenced articles

[Python-inspired Doc Tests in VBADoc tests are not a replacement for unit or integration testing. But they do provide the best return on investment (ROI) of any type of test, mostly because the effort to write them is near zero.![](https://nolongerset.com/favicon.png)No Longer SetMike Wolfe![](https://storage.ghost.io/c/eb/d7/ebd732c1-5f03-4f07-b386-5d08557e15c9/content/images/2020/09/20200921_173427---gbm18---.png)](https://nolongerset.com/python-inspired-doc-tests-in-vba/)

[Dt() Function v2: Handling Time-Only Date ValuesAn important bug fix for my previously published date-wrapping VBA function that addresses an issue integrating time-only values with SQL Server.![](https://nolongerset.com/favicon.png)No Longer SetMike Wolfe![](https://storage.ghost.io/c/eb/d7/ebd732c1-5f03-4f07-b386-5d08557e15c9/content/images/2022/12/Date-Wrapping-Function-v2.jpeg)](https://nolongerset.com/dt-function-v2/)

*Cover image created with [Microsoft Designer](https://designer.microsoft.com/)*