Build a cheat sheet for SQL Server date and time formats

Problem

I’m a forgetful person, and I often have to look up which style number for convert will be easiest to achieve a certain output. Now, to be completely honest, I am mostly against doing any type of string formatting inside the database – this is generally better handled by the presentation tier. But, I recognize that sometimes this is done in a view that serves multiple applications or reports, or the powers that be have simply dictated that the database will be doing this work. In these cases, it can be handy to have a “cheat sheet” that shows you all of the output styles available through the CONVERT() function.

Solution

I’ve found that it is not too difficult to build a script that can be re-used to generate such a cheat sheet. Let’s first determine all the style numbers that are valid. We can do this by attempting conversion to all styles between 0 and 255, and insert into a #temp table the ones that don’t yield an error:

SET NOCOUNT ON;
DECLARE @sql NVARCHAR(MAX), @v VARCHAR(30), @d DATETIME2(7);
SET @sql = N'';
-- a random date/time, making sure no single digits for any
-- date parts as these can truncate length of output:
SET @d = '2015-12-31T22:25:59.7901245';
CREATE TABLE #s(style VARCHAR(3));
DECLARE @s INT = 0;
WHILE @s <= 255
BEGIN
  BEGIN TRY;
    SET @sql = N'SELECT @v = CONVERT(VARCHAR(30), @d, ' + RTRIM(@s) + ');';
EXEC sys.sp_executesql @sql, N'@v VARCHAR(30), @d DATETIME2(7)', @v, @d;
    INSERT #s(style) VALUES(@s); 
  END TRY
  BEGIN CATCH;
    SET @sql = N'';
  END CATCH;
  SET @s = @s + 1;
END

Now, the #temp table is populated with all of the styles that produced valid output and no error (42 in total, including styles 130 and 131 which have Hijri output). Note that this code is meant to work on all versions of SQL Server 2005 and up; for 2012 and up, you could do something much simpler, like:

SET @sql = N'';
;WITH x(rn) AS 
(
  SELECT TOP (256) CONVERT(VARCHAR(3), ROW_NUMBER() OVER (ORDER BY name) - 1)
  FROM sys.all_objects ORDER BY name
)
SELECT @sql = @sql + N'INSERT #s SELECT ' + rn + ' FROM 
  (SELECT n = TRY_CONVERT(VARCHAR(30),@d,' + rn + ')) AS x 
  WHERE n IS NOT NULL;' FROM x;
EXEC sys.sp_executesql @sql, N'@d DATETIME2(7)', @d;

Next, we can generate some dynamic SQL that will output each style number, the expression that is used to apply that style to the conversion of a date/time variable, and the actual output of that expression.

SET @sql = N'';
SELECT @sql = @sql + N' UNION ALL SELECT [style #] = ' 
  + style + ', expression = N''CONVERT(CHAR(''
    +RTRIM(LEN(CONVERT(VARCHAR(30), @d, ' + style + ')))
+''), @d, ' + style + ')'',
[output] = CONVERT(VARCHAR(30), @d, ' + style + ')'
FROM #s;
SET @sql = STUFF(@sql, 1, 11, N'') + N';';
EXEC sys.sp_executesql @sql, N'@d DATETIME2(7)', @d;

Full output:

style #

expression

output
0

CONVERT(CHAR(19), @d, 0)

Dec 31 2015 10:25PM
1

CONVERT(CHAR(8), @d, 1)

12/31/15
2

CONVERT(CHAR(8), @d, 2)

15.12.31
3

CONVERT(CHAR(8), @d, 3)

31/12/15
4

CONVERT(CHAR(8), @d, 4)

31.12.15
5

CONVERT(CHAR(8), @d, 5)

31-12-15
6

CONVERT(CHAR(9), @d, 6)

31 Dec 15
7

CONVERT(CHAR(10), @d, 7)

Dec 31, 15
8

CONVERT(CHAR(8), @d, 8)

22:25:59
9

CONVERT(CHAR(30), @d, 9)

Dec 31 2015 10:25:59.7901245PM
10

CONVERT(CHAR(8), @d, 10)

12-31-15
11

CONVERT(CHAR(8), @d, 11)

15/12/31
12

CONVERT(CHAR(6), @d, 12)

151231
13

CONVERT(CHAR(28), @d, 13)

31 Dec 2015 22:25:59.7901245
14

CONVERT(CHAR(16), @d, 14)

22:25:59.7901245
20

CONVERT(CHAR(19), @d, 20)

2015-12-31 22:25:59
21

CONVERT(CHAR(27), @d, 21)

2015-12-31 22:25:59.7901245
22

CONVERT(CHAR(20), @d, 22)

12/31/15 10:25:59 PM
23

CONVERT(CHAR(10), @d, 23)

2015-12-31
24

CONVERT(CHAR(8), @d, 24)

22:25:59
25

CONVERT(CHAR(27), @d, 25)

2015-12-31 22:25:59.7901245
100

CONVERT(CHAR(19), @d, 100)

Dec 31 2015 10:25PM
101

CONVERT(CHAR(10), @d, 101)

12/31/2015
102

CONVERT(CHAR(10), @d, 102)

2015.12.31
103

CONVERT(CHAR(10), @d, 103)

31/12/2015
104

CONVERT(CHAR(10), @d, 104)

31.12.2015
105

CONVERT(CHAR(10), @d, 105)

31-12-2015
106

CONVERT(CHAR(11), @d, 106)

31 Dec 2015
107

CONVERT(CHAR(12), @d, 107)

Dec 31, 2015
108

CONVERT(CHAR(8), @d, 108)

22:25:59
109

CONVERT(CHAR(30), @d, 109)

Dec 31 2015 10:25:59.7901245PM
110

CONVERT(CHAR(10), @d, 110)

12-31-2015
111

CONVERT(CHAR(10), @d, 111)

2015/12/31
112

CONVERT(CHAR(8), @d, 112)

20151231
113

CONVERT(CHAR(28), @d, 113)

31 Dec 2015 22:25:59.7901245
114

CONVERT(CHAR(16), @d, 114)

22:25:59.7901245
120

CONVERT(CHAR(19), @d, 120)

2015-12-31 22:25:59
121

CONVERT(CHAR(27), @d, 121)

2015-12-31 22:25:59.7901245
126

CONVERT(CHAR(27), @d, 126)

2015-12-31T22:25:59.7901245
127

CONVERT(CHAR(27), @d, 127)

2015-12-31T22:25:59.7901245
130

CONVERT(CHAR(30), @d, 130)

20 ???? ????? 1437 10:25:59.79
131

CONVERT(CHAR(29), @d, 131)

20/03/1437 10:25:59.7901245PM

Create Date / Time Formats in HTML format

Your next question is probably, what if I want to present this output on a web page, and want to generate an HTML table like the one above? No problem, we can do that with a few minor changes to the dynamic SQL:

SET @sql = N'SELECT ''<table><tr><th>style #<th>expression<th>output</tr>''';
SELECT @sql = @sql + N' UNION ALL SELECT ''<tr><td>' 
  + style + '<td>CONVERT(CHAR(''
    +RTRIM(LEN(CONVERT(VARCHAR(30), @d, ' + style + ')))
+''), @d, ' + style + ')<td>'' + 
CONVERT(VARCHAR(30), @d, ' + style + ')+''</tr>'''
FROM #s;
SET @sql = @sql + ' UNION ALL SELECT ''</table>'';';
EXEC sys.sp_executesql @sql, N'@d DATETIME2(7)', @d;

Truncated output:

AB CheatSheet

Using FORMAT to format dates

In any case, that's a pretty exhaustive set, but there may be some formats you want that are not represented above. While I typically do not recommend the FORMAT() function because of the demonstrable overhead of using the CLR, it can be used in a pinch when you have no other options. FORMAT() was introduced in SQL Server 2012, and behaves similarly to its C# equivalent (documented here). So, you can do things like this without having to memorize any style numbers:

SELECT FORMAT(@d, 'MMMM, yyyy'),       --> December, 2015
       FORMAT(@d, 'MMM-yyyy'),         --> Dec-2015
       FORMAT(@d, 'dddd MMMM d'),      --> Thursday December 31
       FORMAT(@d, 'yyyy -> MM -> dd'), --> 2015 -> 12 -> 31
       FORMAT(@d, 'h\h, m\m');         --> 10h, 25m

But I will stress again that, while this may seem more convenient than cobbling together multiple outputs from CONVERT(), DATEPART(), or DATENAME(), the performance impact can be significant at high volumes.

Don't forget to clean up:

DROP TABLE #s;

Summary

Memorizing meaningless style numbers can be a pain, but with a little creative thinking, you can build yourself a cheat sheet in no time. And you can repeat this process with different date inputs to see differences in output, or on different versions of SQL Server (since supported style numbers may vary by version). Or you could just bookmark this page. :-)

Next Steps

Leave a Reply

Your email address will not be published. Required fields are marked *