2222#ifndef Rcpp__Date_h
2323#define Rcpp__Date_h
2424
25- #include < RcppCommon.h>
26-
2725namespace Rcpp {
2826
2927 class Date {
3028 public:
31- Date ();
32- Date (SEXP s);
33- Date (const int &dt); // from integer (with negative dates before Jan 1, 1970)
34- Date (const double &dt); // from fractional integer since epoch, just like R
35- Date (const std::string &s, const std::string &fmt=" %Y-%m-%d" );
36- Date (const unsigned int &m, const unsigned int &d, const unsigned int &y);
37- Date (const Date ©);
38- ~Date () {};
39-
40- double getDate (void ) const { return m_d; }
41-
42- // intra-day useless for date class
43- // int getSeconds() const { return m_tm.tm_sec; }
44- // int getMinutes() const { return m_tm.tm_min; }
45- // int getHours() const { return m_tm.tm_hour; }
46- int getDay () const { return m_tm.tm_mday ; }
47- int getMonth () const { return m_tm.tm_mon + 1 ; } // makes it 1 .. 12
48- int getYear () const { return m_tm.tm_year ; } // does include 1900 (see Date.cpp)
49- int getWeekday () const { return m_tm.tm_wday + 1 ; } // makes it 1 .. 7
50- int getYearday () const { return m_tm.tm_yday + 1 ; } // makes it 1 .. 366
51-
52- static const unsigned int QLtoJan1970Offset; // Offset between R / Unix epoch date and the QL base date
53- static const unsigned int baseYear; // 1900 as per POSIX mktime() et al
29+ Date (){
30+ m_d = 0 ;
31+ update_tm ();
32+ }
33+ Date (SEXP s);
34+
35+ // from integer (with negative dates before Jan 1, 1970)
36+ Date (const int &dt){
37+ m_d = dt;
38+ update_tm ();
39+ }
40+
41+ // from fractional integer since epoch, just like R
42+ Date (const double &dt){
43+ m_d = dt;
44+ update_tm ();
45+ }
46+ Date (const std::string &s, const std::string &fmt=" %Y-%m-%d" );
47+
48+ Date (const unsigned int &mon, const unsigned int &day, const unsigned int &year) {
49+ m_tm.tm_sec = m_tm.tm_min = m_tm.tm_hour = m_tm.tm_isdst = 0 ;
50+
51+ // allow for ISO-notation case (yyyy, mm, dd) which we prefer over (mm, dd, year)
52+ if (mon >= baseYear && day <= 12 && year <= 31 ) {
53+ m_tm.tm_year = mon - baseYear;
54+ m_tm.tm_mon = day - 1 ; // range 0 to 11
55+ m_tm.tm_mday = year;
56+ } else {
57+ m_tm.tm_mday = day;
58+ m_tm.tm_mon = mon - 1 ; // range 0 to 11
59+ m_tm.tm_year = year - baseYear;
60+ }
61+ double tmp = mktime00 (m_tm); // use mktime() replacement borrowed from R
62+ m_tm.tm_year += baseYear; // we'd rather keep it as a normal year
63+ m_d = tmp/(24 *60 *60 );
64+ }
5465
55- Date & operator =(const Date &newdate); // copy assignment operator
56-
57- // Minimal set of date operations.
58- friend Date operator +(const Date &date, int offset);
59- friend double operator -(const Date& date1, const Date& date2);
60- friend bool operator <(const Date &date1, const Date& date2);
61- friend bool operator >(const Date &date1, const Date& date2);
62- friend bool operator ==(const Date &date1, const Date& date2);
63- friend bool operator >=(const Date &date1, const Date& date2);
64- friend bool operator <=(const Date &date1, const Date& date2);
65- friend bool operator !=(const Date &date1, const Date& date2);
66-
67- inline int is_na () const { return traits::is_na<REALSXP>( m_d ) ; }
68-
66+ ~Date () {};
67+
68+ double getDate (void ) const {
69+ return m_d;
70+ }
71+
72+ // intra-day useless for date class
73+ // int getSeconds() const { return m_tm.tm_sec; }
74+ // int getMinutes() const { return m_tm.tm_min; }
75+ // int getHours() const { return m_tm.tm_hour; }
76+ int getDay () const { return m_tm.tm_mday ; }
77+ int getMonth () const { return m_tm.tm_mon + 1 ; } // makes it 1 .. 12
78+ int getYear () const { return m_tm.tm_year ; } // does include 1900 (see Date.cpp)
79+ int getWeekday () const { return m_tm.tm_wday + 1 ; } // makes it 1 .. 7
80+ int getYearday () const { return m_tm.tm_yday + 1 ; } // makes it 1 .. 366
81+
82+ static const unsigned int QLtoJan1970Offset; // Offset between R / Unix epoch date and the QL base date
83+ static const unsigned int baseYear; // 1900 as per POSIX mktime() et al
84+
85+ Date & operator =(const Date &newdate); // copy assignment operator
86+
87+ // Minimal set of date operations.
88+ friend Date operator +(const Date &date, int offset);
89+ friend double operator -(const Date& date1, const Date& date2);
90+ friend bool operator <(const Date &date1, const Date& date2);
91+ friend bool operator >(const Date &date1, const Date& date2);
92+ friend bool operator ==(const Date &date1, const Date& date2);
93+ friend bool operator >=(const Date &date1, const Date& date2);
94+ friend bool operator <=(const Date &date1, const Date& date2);
95+ friend bool operator !=(const Date &date1, const Date& date2);
96+
97+ inline int is_na () const {
98+ return traits::is_na<REALSXP>( m_d ) ;
99+ }
100+
69101 private:
70102 double m_d; // (fractional) day number, relative to epoch of Jan 1, 1970
71103 struct tm m_tm; // standard time representation
72-
73- void update_tm (); // update m_tm based on m_d
74-
75- double mktime00 (struct tm &tm) const ; // from R's src/main/datetime.c
76- };
77-
104+
105+ // update m_tm based on m_d
106+ void update_tm (){
107+ if (R_FINITE (m_d)) {
108+ time_t t = 24 *60 *60 * m_d; // (fractional) days since epoch to seconds since epoch
109+ m_tm = *gmtime_ (&t);
110+ } else {
111+ m_tm.tm_sec = m_tm.tm_min = m_tm.tm_hour = m_tm.tm_isdst = NA_INTEGER;
112+ m_tm.tm_min = m_tm.tm_hour = m_tm.tm_mday = m_tm.tm_mon = m_tm.tm_year = NA_INTEGER;
113+ }
114+ }
115+
116+ double mktime00 (struct tm &tm) const ; // from R's src/main/datetime.c
117+ };
118+
119+ const unsigned int Date::QLtoJan1970Offset = 25569 ; // Offset between R / Unix epoch date and the QL base date
120+ const unsigned int Date::baseYear = 1900 ; // because we hate macros
78121
79122 // template specialisation for wrap() on the date
80123 template <> SEXP wrap<Rcpp::Date>(const Rcpp::Date &date);
@@ -90,10 +133,51 @@ namespace Rcpp {
90133 }
91134
92135 template <> inline SEXP wrap_extra_steps<Rcpp::Date>( SEXP x ){
93- Rf_setAttrib ( x, R_ClassSymbol, Rf_mkString ( " Date" ) ) ;
94- return x ;
136+ Rf_setAttrib ( x, R_ClassSymbol, Rf_mkString ( " Date" ) ) ;
137+ return x ;
138+ }
139+
140+ inline Date operator +(const Date &date, int offset) {
141+ Date newdate (date.m_d );
142+ newdate.m_d += offset;
143+ time_t t = 24 *60 *60 * newdate.m_d ; // days since epoch to seconds since epo
144+ // newdate.m_tm = *gmtime(&t); // this may need a Windows fix, re-check R's datetime.c
145+ newdate.m_tm = *gmtime_ (&t);
146+ return newdate;
147+ }
148+
149+ inline double operator -(const Date& d1, const Date& d2) { return d1.m_d - d2.m_d ; }
150+ inline bool operator <(const Date &d1, const Date& d2) { return d1.m_d < d2.m_d ; }
151+ inline bool operator >(const Date &d1, const Date& d2) { return d1.m_d > d2.m_d ; }
152+ inline bool operator ==(const Date &d1, const Date& d2) { return d1.m_d == d2.m_d ; }
153+ inline bool operator >=(const Date &d1, const Date& d2) { return d1.m_d >= d2.m_d ; }
154+ inline bool operator <=(const Date &d1, const Date& d2) { return d1.m_d <= d2.m_d ; }
155+ inline bool operator !=(const Date &d1, const Date& d2) { return d1.m_d != d2.m_d ; }
156+
157+ namespace internal {
158+
159+ inline SEXP getPosixClasses (){
160+ Shield<SEXP> datetimeclass (Rf_allocVector (STRSXP,2 ));
161+ SET_STRING_ELT (datetimeclass, 0 , Rf_mkChar (" POSIXct" ));
162+ SET_STRING_ELT (datetimeclass, 1 , Rf_mkChar (" POSIXt" ));
163+ return datetimeclass ;
164+ }
165+
166+ inline SEXP new_posixt_object ( double d){
167+ Shield<SEXP> x ( Rf_ScalarReal ( d ) ) ;
168+ Rf_setAttrib (x, R_ClassSymbol, getPosixClasses () );
169+ return x ;
170+ }
171+
172+ inline SEXP new_date_object ( double d){
173+ Shield<SEXP> x (Rf_ScalarReal ( d ) ) ;
174+ Rf_setAttrib (x, R_ClassSymbol, Rf_mkString (" Date" ));
175+ return x;
176+ }
177+
95178 }
96-
179+
180+
97181}
98182
99183#endif
0 commit comments