2016-05-28 6 views
2

MVC 5アプリケーションでExcelPackage関数を使用しています。強く型付けされたモデルを新しいExcelファイルに正常に出力できます。Epplus ExcelWorksシートで日時の値を見つける方法

  • ヌル
  • 日付のみ
  • 時間だけ
  • 日時

I:

Iは、特定の列は、4つの可能な値を持つnull許容のDateTimeである場合を持っていますワークシート内のDateTime値を特定する作業を行う関数を抽出しました。 DateTimeの値は一貫して識別され、正しくフォーマットされていますが、ネストされたループと同じ結果を得るためのより良い方法があるとは思えません。

IEnumerableに任意のIEnumerableを受け入れるように設計されているため、IEnumerableにDateTime値が含まれる列を予測できません。そのため、私は既知の範囲の細胞をハードコードすることはできません。

より良いコンテキストを提供するために、ここにクラスコンストラクタが貼り付けられ、その後に私がより良くしようとしている関数が貼り付けられています。コメントを取り除いても、それはまだネストされたコードのかなり醜いセットです。

要約すると、私の質問はこれです:C#言語やNuget Epplusパッケージに関してより洗練されたコーディング手法が欠けていますか?

public class EpplusExcelPackage<T> 
{ 
    private IEnumerable<T> _data; 
    private string _reportName; 

    public EpplusExcelPackage(IEnumerable<T> Data, string ReportName) 
    { 
     this._data = Data; 
     this._reportName = ReportName;  
    } 

    // much more code... 

これは私がより効率的にしていきたいと考えてい方法である:それがダウンしてあなたがソースがテーブルが「適切」フォーマットされている優れていることをどのように自信を持ってくるに

private static void FormatDateTimeValuesInWorksheet(ExcelWorksheet worksheet) 
{ 
    /* correctly format datetime values as: 
    *  if date only, format as shortdate 
    *  if time only, format as am/pm time 
    *  if date & time present, format as default datetime */ 

    // the worksheet is data is a strongly-typed model, populated in the model constructor 

    System.DateTime dateValue; // used as the out variable of DateTime.TryParse() 

    // nested for-loop to find datetime values in worksheet 
    for (int i = worksheet.Dimension.Start.Column; i < worksheet.Dimension.End.Column; i++) 
    { 
     for (int j = worksheet.Dimension.Start.Row; j < worksheet.Dimension.End.Row; j++) 
     { 
      // ignore null cell values to prevent null exception error 
      if (worksheet.Cells[i, j].Value != null) 
      { 
       // convert the cell value to string: required by TryParse() 
       string cellValue = worksheet.Cells[i, j].Value.ToString(); 

       // identify type of datetime and format accordingly 
       if (DateTime.TryParse(cellValue, out dateValue)) 
       { 
        if (dateValue.Date == Convert.ToDateTime("12/30/1899")) 
        { 
         worksheet.Cells[i, j].Value = dateValue.ToShortTimeString(); 
        } 
        else if (dateValue.TimeOfDay.TotalSeconds == 0) 
        { 
         worksheet.Cells[i, j].Value = dateValue.ToShortDateString(); 
        } 
        else // do not change 
        { 
         worksheet.Cells[i, j].Value = worksheet.Cells[i, j].Value; 
        } 
       } 
      } 
     } 
    } 
} 

答えて

3

。これは、適切な日付(つまり数値)として保存されているか、「文字列として保存された数字」という共通のExcel問題がある可能性があることを意味します。

データが一般的にきれいな場合は、データ型をチェックして文字列と日付を前後にキャストすることを避けることができます。 Epplusは日付をインポートするときに独自の解釈を行うのが好きなので、これは完全に単純ではありません。

は(COLのAに焦点を当てて)この表を見てみましょう:

enter image description here

行1から4までを "正しく" 形式のデータを持っています。つまり、日付と時間は倍精度でExcelに保存されます。行5-8は「ひどく」フォーマットされています。数字(および日付/時刻)は文字列として格納されます。これを実行する場合:

var workbook = pck.Workbook; 
var worksheet = workbook.Worksheets.First(); 
var cells = worksheet.Cells; 

foreach (var cell in cells) 
    Console.WriteLine($"{{Cell: {cell.Address}, Display: {cell.Text}, Value: {cell.Value}, Type: {cell.Value.GetType()}}}"); 

あなたは出力にこれを取得する:

{Cell: A1, Display: 11:33:00 AM, Value: 0.48125, Type: System.Double} 
{Cell: A2, Display: 1/1/2016, Value: 1/1/2016 12:00:00 AM, Type: System.DateTime} 
{Cell: A3, Display: 1/1/16 11:33 AM, Value: 42370.48125, Type: System.Double} 
{Cell: A4, Display: 1264, Value: 1264, Type: System.Double} 
{Cell: A5, Display: 11:33:00 AM, Value: 11:33:00 AM, Type: System.String} 
{Cell: A6, Display: 1/1/2016, Value: 1/1/2016, Type: System.String} 
{Cell: A7, Display: 1/1/2016 11:33:00 AM, Value: 1/1/2016 11:33:00 AM, Type: System.String} 
{Cell: A8, Display: 1264, Value: 1264, Type: System.String} 

日付と時刻は、数字だけである技術(整数部が日付で、小数は時間である)ので、これができますそれらを変換または分離する方法です。時間の倍の0.0は00:00:00を意味します。行3はSystem.DateTimeと表示されていることに注意してください。私が言ったように、EpplusはちょうどそのようなExcelスタイルを認識しますが、その他はDoublesです。

したがって、Typeチェックを使用して、文字列の変換と比較の多くを避けることができます。あなたがひどくフォーマットされたデータを心配しているなら、あなたのアプローチはおそらくそれと同じくらい良いでしょう。私は値のConvert.ToDateTime("12/30/1899"))をどこかの定数の前にループを作成することをお勧めしますが、いくつかのCPUサイクルを節約するためにインクリメントするたびに再作成します。

+0

EPPLusについて独自の解釈をしてくれてありがとうございました。私はタイプがダブルであると仮定したので、私は1/1/201のような日付で問題を抱えていました。私はEPPLusがいくつかの前処理をしている可能性があると思っています。 –

関連する問題