By: Aaron Bertrand | Updated: 2015-10-13 | Comments (10) | Related: > Dates
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:
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
- See these related tips and other resources:
- Date and Time Conversions Using SQL Server
- SQL Server 2008 Date and Time Data Types
- Determine SQL Server Date and Time with DATEPART and DATENAME Functions
- Custom Date and Time Format Strings (MSDN)
- Conversion Functions (Transact-SQL) (MSDN)
- FORMAT (Transact-SQL) (MSDN)
- FORMAT() is nice and all, but…
About the author
This author pledges the content of this article is based on professional experience and not AI generated.
View all my tips
Article Last Updated: 2015-10-13