Does anyone happen to know if there is a token I can add to my csv for a certain field so Excel doesn\'t try to convert it to a date?
I\'m trying to write a .csv fil
If you put an inverted comma at the start of the field, it will be interpreted as text.
Example:
25/12/2008
becomes '25/12/2008
You are also able to select the field type when importing.
I know this is an old question, but the problem is not going away soon. CSV files are easy to generate from most programming languages, rather small, human-readable in a crunch with a plain text editor, and ubiquitous.
The problem is not only with dates in text fields, but anything numeric also gets converted from text to numbers. A couple of examples where this is problematic:
which sometimes can start with one or more zeroes (0), which get thrown away when converted to numeric. Or the value contains characters that can be confused with mathematical operators (as in dates: /, -).
Two cases that I can think of that the "prepending =" solution, as mentioned previously, might not be ideal is
If one pre/appends a non-numeric and/or non-date character in the value, the value will be recognized as text and not converted. A non-printing character would be good as it will not alter the displayed value. However, the plain old space character (\s, ASCII 32) doesn't work for this as it gets chopped off by Excel and then the value still gets converted. But there are various other printing and non-printing space characters that will work well. The easiest however is to append (add after) the simple tab character (\t, ASCII 9).
Benefits of this approach:
If there's a reason you don't want to use the tab, look in an Unicode table for something else suitable.
might be to generate XML files, for which a certain format also is accepted for import by newer MS Excel versions, and which allows a lot more options similar to .XLS format, but I don't have experience with this.
So there are various options. Depending on your requirements/application, one might be better than another.
It needs to be said that newer versions (2013+) of MS Excel don't open the CSV in spreadsheet format any more - one more speedbump in one's workflow making Excel less useful... At least, instructions exist for getting around it. See e.g. this Stackoverflow: How to correctly display .csv files within Excel 2013? .
This is a only way I know how to accomplish this without messing inside the file itself. As usual with Excel, I learned this by beating my head on the desk for hours.
Change the .csv file extension to .txt; this will stop Excel from auto-converting the file when it's opened. Here's how I do it: open Excel to a blank worksheet, close the blank sheet, then File => Open and choose your file with the .txt extension. This forces Excel to open the "Text Import Wizard" where it'll ask you questions about how you want it to interpret the file. First you choose your delimiter (comma, tab, etc...), then (here's the important part) you choose a set columns of columns and select the formatting. If you want exactly what's in the file then choose "Text" and Excel will display just what's between the delimiters.
I made this vba macro which basically formats the output range as text before pasting the numbers. Works perfect for me when i want to paste values such as 8/11, 23/6, 1/3 etc. without Excel interpreting them as dates.
Sub PasteAsText()
' Created by Lars-Erik Sørbotten, 2017-09-17
Call CreateSheetBackup
Columns(ActiveCell.Column).NumberFormat = "@"
Dim DataObj As MSForms.DataObject
Set DataObj = New MSForms.DataObject
DataObj.GetFromClipboard
ActiveCell.PasteSpecial
End Sub
I'm very interested in knowing if this works for other people as well. I've been looking for a solution to this problem for a while, but I haven't seen a quick vba solution to it before which didn't include inserting ' in front of the input text. This code retains the data in its original form.
I know this is an old thread. For the ones like me, who still have this problem using office 2013 via powershell com object can use the opentext method. The problem is that this method has many arguments, that are sometimes mutual exclusive. To resolve this issue you can use the invoke-namedparameter method introduced in this post. An example would be
$ex = New-Object -com "Excel.Application"
$ex.visible = $true
$csv = "path\to\your\csv.csv"
Invoke-NamedParameter ($ex.workbooks) "opentext" @{"filename"=$csv; "Semicolon"= $true}
Unfortunately I just discovered that this method somehow breaks the csv parsing when cells contain linebreaks. This is supported by csv but microsofts implementation seems to be bugged. Also it did somehow not detect german specific chars. Giving it the correct culture did not change this behaveiour. All files (csv and script) are saved with utf8 encoding. First I wrote the following code to insert the csv cell by cell.
$ex = New-Object -com "Excel.Application"
$ex.visible = $true;
$csv = "path\to\your\csv.csv";
$ex.workbooks.add();
$ex.activeWorkbook.activeSheet.Cells.NumberFormat = "@";
$data = import-csv $csv -encoding utf8 -delimiter ";";
$row = 1;
$data | %{ $obj = $_; $col = 1; $_.psobject.properties.Name |%{if($row -eq1){$ex.ActiveWorkbook.activeSheet.Cells.item($row,$col).Value2= $_ };$ex.ActiveWorkbook.activeSheet.Cells.item($row+1,$col).Value2 =$obj.$_; $col++ }; $row++;}
But this is extremly slow, which is why i looked for an alternative. Appearently Excel allows you to set the values of a range of cells with a matrix. So i used the algorithm in this blog to transform the csv in a multiarray.
function csvToExcel($csv,$delimiter){
$a = New-Object -com "Excel.Application"
$a.visible = $true
$a.workbooks.add()
$a.activeWorkbook.activeSheet.Cells.NumberFormat = "@"
$data = import-csv -delimiter $delimiter $csv;
$array = ($data |ConvertTo-MultiArray).Value
$starta = [int][char]'a' - 1
if ($array.GetLength(1) -gt 26) {
$col = [char]([int][math]::Floor($array.GetLength(1)/26) + $starta) + [char](($array.GetLength(1)%26) + $Starta)
} else {
$col = [char]($array.GetLength(1) + $starta)
}
$range = $a.activeWorkbook.activeSheet.Range("a1:"+$col+""+$array.GetLength(0))
$range.value2 = $array;
$range.Columns.AutoFit();
$range.Rows.AutoFit();
$range.Cells.HorizontalAlignment = -4131
$range.Cells.VerticalAlignment = -4160
}
function ConvertTo-MultiArray {
param(
[Parameter(Mandatory=$true, Position=1, ValueFromPipeline=$true)]
[PSObject[]]$InputObject
)
BEGIN {
$objects = @()
[ref]$array = [ref]$null
}
Process {
$objects += $InputObject
}
END {
$properties = $objects[0].psobject.properties |%{$_.name}
$array.Value = New-Object 'object[,]' ($objects.Count+1),$properties.count
# i = row and j = column
$j = 0
$properties |%{
$array.Value[0,$j] = $_.tostring()
$j++
}
$i = 1
$objects |% {
$item = $_
$j = 0
$properties | % {
if ($item.($_) -eq $null) {
$array.value[$i,$j] = ""
}
else {
$array.value[$i,$j] = $item.($_).tostring()
}
$j++
}
$i++
}
$array
}
}
csvToExcel "storage_stats.csv" ";"
You can use above code as is it should convert any csvs into excel. Just change the path to the csv and the delimiter character at the bottom.
A workaround using Google Drive (or Numbers if you're on a Mac):
Alternatively if you're on a Mac for step 3 you can open the data in Numbers.