10

rubyスクリプトでroogemを使用してXLSXファイルを解析しようとしています。

Excelでは、日付は、から数えてDDDDD.tttttの形式で浮動小数点数または整数として格納されます1900-01-00 (00 no 01)。したがって、40396などの日付を変換するには1900-01-00 + 40396、2010-10-15を取得する必要がありますが、2010-08-08を取得しています。

私はactive_support/timeを使用して、次のような計算を行っています。

Time.new("1900-01-01") + 40396.days

計算が間違っていますか、それともアクティブサポートにバグがありますか?

私はWindows7でruby1.9.3-mriを実行しています+最新のactive_supportgem(3.2.1)

編集

私はExcelで間違ったデータを含む古いファイルを見ていました-私のスクリプト/コンソールは正しいデータを引き出していました-それ故に私の混乱-私は正しいファイルを使用することを除いてすべてを正しく行っていました!!!! 夜通しの人を酷評しなさい!

返信してくださった皆さんのおかげで、誰かがルビーを使ってエクセルから日付を変換する方法についての情報が必要な場合に備えて、ここに質問を残しておきます。

また、これに遭遇した他の人にとっても-スプレッドシートgemはこの時点(v 0.7.1)でXLSXファイルの読み取りを適切にサポートしていません-したがって、読み取りにはrooを使用し、書き込みにはaxlsxを使用しています。

4

3 に答える 3

31

1日ごとの番号付けに1つずつエラーがあります。これは、Excelやその他のスプレッドシートプログラムが30年以上にわたって慎重に互換性を維持しているLotus1-2-3のバグが原因です。

当初、1日目は1900年1月1日であることが意図されていました(これにより、あなたが述べたように、0日目は1899年12月31日に等しくなります)。しかし、ロータスは1900をうるう年と誤って見なしていたため、現在のロータスの数値を使用して逆算すると、1900を平年に正しくすると、1900年3月1日より前のすべての日の数値が高すぎます。1日目は1899年12月31日になり、0日目は30日に戻ります。したがって、ロータスベースのスプレッドシートでの日付演算のエポックは、実際には1899年12月30日土曜日です。 0土曜日であることに同意しながら、「12月31日」!しかし、他のLotusベースのスプレッドシートはそれを行わず、Rubyも確かに行いません。)

ただし、このエラーを考慮しても、記載されている例は正しくありません。ロータスの日数40,396は、2010年8月6日であり、10月15日ではありません。この対応をExcel、LibreOffice、Googleスプレッドシートで確認しましたが、すべて同意しています。あなたはどこかで例を越えたに違いありません。

変換を行う1つの方法は次のとおりです。

Time.utc(1899,12,30) + 40396.days #=> 2010-08-06 00:00:00 UTC

または、別の既知の対応を利用することもできます。Ruby(および一般的なPOSIXシステム)の時間ゼロは、1970年1月1日のグリニッジ標準時午前0時です。1970年1月1日はロータスの日25,569です。UTCで計算を行うことを覚えている限り、次のこともできます。

Time.at( (40396 - 25569).days ).utc # => 2010-08-06 00:00:00 UTC

いずれの場合も、エポック日付のシンボリック定数(Time1899-12-30を表すオブジェクトまたはPOSIX "day 0"値25,569のいずれか)を宣言することをお勧めします。

他に何も.days必要なく、このためだけにロードしたくない場合は、これらの呼び出しを86400(1日あたりの秒数)の乗算に置き換えることができます。active_support/core_ext/integer/time

于 2012-05-12T01:12:46.793 に答える
6

「Excelは、日付と時刻を1900-Jan-0からの日数に加えて、24時間制の小数部分ddddd.ttttttを表す数値として格納します。これは、シリアル日付またはシリアル日時と呼ばれます。」(http://www.cpearson.com/excel/datetime.htm

列に日付だけでなく日時が含まれている場合は、次のコードが役立ちます。

 dt = DateTime.new(1899, 12, 30) + excel_value.to_f

また、Excelワークシートには1900ベースと1904ベースの2つの日付モードがあり、通常、Macで作成されたスプレッドシートではデフォルトで有効になっていることにも注意してください。一貫して4年ずれている場合は、別の基準日を使用する必要があります。

 dt = DateTime.new(1904, 1, 1) + excel_value.to_f

どのスプレッドシートでも1904日付モードを有効/無効にできますが、データの追加後に設定を変更すると、日付はスプレッドシートに4年ずれて表示されます。一般的に、野生のほとんどのExcelユーザーはウィンドウベースであるため、常に1900日付モードを使用する必要があります。

注:この方法の落とし穴は、丸めが+/-1秒発生する可能性があることです。私にとって、インポートする日付は「十分に近い」ですが、覚えておくべきことです。より良い解決策は、この問題を解決するために小数秒の丸めを使用する場合があります。

于 2013-03-06T16:18:02.040 に答える
3

あなたはあなたの計算を間違っています。2010-10-15の期待される結果にどのように到達しますか?

Excelでは、40396です2010-08-06(もちろん、1904年のカレンダーは使用していません)。これを示すために、Excelセルに40396と入力し、形式をに設定しますyyyy-mm-dd

または:

40396 / 365.2422 = 110.6 (years -- 1900 + 110 = 2010)
0.6 * 12 = 7.2 (months -- January = 1; 1 + 7 = 8; 8 = August)
0.2 * 30 = 6 (days)

Excelのカレンダーに誤って1900-02-29が含まれています。これは、2010年8月8日の結果との1日の違いを説明しています。違いの2日目の理由はわかりません。

于 2012-05-12T01:12:07.783 に答える