Skip to content

Inconsistent Datetime microsecond output in Rcpp #899

@driftwoods

Description

@driftwoods

I would like to generate Datetime objects with microsecond precision using Rcpp. However I got inconsistent Datetime outputs (in the microsecond part) in R, even though the printout within Rcpp code shows accurate result. To demonstrate this issue, let's save the following Rcpp code into a file called ./test_Rcpp_datetime.cpp.

#include <ctime>
#include <chrono>
#include <Rcpp.h>
using namespace Rcpp;
using namespace std;

// [[Rcpp::export]]
Datetime RcppConvertMicrosecsToDatetime(int idate,
                                        int year,
                                        int month,
                                        int day,
                                        int hour,
                                        int min,
                                        int secs,
                                        int usecs) {
  tm time;
  time.tm_year = year - 1900;
  time.tm_mon = month - 1;
  time.tm_mday = day;
  time.tm_hour = hour;
  time.tm_min = min;
  time.tm_sec = secs;
  time.tm_isdst = 0; // this is important
  
  time_t ttime = mktime(&time);
  chrono::system_clock::time_point tp = chrono::system_clock::from_time_t(ttime);
  tp += chrono::microseconds(usecs);
  auto duration = tp.time_since_epoch(); 
  auto micros = chrono::duration_cast<chrono::microseconds>(duration).count();
  double seconds = micros / 1.0e6;
  Rcpp::Rcout << "micro seconds since epoch = " << micros << endl;
  Rcpp::Rcout << std::setprecision(18) << "seconds since epoch = " << seconds << endl;
  Datetime dt = seconds;
  Rcpp::Rcout << "Datetime.getMicroSeconds() = " << dt.getMicroSeconds() << endl;
  
  return dt; 
}

/*** R
options(digits.secs=6)
RcppConvertMicrosecsToDatetime(idate=20180113, year=2018, month=1, day=13, hour=15, min=30, secs=1, usecs=834198)
RcppConvertMicrosecsToDatetime(idate=20180113, year=2018, month=1, day=13, hour=15, min=30, secs=1, usecs=834199)
RcppConvertMicrosecsToDatetime(idate=20180113, year=2018, month=1, day=13, hour=15, min=30, secs=1, usecs=834200)
RcppConvertMicrosecsToDatetime(idate=20180113, year=2018, month=1, day=13, hour=15, min=30, secs=1, usecs=834201)
RcppConvertMicrosecsToDatetime(idate=20180113, year=2018, month=1, day=13, hour=15, min=30, secs=1, usecs=834202)
RcppConvertMicrosecsToDatetime(idate=20180113, year=2018, month=1, day=13, hour=15, min=30, secs=1, usecs=834203)
RcppConvertMicrosecsToDatetime(idate=20180113, year=2018, month=1, day=13, hour=15, min=30, secs=1, usecs=834204)
*/

In R condole, we can do Rcpp::sourceCpp('./test_Rcpp_datetime.cpp'), below is the output of running. Rcpp internal microseconds values look good to me (with proper round of decimals). But the microsecond value in R is weird, it doesn't do round properly and neither does floor properly. How can I generate Datetime object correctly in Rcpp? Thanks.

> options(digits.secs=6)

> RcppConvertMicrosecsToDatetime(idate=20180113, year=2018, month=1, day=13, hour=15, min=30, secs=1, usecs=834198)
micro seconds since epoch = 1515879001834198
seconds since epoch = 1515879001.834198
Datetime.getMicroSeconds() = 834198
[1] "2018-01-13 15:30:01.834197 CST"

> RcppConvertMicrosecsToDatetime(idate=20180113, year=2018, month=1, day=13, hour=15, min=30, secs=1, usecs=834199)
micro seconds since epoch = 1515879001834199
seconds since epoch = 1515879001.83419895
Datetime.getMicroSeconds() = 834199
[1] "2018-01-13 15:30:01.834198 CST"

> RcppConvertMicrosecsToDatetime(idate=20180113, year=2018, month=1, day=13, hour=15, min=30, secs=1, usecs=834200)
micro seconds since epoch = 1515879001834200
seconds since epoch = 1515879001.83419991
Datetime.getMicroSeconds() = 834200
[1] "2018-01-13 15:30:01.8341 CST"

> RcppConvertMicrosecsToDatetime(idate=20180113, year=2018, month=1, day=13, hour=15, min=30, secs=1, usecs=834201)
micro seconds since epoch = 1515879001834201
seconds since epoch = 1515879001.8342011
Datetime.getMicroSeconds() = 834201
[1] "2018-01-13 15:30:01.834201 CST"

> RcppConvertMicrosecsToDatetime(idate=20180113, year=2018, month=1, day=13, hour=15, min=30, secs=1, usecs=834202)
micro seconds since epoch = 1515879001834202
seconds since epoch = 1515879001.83420205
Datetime.getMicroSeconds() = 834202
[1] "2018-01-13 15:30:01.834202 CST"

> RcppConvertMicrosecsToDatetime(idate=20180113, year=2018, month=1, day=13, hour=15, min=30, secs=1, usecs=834203)
micro seconds since epoch = 1515879001834203
seconds since epoch = 1515879001.834203
Datetime.getMicroSeconds() = 834203
[1] "2018-01-13 15:30:01.834203 CST"

> RcppConvertMicrosecsToDatetime(idate=20180113, year=2018, month=1, day=13, hour=15, min=30, secs=1, usecs=834204)
micro seconds since epoch = 1515879001834204
seconds since epoch = 1515879001.83420396
Datetime.getMicroSeconds() = 834204
[1] "2018-01-13 15:30:01.834203 CST"

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions