Skip to content

Commit 7a22d21

Browse files
authored
Merge pull request #599 from RcppCore/feature/format_dates
added format() methods for Date and Datetime
2 parents 3bdd1f2 + 06fb890 commit 7a22d21

File tree

10 files changed

+372
-232
lines changed

10 files changed

+372
-232
lines changed

ChangeLog

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,27 @@
1+
2016-11-28 Dirk Eddelbuettel <[email protected]>
2+
3+
* inst/unitTests/cpp/dates.cpp (Date_format, Datetime_format): New tests
4+
* inst/unitTests/runit.Date.R (test.Date.formating): Ditto
5+
(test.Datetime.formating): Ditto
6+
7+
2016-11-27 Dirk Eddelbuettel <[email protected]>
8+
9+
* inst/include/Rcpp/date_datetime/Date.h (format, operator<<): Added
10+
* inst/include/Rcpp/date_datetime/Datetime.h (format, operator<<): Ditto
11+
* inst/include/Rcpp/date_datetime/newDateVector.h (operator<<): Ditto
12+
* inst/include/Rcpp/date_datetime/newDatetimeVector.h (operator<<): Ditto
13+
14+
2016-11-23 Dirk Eddelbuettel <[email protected]>
15+
16+
* inst/include/Rcpp/config.h (RCPP_DEV_VERSION): Set minor version
17+
118
2016-11-22 Dirk Eddelbuettel <[email protected]>
219

320
* DESCRIPTION (Date, Version): roll minor version
421

522
* inst/include/Rcpp/date_datetime/newDatetimeVector.h (Rcpp): Small
623
correction concerning timezone attribute to ctor from RTYPE
24+
725
2016-11-22 Jim Hester <[email protected]>
826

927
* inst/src/api.cpp: Cleanup to stack message parseing

inst/NEWS.Rd

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,13 @@
44
\newcommand{\ghit}{\href{https://github.com/RcppCore/Rcpp/issues/#1}{##1}}
55

66
\section{Changes in Rcpp version 0.12.9 (2017-01-xx)}{
7+
\itemize{
78
\item Changes in Rcpp API:
89
\itemize{
910
\item The exception stack message is now correctly demangled on all
1011
compiler versions (Jim Hester in \ghpr{598})
12+
\item Date and Datetime object and vector now have format methods and
13+
\code{operator<<} support (PR\ghpr{599})
1114
}
1215
\item Changes in Rcpp unit tests
1316
\itemize{
@@ -17,8 +20,9 @@
1720
\item Changes in Rcpp Documentation:
1821
\itemize{
1922
\item Exposed pointers macros were included in the Rcpp Extending vignette
20-
(MathurinD; James Balamuta in \ghpr{592} addressing \ghit{418}).
23+
(MathurinD; James Balamuta in \ghpr{592} addressing \ghit{418}).
2124
}
25+
}
2226
}
2327

2428
\section{Changes in Rcpp version 0.12.8 (2016-11-16)}{

inst/include/Rcpp/config.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
#define RCPP_VERSION Rcpp_Version(0,12,8)
3131

3232
// the current source snapshot
33-
#define RCPP_DEV_VERSION RcppDevVersion(0,12,8,0)
33+
#define RCPP_DEV_VERSION RcppDevVersion(0,12,8,1)
3434

3535
#endif
3636

inst/include/Rcpp/date_datetime/Date.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,20 @@ namespace Rcpp {
102102
return m_d;
103103
}
104104

105+
inline std::string format(const char *fmt = "%Y-%m-%d") const {
106+
char txt[32];
107+
struct tm temp = m_tm;
108+
temp.tm_year -= baseYear(); // adjust for fact that system has year rel. to 1900
109+
int res = ::strftime(txt, 31, fmt, &temp);
110+
if (res == 0) {
111+
return std::string("");
112+
} else {
113+
return std::string(txt);
114+
}
115+
}
116+
117+
friend inline std::ostream &operator<<(std::ostream & os, const Date d);
118+
105119
private:
106120
double m_d; // (fractional) day number, relative to epoch of Jan 1, 1970
107121
struct tm m_tm; // standard time representation
@@ -153,6 +167,11 @@ namespace Rcpp {
153167
inline bool operator<=(const Date &d1, const Date& d2) { return d1.m_d <= d2.m_d; }
154168
inline bool operator!=(const Date &d1, const Date& d2) { return d1.m_d != d2.m_d; }
155169

170+
inline std::ostream &operator<<(std::ostream & os, const Date d) {
171+
os << d.format();
172+
return os;
173+
}
174+
156175
namespace internal {
157176

158177
inline SEXP getPosixClasses() {

inst/include/Rcpp/date_datetime/Datetime.h

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,25 @@ namespace Rcpp {
6868

6969
operator double() const { return m_dt; }
7070

71+
inline std::string format(const char *fmt = "%Y-%m-%d %H:%M:%S") const {
72+
char txtiso[64], txtsec[64];
73+
time_t t = static_cast<time_t>(std::floor(m_dt));
74+
struct tm temp = *localtime(&t); // localtime, not gmtime
75+
int res = ::strftime(txtiso, 63, fmt, &temp);
76+
if (res == 0) {
77+
return std::string("");
78+
} else {
79+
res = ::snprintf(txtsec, 63, "%s.%06d", txtiso, m_us);
80+
if (res <= 0) {
81+
return std::string("");
82+
} else {
83+
return std::string(txtsec);
84+
}
85+
}
86+
}
87+
88+
friend inline std::ostream &operator<<(std::ostream & s, const Datetime d);
89+
7190
private:
7291
double m_dt; // fractional seconds since epoch
7392
struct tm m_tm; // standard time representation
@@ -88,6 +107,11 @@ namespace Rcpp {
88107
}
89108
}
90109

110+
// 1900 as per POSIX mktime() et al
111+
static inline unsigned int baseYear() {
112+
return 1900;
113+
}
114+
91115
};
92116

93117

@@ -132,6 +156,11 @@ namespace Rcpp {
132156
inline bool operator<=(const Datetime &d1, const Datetime& d2) { return d1.m_dt <= d2.m_dt; }
133157
inline bool operator!=(const Datetime &d1, const Datetime& d2) { return d1.m_dt != d2.m_dt; }
134158

159+
inline std::ostream &operator<<(std::ostream & os, const Datetime d) {
160+
os << d.format();
161+
return os;
162+
}
163+
135164
}
136165

137166
#endif

inst/include/Rcpp/date_datetime/newDateVector.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,24 @@ namespace Rcpp {
5252
return *this;
5353
}
5454

55+
friend inline std::ostream &operator<<(std::ostream & s, const newDateVector d);
56+
5557
private:
5658

5759
void setClass() {
5860
Shield<SEXP> dateclass(Rf_mkString("Date"));
5961
Rf_setAttrib(*this, R_ClassSymbol, dateclass);
6062
}
6163
};
64+
65+
inline std::ostream &operator<<(std::ostream & os, const newDateVector d) {
66+
int n = d.size();
67+
for (int i=0; i<n; i++) {
68+
os << Date(d[i]).format() << " ";
69+
if ((i+1) % 8 == 0) os << "\n";
70+
}
71+
return os;
72+
}
6273
}
6374

6475
#endif

inst/include/Rcpp/date_datetime/newDatetimeVector.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ namespace Rcpp {
6161
return *this;
6262
}
6363

64+
friend inline std::ostream &operator<<(std::ostream & s, const newDatetimeVector d);
65+
6466
private:
6567

6668
void setClass(const char *tz) {
@@ -75,6 +77,16 @@ namespace Rcpp {
7577
}
7678
}
7779
};
80+
81+
inline std::ostream &operator<<(std::ostream & os, const newDatetimeVector d) {
82+
int n = d.size();
83+
for (int i=0; i<n; i++) {
84+
os << Datetime(d[i]).format() << " ";
85+
if ((i+1) % 4 == 0) os << "\n";
86+
}
87+
return os;
88+
}
89+
7890
}
7991

8092
#endif

inst/unitTests/cpp/dates.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,4 +171,14 @@ DatetimeVector DatetimeVector_assignment(DatetimeVector v1,
171171
DateVector DateVector_assignment(DateVector v1, DateVector v2) {
172172
v1 = v2;
173173
return v1;
174-
}
174+
}
175+
176+
// [[Rcpp::export]]
177+
std::string Date_format(Date d, std::string fmt) {
178+
return d.format(fmt.c_str());
179+
}
180+
181+
// [[Rcpp::export]]
182+
std::string Datetime_format(Datetime d, std::string fmt) {
183+
return d.format(fmt.c_str());
184+
}

inst/unitTests/runit.Date.R

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,19 +181,56 @@ if (.runThisTest) {
181181
checkEquals(fun(vec), c(now, rep(posixtNA, 3), now+2.345), msg = "Datetime.ctor.NA.NaN.Inf.set")
182182
}
183183
}
184-
184+
185185
test.DatetimeVector.assignment <- function() {
186186
now <- Sys.time()
187187
v1 <- c(now, now + 1, now + 2)
188188
v2 <- c(now + 3, now + 4, now + 5)
189189
checkEquals(v2, DatetimeVector_assignment(v1, v2))
190190
}
191-
191+
192192
test.DateVector.assignment <- function() {
193193
now <- Sys.Date()
194194
v1 <- c(now, now + 1, now + 2)
195195
v2 <- c(now + 3, now + 4, now + 5)
196196
checkEquals(v2, DateVector_assignment(v1, v2))
197197
}
198198

199+
200+
## formatting
201+
test.Date.formating <- function() {
202+
oldTZ <- Sys.getenv("TZ")
203+
Sys.setenv(TZ="America/Chicago")
204+
d <- as.Date("2011-12-13")
205+
206+
checkEquals(Date_format(d, "%Y-%m-%d"),
207+
format(d),
208+
msg="Date.formating.default")
209+
checkEquals(Date_format(d, "%Y/%m/%d"),
210+
format(d, "%Y/%m/%d"),
211+
msg="Date.formating.given.format")
212+
213+
Sys.setenv(TZ=oldTZ)
214+
}
215+
216+
test.Datetime.formating <- function() {
217+
oldTZ <- Sys.getenv("TZ")
218+
Sys.setenv(TZ="America/Chicago")
219+
220+
olddigits <- getOption("digits.secs")
221+
options("digits.secs"=6)
222+
223+
d <- as.POSIXct("2016-12-13 14:15:16.123456")
224+
checkEquals(Datetime_format(d,"%Y-%m-%d %H:%M:%S"),
225+
format(d, "%Y-%m-%d %H:%M:%OS"),
226+
msg="Datetime.formating.default")
227+
checkEquals(Datetime_format(d, "%Y/%m/%d %H:%M:%S"),
228+
format(d, "%Y/%m/%d %H:%M:%OS"),
229+
msg="Datetime.formating.given.format")
230+
231+
Sys.setenv(TZ=oldTZ)
232+
options("digits.secs"=olddigits)
233+
}
234+
235+
199236
}

0 commit comments

Comments
 (0)