fast_excel icon indicating copy to clipboard operation
fast_excel copied to clipboard

Fix timestamps with timezones

Open Narnach opened this issue 3 years ago • 1 comments

What problem does this address?

Using fast_excel to write Time or DateTime to XLSX corrupts the result when the timezone is not +00:00.

While exposing the issue, this was the result of converting various input values via FastExcel::WorksheetExt#write_value:

Equivalent                 Check                          Input                         Result
√                DateTime +00:00      2017-03-03T03:03:03+00:00      2017-03-03T03:03:03+00:00
x                DateTime +01:00      2017-01-01T01:01:01+01:00      2017-01-01T01:01:01+00:00
x                   DateTime CET      2017-01-01T01:01:01+01:00      2017-01-01T01:01:01+00:00
x                  DateTime CEST      2017-07-07T07:07:07+02:00      2017-07-07T07:07:07+00:00
√                    Time +00:00      2017-03-03 03:03:03 +0000      2017-03-03T03:03:03+00:00
x                    Time +01:00      2017-01-01 01:01:01 +0100      2017-01-01T00:01:01+00:00
x                    Time +02:00      2017-07-07 07:07:07 +0200      2017-07-07T05:07:07+00:00
√                           Date                     2017-03-01                     2017-03-01

Only the +00:00 offsets work as expected, which are the only use cases originally tested.

What have I done to solve this?

I've expanded the test cases to expose the problem and then applied a fix that ensures DateTime and Time use non-destructive calls to convert timestamps to be in +00:00 before writing them to XLSX.

I've tested it locally on Ruby 2.7.5. If older Rubies break, CI should show us.

Refactoring

Because of the (now) large number of test cases that duplicate the logic for writing a value to XLSX and reading it back, I've added a helper method to the test file to encapsulate this. The test cases are now much easier to read.

Narnach avatar Jan 20 '22 15:01 Narnach

I think excel doesn't know about timezones, and internally it stores dates as number of days since 1900. And excel file is usually for people to see, so it should display local time.

When we write date or time, this library will call FastExcel.date_num(...) https://github.com/Paxa/fast_excel/blob/788c94231405e80ce307ac29ce2c85d37f2a41fa/lib/fast_excel.rb#L92

And inside date_num it will try to read zone offset of parameter or Time.zone (for rails), if none then use UTC.

I think it's correct behaviour, if we call SpecialEvent.all() and print it in logs or in HTML, the dates will be in local timezone (zone of application or Time.zone inside rails http request), same time also shown in excel file

If you want always UTC then do something like


worksheet.write_number(1, 1, FastExcel.date_num(value, 0), nil) # 0 = offset in seconds

Paxa avatar Dec 29 '23 11:12 Paxa