2012-05-11 36 views
7

Cố gắng phân tích cú pháp và tệp XLSX bằng đá quý roo trong tập lệnh ruby.Làm thế nào để chuyển đổi MS excel ngày từ phao sang định dạng ngày trong Ruby?

Trong ngày excel được lưu trữ dưới dạng phao hoặc số nguyên theo định dạng DDDDD.ttttt, tính từ 1900-01-00 (00 no 01). Vì vậy, để chuyển đổi một ngày như 40396 - bạn sẽ mất 1900-01-00 + 40396 và bạn sẽ nhận được 2010-10-15, nhưng tôi nhận được 2010-08-08.

Tôi đang sử dụng active_support/thời gian để làm tính toán như sau:

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

Tôi có làm tính toán của tôi sai hay là có một lỗi trong hỗ trợ tích cực?

Tôi đang chạy ruby ​​1.9.3-MRI trên Windows 7 + mới nhất active_support đá quý (3.2.1)

EDIT

Tôi đã nhìn vào các tập tin cũ trong Excel với dữ liệu sai - kịch bản/bàn điều khiển của tôi đã kéo dữ liệu đúng - do đó sự nhầm lẫn của tôi - tôi đã làm mọi thứ đúng, ngoại trừ việc sử dụng đúng tệp !!!! Chết tiệt tất cả các nighters!

Nhờ mọi người trả lời, tôi sẽ giữ câu hỏi ở đây trong trường hợp ai đó cần thông tin về cách chuyển đổi ngày từ excel bằng ruby.

Ngoài ra đối với bất kỳ ai khác tham gia vào - đá quý bảng tính KHÔNG hỗ trợ đọc tệp XLSX tại thời điểm này (v 0.7.1) đúng cách - vì vậy tôi đang sử dụng roo để đọc và viết lách.

Trả lời

24

Bạn gặp lỗi tạm thời trong đánh số ngày - do lỗi trong Lotus 1-2-3 mà Excel và các chương trình bảng tính khác đã duy trì tính tương thích một cách cẩn thận với hơn 30 năm.

Ban đầu, ngày 1 được dự định là ngày 1 tháng 1 năm 1900 (như bạn đã nêu, làm cho ngày 0 bằng ngày 31 tháng 12 năm 1899). Nhưng Lotus đã xem không đúng năm 1900 là năm nhuận, nên số ngày cho mọi thứ trước ngày 1 tháng 3 của năm đó là quá cao. Sử dụng những con số với một lịch mà đếm chính xác 1900 là một năm chung, ngày 1 trở thành ngày 31 tháng 12 và ngày 0 chuyển trở lại ngày 30. Vì vậy, kỷ nguyên cho số học ngày trong bảng tính dựa trên Lotus là thứ bảy, ngày 30 tháng 12 năm 1899. (Excel hiện đại và một số bảng tính khác mở rộng khả năng tương thích lỗi Lotus đủ xa để tiếp tục gắn nhãn ngày đó "ngày 31 tháng 12" trong khi đồng ý rằng đó là Thứ bảy, nhưng các bảng tính dựa trên Lotus khác thì không, và Ruby chắc chắn cũng vậy.)

Thậm chí cho phép lỗi này, ví dụ đã nêu của bạn không đúng: số ngày Lotus 40,396 là ngày 6 tháng 8 năm 2010, 15 tháng 10. Tôi đã xác nhận thư từ này trong các trang Excel, LibreOffice và Google, tất cả đều đồng ý.Bạn phải vượt qua các ví dụ ở đâu đó.

Dưới đây là một cách để làm việc chuyển đổi:

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

Ngoài ra, bạn có thể tận dụng lợi thế của một thư được biết đến. Thời gian bằng không cho Ruby (và các hệ thống POSIX nói chung) là thời điểm ngày 1 tháng 1 năm 1970, lúc nửa đêm GMT. Ngày 1 tháng 1 năm 1970 là ngày Lotus 25.569. Chừng nào bạn nhớ để làm các phép tính của bạn trong UTC, bạn cũng có thể làm điều này:

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

Trong cả hai trường hợp, bạn có thể muốn khai báo một hằng số tượng trưng cho ngày kỷ nguyên (một trong hai đối tượng Time đại diện 1899-1812 -30 hoặc POSIX "ngày 0" giá trị 25,569).

Bạn có thể thay thế các cuộc gọi đó thành .days bằng phép nhân với 86.400 nếu bạn không cần active_support/core_ext/integer/time cho bất kỳ mục đích nào khác và không muốn tải nó chỉ cho việc này.

+0

Tính tương thích kéo dài trở lại 1/1/1900, vì lịch của Excel cũng có 1900 là năm nhuận. – phoog

+0

Đủ công bằng, @phoog, kể từ khi câu hỏi đề cập đến Excel cụ thể, nhưng tôi cũng đã đề cập đến các bảng tính khác và chúng không mở rộng khả năng tương thích của chúng cho đến nay. Ruby cũng không, dĩ nhiên. Vì vậy, hiệu quả, ngày 0 vẫn là 1899-12-30. –

+0

Chỉ cần bỏ qua toàn bộ điều - tôi đã nhầm lẫn - nguyên nhân trong kịch bản của tôi tôi đã kéo tập tin đúng, nhưng trong Excel tôi đã có một tập tin cũ mở với sai ngày. !!!!! Vẫn cảm ơn bạn đã trả lời. – konung

3

Bạn đang tính toán sai. Làm thế nào để bạn đến kết quả mong đợi của 2010-10-15?

Trong Excel, 403962010-08-06 (không sử dụng lịch 1904, tất nhiên). Để chứng minh điều đó, hãy nhập 40396 vào ô Excel và đặt định dạng là yyyy-mm-dd.

Hoặc: lịch

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 của sai bao gồm 1900/02/29; tính đến sự khác biệt trong một ngày giữa kết quả 2010-08-08 của bạn; Tôi không chắc chắn về lý do cho ngày thứ hai của sự khác biệt.

3

"Excel lưu trữ ngày và giờ làm số đại diện cho số ngày kể từ 1900-Jan-0, cộng với phần phân số của ngày 24 giờ: ddddd.tttttt. Đây được gọi là ngày nối tiếp hoặc ngày nối tiếp- thời gian." (http://www.cpearson.com/excel/datetime.htm)

Nếu cột của bạn có chứa một thời gian hẹn hò, tỏ sau đó chỉ cần một ngày, đoạn code sau rất hữu ích:

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

Cũng nên nhớ rằng có 2 phương thức ngày tháng trong một bảng tính excel, Dựa trên 1900 và 1904, thường được bật theo mặc định cho các bảng tính được tạo trên mac. Nếu bạn thường xuyên thấy ngày của bạn tắt bởi 4 năm, bạn nên sử dụng một ngày cơ sở khác nhau:

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

Bạn có thể bật/tắt chế độ 1904 ngày đối với bất kỳ bảng tính, nhưng những ngày sau đó sẽ xuất hiện ra bởi 4 năm trong bảng tính nếu bạn thay đổi cài đặt sau khi thêm dữ liệu. Nói chung, bạn nên luôn luôn sử dụng chế độ ngày 1900 vì hầu hết người dùng excel trong tự nhiên là cửa sổ dựa.

Lưu ý: Một hình ảnh với phương thức này là làm tròn có thể xảy ra +/- 1 giây. Đối với tôi những ngày tôi nhập khẩu là "đủ gần" nhưng chỉ cần một cái gì đó để ghi nhớ. Một giải pháp tốt hơn có thể sử dụng làm tròn số giây phân số để giải quyết vấn đề này.

+0

Đắm bạn thật nhiều! –

Các vấn đề liên quan