Comment insérer une date à une feuille de calcul Open XML?
-
04-10-2019 - |
Question
J'utilise Microsoft Open XML SDK 2 et je vais avoir une période très difficile d'insérer une date dans une cellule. Je peux insérer des numéros sans problème en définissant Cell.DataType = CellValues.Number
, mais quand je fais la même chose avec une date (Cell.DataType = CellValues.Date
) se bloque Excel 2010 (2007 aussi).
J'ai essayé de définir la valeur de Cell.Text
à de nombreux formats de date, ainsi que la date d'Excel / format numérique sans succès. J'ai aussi essayé de styles d'utilisation, en supprimant l'attribut type, ainsi que beaucoup d'autres pizzas j'ai jeté au mur ...
point Quelqu'un peut-il me un exemple d'insérer une date dans une feuille de calcul?
La solution
Vous devez convertir DateTime
à double
en utilisant la fonction ToOADate
i.e.:.
DateTime dtValue = DateTime.Now;
string strValue = dtValue.ToOADate().ToString(CultureInfo.InvariantCulture);
puis définissez comme CellValue
Cell cell;
cell.DataType = new EnumValue<CellValues>(CellValues.Date);
cell.CellValue = new CellValue(strValue);
Souvenez-vous de la cellule de format à l'aide DateTime
le formatage, sinon vous verrez valeur double
, ne date pas.
Autres conseils
J'ai utilisé le code fourni par Andrew J, mais le DataType
de CellValues.Date
produit un xlsx fichier corrompu pour moi.
Le DataType
de CellValues.Number
a bien fonctionné pour moi (Ne pas oublier de NumberFormatId
ensemble) :
cell.DataType = new EnumValue<CellValues>(CellValues.Number);
Mon code complet:
DateTime valueDate = DateTime.Now;
string valueString = valueDate.ToOADate().ToString();
CellValue cellValue = new CellValue(valueString);
Cell cell = new Cell();
cell.DataType = new EnumValue<CellValues>(CellValues.Number);
cell.StyleIndex = yourStyle; //StyleIndex of CellFormat cfBaseDate -> See below
cell.Append(cellValue);
Mon CellFormat pour cette cellule dans les regards Stylesheet comme:
CellFormat cfBaseDate = new CellFormat() {
ApplyNumberFormat = true,
NumberFormatId = 14, //14 is a localized short Date (d/m/yyyy) -> See list below
//Some further styling parameters
};
Si vous souhaitez formater votre date d'une autre manière, voici une liste de tous par défaut Excel NumberFormatId
de
ID FORMAT CODE 0 General 1 0 2 0.00 3 #,##0 4 #,##0.00 9 0% 10 0.00% 11 0.00E+00 12 # ?/? 13 # ??/?? 14 d/m/yyyy 15 d-mmm-yy 16 d-mmm 17 mmm-yy 18 h:mm tt 19 h:mm:ss tt 20 H:mm 21 H:mm:ss 22 m/d/yyyy H:mm 37 #,##0 ;(#,##0) 38 #,##0 ;[Red](#,##0) 39 #,##0.00;(#,##0.00) 40 #,##0.00;[Red](#,##0.00) 45 mm:ss 46 [h]:mm:ss 47 mmss.0 48 ##0.0E+0 49 @
Source de la liste: https://github.com/ClosedXML/ClosedXML / wiki / NumberFormatId-Lookup Table
Je sais que cette liste est de ClosedXML, mais il est le même dans OpenXML.
Lors de la création SpreadsheetDocument
à partir de zéro, pour Date
mise en forme au travail, Stylesheet
minimum doit être créé.
critiques sont ces quelques lignes:
new CellFormat
{
NumberFormatId = 14,
ApplyNumberFormat = true
})
class Full Stylesheet
:
using (var spreadSheet = SpreadsheetDocument.Create(ms, SpreadsheetDocumentType.Workbook))
{
// Workbook
var workbookPart = spreadSheet.AddWorkbookPart();
workbookPart.Workbook =
new Workbook(new Sheets(new Sheet { Name = "Sheet1", SheetId = (UInt32Value) 1U, Id = "rId1" }));
// Add minimal Stylesheet
var stylesPart = spreadSheet.WorkbookPart.AddNewPart<WorkbookStylesPart>();
stylesPart.Stylesheet = new Stylesheet
{
Fonts = new Fonts(new Font()),
Fills = new Fills(new Fill()),
Borders = new Borders(new Border()),
CellStyleFormats = new CellStyleFormats(new CellFormat()),
CellFormats =
new CellFormats(
new CellFormat(),
new CellFormat
{
NumberFormatId = 14,
ApplyNumberFormat = true
})
};
// Continue creating `WorksheetPart`...
Après Stylesheet
est ajouté, DateTime
peut être formaté:
if (valueType == typeof(DateTime))
{
DateTime date = (DateTime)value;
cell.CellValue = new CellValue(date.ToOADate().ToString(CultureInfo.InvariantCulture));
// "StyleIndex" is "1", because "NumberFormatId=14"
// is in the 2nd item of `CellFormats` array.
cell.StyleIndex = 1;
}
Notez que la valeur StyleIndex
dépend de l'ordre des éléments de CellFormat
dans le tableau de CellFormats
ou l'objet Stylesheet
. Dans cet exemple, l'article de NumberFormatId = 14
sur le 2ème élément du tableau.
Il y a 2 façons de stocker les dates dans OpenXml; en attribuant un numéro (en utilisant ToOADate
) et le réglage de la DataType
à Number
ou en écrivant un ISO 8601 formaté la date et le réglage de la DataType
à Date
. Notez que le DataType
par défaut est Number
donc si vous allez avec la première option, vous ne devez pas régler le DataType
.
Quelle que soit la méthode choisie, vous devrez définir le style comme Excel affiche les deux méthodes identiques. Le code suivant montre un exemple d'écrire une date en utilisant le format Number
(avec et sans mettre explicitement le DataType
) et en utilisant le format ISO 8601.
using (SpreadsheetDocument document = SpreadsheetDocument.Create(filename, SpreadsheetDocumentType.Workbook))
{
//fluff to generate the workbook etc
WorkbookPart workbookPart = document.AddWorkbookPart();
workbookPart.Workbook = new Workbook();
var worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
worksheetPart.Worksheet = new Worksheet();
Sheets sheets = workbookPart.Workbook.AppendChild(new Sheets());
Sheet sheet = new Sheet() { Id = workbookPart.GetIdOfPart(worksheetPart), SheetId = 1, Name = "Sheet" };
sheets.Append(sheet);
workbookPart.Workbook.Save();
var sheetData = worksheetPart.Worksheet.AppendChild(new SheetData());
//add the style
Stylesheet styleSheet = new Stylesheet();
CellFormat cf = new CellFormat();
cf.NumberFormatId = 14;
cf.ApplyNumberFormat = true;
CellFormats cfs = new CellFormats();
cfs.Append(cf);
styleSheet.CellFormats = cfs;
styleSheet.Borders = new Borders();
styleSheet.Borders.Append(new Border());
styleSheet.Fills = new Fills();
styleSheet.Fills.Append(new Fill());
styleSheet.Fonts = new Fonts();
styleSheet.Fonts.Append(new Font());
workbookPart.AddNewPart<WorkbookStylesPart>();
workbookPart.WorkbookStylesPart.Stylesheet = styleSheet;
CellStyles css = new CellStyles();
CellStyle cs = new CellStyle();
cs.FormatId = 0;
cs.BuiltinId = 0;
css.Append(cs);
css.Count = UInt32Value.FromUInt32((uint)css.ChildElements.Count);
styleSheet.Append(css);
Row row = new Row();
DateTime date = new DateTime(2017, 6, 24);
/*** Date code here ***/
//write an OADate with type of Number
Cell cell1 = new Cell();
cell1.CellReference = "A1";
cell1.CellValue = new CellValue(date.ToOADate().ToString());
cell1.DataType = new EnumValue<CellValues>(CellValues.Number);
cell1.StyleIndex = 0;
row.Append(cell1);
//write an OADate with no type (defaults to Number)
Cell cell2 = new Cell();
cell2.CellReference = "B1";
cell2.CellValue = new CellValue(date.ToOADate().ToString());
cell1.StyleIndex = 0;
row.Append(cell2);
//write an ISO 8601 date with type of Date
Cell cell3 = new Cell();
cell3.CellReference = "C1";
cell3.CellValue = new CellValue(date.ToString("yyyy-MM-dd"));
cell3.DataType = new EnumValue<CellValues>(CellValues.Date);
cell1.StyleIndex = 0;
row.Append(cell3);
sheetData.AppendChild(row);
worksheetPart.Worksheet.Save();
}
Utiliser la chaîne partagée:
// assuming it's the first item in the shared string table
SharedStringItem sharedStringItem = new SharedStringItem();
Text text = new Text();
text.Text = DateTime.Today.ToString("MM/dd/yyyy hh:mm");
sharedStringTable1.Append(sharedStringItem);
Puis, plus tard dans le code:
// assuming it's the first item in the shared string table
var cell = new Cell {CellReference = "A1", DataType = CellValues.SharedString};
var cellValue = new CellValue("0");
cell.Append(cellValue);
La suivante a fonctionné pour nous:
c.CellValue = new CellValue(datetimeValue).ToOADate().ToString());
c.DataType = CellValues.Number;
c.StyleIndex = StyleDate;
Définissez le DataType à CellValues.Number puis assurez-vous de formater la cellule avec l'indice de style approprié des CellFormats. Dans notre cas, nous construisons une feuille de style au sein de la feuille de calcul, et StyleDate est un indice dans les CellFormats dans la feuille de style.
a) Obtenez la compatibilité avec Excel 2007, Excel 2007 Viewer, etc. b) DateTime avant 01/01/1900 écriture sous forme de chaîne.
DateTime dat = (DateTime)dr[dc.ColumnName];
//Not working with Excel 2007
//cell.DataType = CellValues.Date;
//cell.CellValue = new CellValue(dat.ToString("s"));
double diff = (dat - new DateTime(1899, 12, 30)).TotalSeconds / 86400.0;
if (diff > 1)
{
cell.DataType = CellValues.Number;
cell.CellValue = new CellValue(diff.ToString().Replace(",", "."));
if (dat.TimeOfDay == new TimeSpan(0))
{
cell.StyleIndex = 2; //Custom Style NumberFormatId = 14 ( d/m/yyyy)
}
else
{
cell.StyleIndex = 1; //Custom Style NumberFormatId = 22 (m/d/yyyy H:mm)
}
}
else
{
cell.DataType = CellValues.String;
cell.CellValue = new CellValue(dat.ToString());
}