2

I have an annoying issue working with SQL Server DATETIME objects in Excel 2013. The problem has been stated several times here in SO, and I know that the work around is to just reformat the DATETIME objects in Excel by doing this:

  • Right click the cell
  • Choose Format Cells
  • Choose Custom
  • In the Type: input field enter yyyy-mm-dd hh:mm:ss.000

This works fine BUT I loathe having to do this every time. Is there a permanent work around to this aside from creating macros? I need to maintain the granularity of the DATETIME object so I cannot use a SMALLDATETIME. I am currently using Microsoft SQL Server Management Studio 2008 r2 on a win7 machine.

Thanks in advance.

-Stelio K.

StelioK
  • 1,771
  • 1
  • 11
  • 21
  • How are you bringing it into Excel? Because that can be done by macro as well, shrinking all your steps to a button-click. There's also data source linking which comes into a table, which you can format. – n8. Sep 12 '16 at 22:48
  • This is usually done for ad-hoc requests, and I usually just copy and paste my results from sql sever into excel. – StelioK Sep 12 '16 at 22:58
  • 1
    It doesn't seem like you can modify Excel's default paste behavior without a bunch of other hassles. Annoying as it is, I think that's your path of least resistance. – n8. Sep 12 '16 at 23:22
  • That's what I was afraid of. Thanks @n8 – StelioK Sep 13 '16 at 00:12
  • Please post the actual code. SQL Server `datetime` fields have no format and no such problem was reported in SO. What happens *every* time is that the user's code performs some unexpected string formatting. You can avoid the problem by using a library like EPPlus or the OpenXML SDK to create proper Excel files that store DateTime values correctly – Panagiotis Kanavos Sep 13 '16 at 12:19
  • @n8 there is no "default paste behavior" nor is there a need for macros. If you create an XLSX file correctly (eg with the SDK or EPPlus), dates are stored correctly. If you convert it to text, or copy-paste it (thus converting it to text), you lose the type information before the data reaches the spreadsheet – Panagiotis Kanavos Sep 13 '16 at 12:23
  • 1
    Saving a special spreadsheet is one step, converting to datetimes is one step. And if they are all ad-hoc queries then the locations of the datetime columns are variable, so tell me how your solution solves the problem. – n8. Sep 13 '16 at 15:40
  • 1
    And there IS "default paste behavior" if you consider what the words mean. It's what Excel does by default when you paste into it. It seems to me that your input is not constructive. – n8. Sep 13 '16 at 15:44
  • @PanagiotisKanavos There is no need to paste my code, this behavior is exhibited whenever I use/cast anything datetime. Can you please enlighten me? How does one create an xlsx file correctly? – StelioK Sep 13 '16 at 21:35
  • @StelioK please post your code. An Excel sheet that loads data through a data connection requires different coding from a sheet is generated on the server. – Panagiotis Kanavos Sep 14 '16 at 07:51
  • @n8 please consider that copy/paste isn't used to generate Excel sheets, especially server-side. Also consider that what you call "default behaviour" is Excel trying to import unknown text, using the user's localization settings. Which is why eg in many European countries `,` isn't recognized as a column separator - `;` is the list separator in France, German, Greece etc – Panagiotis Kanavos Sep 14 '16 at 07:54
  • 2
    @StelioK you (or the end users) can use Power Query in any edition of Excel 2013 to perform any type of manipulation you want, including applying types and formats. There's no need to use code. – Panagiotis Kanavos Sep 14 '16 at 10:12
  • It does require a change of behavior to use PowerQuery but that's a good option. Not necessarily fewer steps, but does include a host of features that StelioK could benefit from. – n8. Sep 14 '16 at 20:09

1 Answers1

0

Without any code it's hard to guess how the data gets from SQL Server to Excel. I assume it's not through a data connection, because Excel wouldn't have any issues displaying the data as dates directly.

What about data connections?

Excel doesn't support any kind of formatting or any useful designer for that matter, when working with data connections only. That functionality is provided by Power Query or the PivotTable designer. Power Query is integrated in Excel 2016 and available as a download for Excel 2010+.

Why you need to format dates

Excel doesn't preserve type information. Everything is a string or number and its display is governed by the cell's format.

Dates are stored as decimals using the OLE Automation format - the integral part is the number of dates since 1900-01-01 and the fractional part is the time. This is why the System.DateTime has those FromOADate and ToOADate functions.

To create an Excel sheet with dates, you should set the cell format at the same time you generate the cell.

How to format cells

Doing this is relatively if you use the Open XML SDK or a library like EPPlus. The following example creates an Excel sheet from a list of customers:

static void Main(string[] args)
{
    var customers = new[]
    {
        new Customer("A",DateTime.Now),
        new Customer("B",DateTime.Today.AddDays(-1))
    };
    File.Delete("customers.xlsx");
    var newFile = new FileInfo(@"customers.xlsx");
    using (ExcelPackage pck = new ExcelPackage(newFile))
    {                
        var ws = pck.Workbook.Worksheets.Add("Content");

        // This format string *is* affected by the user locale!
        // and so is "mm-dd-yy"!
        ws.Column(2).Style.Numberformat.Format = "m/d/yy h:mm";

        //That's all it needs to load the data
        ws.Cells.LoadFromCollection(customers,true);
        pck.Save();
    }
}

The code uses the LoadFromCollection method to load a list of customers directly, without dealing with cells. true means that a header is generated.

There are equivalent methods to load data from other source: LoadFromDatatable, LoadFromDataReader, LoadFromText for CSV data and even LoadFromArrays for jagged object arrays.

The weird thing is that specifying the m/d/yy h:mm or mm-dd-yy format uses the user's locale for formatting, not the US format! That's because these formats are built-in into Excel and are treated as the locale-dependent formats. In the list of date formats they are shown with an asterisk, meaning they are affected by the user's locale.

The reason for this weirdness is that when Excel moved to the XML-based XLSX format 10 years ago, it preserved the quirks of the older XLS format for backward-compatibility reasons.

When EPPlus saves the xlsx file it detects them and stores a reference to the built-in format ID (22 and 14 respectively) instead of storing the entire format string.

Finding Format IDs

The list of standard format IDs is shown in the NumberingFormat element documentation page of the Open XML standard. Excel originally defined IDs 0 (General) through 49.

EPPlus doesn't allow setting the ID directly. It checks the format string and maps only the formats 0-49 as shown in the GetBfromBuildIdFromFormat method of ExcelNumberFormat. In order to get ID 22 we need to set the Format property to "m/d/yy h:mm"

Another trick is to check the stylesheets of an existing sheet. xlsx is a zipped package of XML files that can be opened with any decompression utility. The styles are stored in the xl\styles.xml file.

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
  • I stated in my OP that the data is simply copy and pasted. – StelioK Sep 14 '16 at 17:36
  • @StelioK you may consider putting it into your post as an edit instead of comments, specifically that you copy from the SSMS "Results" pane after running a query. I think my initial assumption is correct but with the myriad of options there is some open interpretation as to what you may be working in. – n8. Sep 14 '16 at 20:16
  • @StelioK You can use the Export Data wizard to generate Excel files directly if you want and avoid format guesses. As it is, you are simply copying text. Excel will recognize some formats but won't change styles based on a guess. – Panagiotis Kanavos Sep 15 '16 at 10:38