Skip to content

Commit

Permalink
Date subsecond rounding; fixes #187 (#290)
Browse files Browse the repository at this point in the history
* Date subsecond rounding; fixes #187

* Add a source for the rounding sol'n; re-save test sheets just to be safe
  • Loading branch information
jennybc authored Mar 12, 2017
1 parent 68cf164 commit 63ef215
Show file tree
Hide file tree
Showing 6 changed files with 25 additions and 2 deletions.
3 changes: 2 additions & 1 deletion src/XlsCell.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <libxls/xls.h>
#include <libxls/xlstypes.h>
#include "ColSpec.h"
#include "utils.h"

// Key reference for understanding the structure of the xls format is
// [MS-XLS]: Excel Binary File Format (.xls) Structure
Expand Down Expand Up @@ -287,7 +288,7 @@ class XlsCell {

case CELL_DATE:
case CELL_NUMERIC:
return (cell_->d - offset) * 86400;
return dateRound((cell_->d - offset) * 86400);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/XlsxCell.h
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ class XlsxCell {
case CELL_NUMERIC:
{
rapidxml::xml_node<>* v = cell_->first_node("v");
return (atof(v->value()) - offset) * 86400;
return dateRound((atof(v->value()) - offset) * 86400);
}
}
}
Expand Down
11 changes: 11 additions & 0 deletions src/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@ inline double dateOffset(bool is1904) {
return is1904 ? 24107 : 25569;
}

// this is sort of horrible
// convert serial date to decimilliseconds
// use well-known hack to round to nearest integer w/o C++11 or boost, e.g.
// http://stackoverflow.com/questions/485525/round-for-float-in-c
// convert back to serial date
inline double dateRound(double dttm) {
double ms = dttm * 10000;
ms = (ms >= 0.0 ? std::floor(ms + 0.5) : std::ceil(ms - 0.5));
return ms / 10000;
}

// Simple parser: does not check that order of numbers and letters is correct
inline std::pair<int, int> parseRef(const char* ref) {
int col = 0, row = 0;
Expand Down
Binary file added tests/testthat/sheets/datetime-rounding.xls
Binary file not shown.
Binary file added tests/testthat/sheets/datetime-rounding.xlsx
Binary file not shown.
11 changes: 11 additions & 0 deletions tests/testthat/test-dates.R
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,14 @@ test_that("dates respect worksheet date setting", {
expect_equal(d1900, d1900loo)
expect_equal(d1900$X1, ISOdate(2000, 01, 01, 0, tz = "UTC"))
})

## #187 Date/times missing a second
test_that("date subsecond rounding works", {
## xlsx
df <- read_excel(test_sheet("datetime-rounding.xlsx"))
expect_identical(as.character(df$dttm), df$dttm_string)

## xls
df <- read_excel(test_sheet("datetime-rounding.xls"))
expect_identical(as.character(df$dttm), df$dttm_string)
})

0 comments on commit 63ef215

Please sign in to comment.