web-dev-qa-db-fra.com

Lire une date de xlsx en utilisant open xml sdk

J'ai une date au format "4/5/2011" (mois/jour/année) dans un fichier xlsx dans l'une des cellules. J'essaie d'analyser le fichier et de charger ces données dans certaines classes.

Jusqu'ici, la partie où j'analyse la cellule ressemble à ceci:

string cellValue = cell.InnerText;
if (cell.DataType != null)
{
    switch (cell.DataType.Value)
    {
        case CellValues.SharedString:
            // get string from shared string table
            cellValue = this.GetStringFromSharedStringTable(int.Parse(cellValue));
            break;
    }
}

J'espérais que cette date serait une cellule.DataType. En réalité, lors de l'analyse syntaxique de la cellule avec la date "4/5/2011", la valeur de cell.DataType est null et la valeur de la cellule est "40638" et il ne s'agit pas d'un index de la table de chaînes partagée. (J'ai déjà essayé ça et ça a fini avec une exception.)

Des idées? Merci

25
Santhos

Open XML stocke les dates sous forme de nombre de jours à compter du 1er janvier 1900. Bien, ignorez le jour incorrect du 29 février 1900 comme jour valide. Vous devriez être capable de trouver des algorithmes pour vous aider à calculer la valeur correcte. Je crois que certains développeurs utilisent DateTime.FromOADate() comme aide.

De même, la classe Cell a la propriété DataType comme numéro par défaut. Donc si c'est nul, c'est un nombre, qui inclut les dates dans notre cas.

Vous ne accédez à la table des chaînes partagées que lorsque la date enregistrée est antérieure à l'époque (le 1 er janvier 1900 dans ce cas). Et dans ce cas, la valeur CellValue de la classe Cell contient l'index de la table de chaînes partagée.

30
Vincent Tan

vous pouvez utiliser DateTime.FromOADate (41690)

10
mzoabi

J'ai eu le même problème - basculé sur EPPlus http://epplus.codeplex.com/

Notez qu'il possède une licence LGPL. Donc, si vous voulez que votre base de code soit protégée contre les problèmes liés à la GPL, utilisez simplement la bibliothèque telle quelle et votre licence de base de code d'origine est sécurisée.

3
CKmum

Ajout de mes 2 pence de valeur . Je suis en train de traiter un modèle, donc je sais qu'une cellule donnée est censée être un DateTime . Je me retrouve donc dans cette méthode avec un paramètre de chaîne excelDateTime contenant la valeur de la cellule, qui sera un numéro OADate du type "42540.041666666664".

public static bool TryParseExcelDateTime(string excelDateTimeAsString, out DateTime dateTime)
{
    double oaDateAsDouble;
    if (!double.TryParse(excelDateTimeAsString, out oaDateAsDouble)) //this line is Culture dependent!
        return false;
    //[...]
    dateTime = DateTime.FromOADate(oaDateAsDouble);

Mon problème est que l'utilisateur final est en Allemagne et, comme il s'agit d'un site Web, nous avons défini Thread.CurrentThread.CurrentCulture et Thread.CurrentThread.CurrentUICulture sur "DE-de". Et lorsque vous appelez double.TryParse, il utilise la culture pour analyser le numéro. Donc, cette ligne: double.TryParse("42540.041666666664", out oaDate) fonctionne, mais renvoie 42540041666666664 car en Allemagne, le point est un séparateur de groupe. DateTime.FromOADate échoue alors car le nombre est en dehors de la plage ( minOaDate = -657435.0, maxOaDate = +2958465.99999999 ).

Cela me fait penser que:

  1. indépendamment de l'environnement local sur la machine d'un utilisateur, le document OpenXML contient des nombres formatés selon l'environnement local par défaut (US? invariant? dans tous les cas, avec le point comme séparateur décimal). J'ai cherché, mais je n'ai pas trouvé les spécifications pour cela.
  2. lorsque vous faites double.TryParse sur une chaîne OADate potentielle, nous devrions le faire avec double.TryParse(excelDateTimeAsString, NumberStyles.Any, CultureInfo.InvariantCulture, out oaDateAsDouble)). J'utilise CultureInfo.InvariantCulture, mais cela devrait être le point 1, ce que je ne sais pas avec certitude.
0
Thierry_S