File: Date.h

package info (click to toggle)
rcpp 1.1.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 7,480 kB
  • sloc: cpp: 27,436; ansic: 7,778; sh: 53; makefile: 2
file content (203 lines) | stat: -rw-r--r-- 7,628 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
// -*- mode: C++; c-indent-level: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*-
//
// Date.h: Rcpp R/C++ interface class library -- dates
//
// Copyright (C) 2010 - 2015  Dirk Eddelbuettel and Romain Francois
//
// This file is part of Rcpp.
//
// Rcpp is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 2 of the License, or
// (at your option) any later version.
//
// Rcpp is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Rcpp.  If not, see <http://www.gnu.org/licenses/>.

#ifndef Rcpp__Date_h
#define Rcpp__Date_h

#if defined(WIN32) || defined(__WIN32) || defined(__WIN32__)
#include <time.h>
#endif

namespace Rcpp {

    class Date {
    public:
        Date() {
            m_d = 0;
            update_tm();
        }
        Date(SEXP s);

        // from integer (with negative dates before Jan 1, 1970)
        Date(const int &dt) {
            m_d = dt;
            update_tm();
        }

        // from fractional integer since epoch, just like R
        Date(const double &dt) {
            m_d = dt;
            update_tm();
        }
        Date(const std::string &s, const std::string &fmt="%Y-%m-%d");

        Date(const unsigned int &mon, const unsigned int &day, const unsigned int &year) {
            m_tm.tm_sec = m_tm.tm_min = m_tm.tm_hour = m_tm.tm_isdst = 0;

            // allow for ISO-notation case (yyyy, mm, dd) which we prefer over (mm, dd, year)
            if (mon >= baseYear() && day <= 12 && year <= 31) {
                m_tm.tm_year = mon - baseYear();
                m_tm.tm_mon  = day - 1;     // range 0 to 11
                m_tm.tm_mday = year;
            } else {
                m_tm.tm_mday  = day;
                m_tm.tm_mon   = mon - 1;    // range 0 to 11
                m_tm.tm_year  = year - baseYear();
            }
            double tmp = mktime00(m_tm);    // use mktime() replacement borrowed from R
            m_tm.tm_year += baseYear();    // we'd rather keep it as a normal year
            m_d = tmp/(24*60*60);
        }

        double getDate(void) const {
            return m_d;
        }

        // intra-day useless for date class
        //int getSeconds() const { return m_tm.tm_sec; }
        //int getMinutes() const { return m_tm.tm_min; }
        //int getHours()   const { return m_tm.tm_hour; }
        int getDay()     const { return m_tm.tm_mday; }
        int getMonth()   const { return m_tm.tm_mon + 1; }      // makes it 1 .. 12
        int getYear()    const { return m_tm.tm_year; }         // does include 1900 (see Date.cpp)
        int getWeekday() const { return m_tm.tm_wday + 1; }     // makes it 1 .. 7
        int getYearday() const { return m_tm.tm_yday + 1; }     // makes it 1 .. 366

        // 1900 as per POSIX mktime() et al
        static inline unsigned int baseYear() {
            return 1900;
        }

        // Minimal set of date operations.
        friend Date   operator+( const Date &date, int offset);
        friend double operator-( const Date &date1, const Date& date2);
        friend bool   operator<( const Date &date1, const Date& date2);
        friend bool   operator>( const Date &date1, const Date& date2);
        friend bool   operator==(const Date &date1, const Date& date2);
        friend bool   operator>=(const Date &date1, const Date& date2);
        friend bool   operator<=(const Date &date1, const Date& date2);
        friend bool   operator!=(const Date &date1, const Date& date2);

        inline int is_na() const {
           return traits::is_na<REALSXP>(m_d);
        }

        operator double() const {
            return m_d;
        }

        inline std::string format(const char *fmt = "%Y-%m-%d") const {
            char txt[32];
            struct tm temp = m_tm;
            temp.tm_year -= baseYear();    // adjust for fact that system has year rel. to 1900
            size_t res = ::strftime(txt, 31, fmt, &temp);
            if (res == 0) {
                return std::string("");
            } else {
                return std::string(txt);
            }
        }

        friend inline std::ostream &operator<<(std::ostream & os, const Date d);

    private:
        double m_d;                 // (fractional) day number, relative to epoch of Jan 1, 1970
        struct tm m_tm;             // standard time representation

        // update m_tm based on m_d
        void update_tm() {
            if (R_FINITE(m_d)) {
                time_t t = static_cast<time_t>(24*60*60 * m_d);      // (fractional) days since epoch to seconds since epoch
                m_tm = *gmtime_(&t);
            } else {
                m_tm.tm_sec = m_tm.tm_min = m_tm.tm_hour = m_tm.tm_isdst = NA_INTEGER;
                m_tm.tm_min = m_tm.tm_hour = m_tm.tm_mday = m_tm.tm_mon  = m_tm.tm_year = NA_INTEGER;
            }
        }

    };

    // template specialisation for wrap() on the date
    template <> SEXP wrap<Rcpp::Date>(const Rcpp::Date &date);

    // needed to wrap containers of Date such as vector<Date> or map<string,Date>
    namespace internal {
        template<> inline double caster<Rcpp::Date,double>(Rcpp::Date from) {
            return static_cast<double>(from.getDate());
        }
        template<> inline Rcpp::Date caster<double,Rcpp::Date>(double from) {
            return Rcpp::Date(static_cast<int>(from));
        }
    }

    template<> inline SEXP wrap_extra_steps<Rcpp::Date>(SEXP x) {
        Rf_setAttrib(x, R_ClassSymbol, Rf_mkString("Date"));
        return x;
    }

    inline Date operator+(const Date &date, int offset) {
        Date newdate(date.m_d);
        newdate.m_d += offset;
        time_t t = static_cast<time_t>(24*60*60 * newdate.m_d);  // days since epoch to seconds since epo
        newdate.m_tm = *gmtime_(&t);
        return newdate;
    }

    inline double operator-( const Date& d1, const Date& d2) { return d1.m_d -  d2.m_d; }
    inline bool   operator<( const Date &d1, const Date& d2) { return d1.m_d <  d2.m_d; }
    inline bool   operator>( const Date &d1, const Date& d2) { return d1.m_d >  d2.m_d; }
    inline bool   operator==(const Date &d1, const Date& d2) { return d1.m_d == d2.m_d; }
    inline bool   operator>=(const Date &d1, const Date& d2) { return d1.m_d >= d2.m_d; }
    inline bool   operator<=(const Date &d1, const Date& d2) { return d1.m_d <= d2.m_d; }
    inline bool   operator!=(const Date &d1, const Date& d2) { return d1.m_d != d2.m_d; }

    inline std::ostream &operator<<(std::ostream & os, const Date d) {
        os << d.format();
        return os;
    }

    namespace internal {

        inline SEXP getPosixClasses() {
            Shield<SEXP> datetimeclass(Rf_allocVector(STRSXP,2));
            SET_STRING_ELT(datetimeclass, 0, Rf_mkChar("POSIXct"));
            SET_STRING_ELT(datetimeclass, 1, Rf_mkChar("POSIXt"));
            return datetimeclass;
        }

        inline SEXP new_posixt_object( double d) {
            Shield<SEXP> x(Rf_ScalarReal(d));
            Rf_setAttrib(x, R_ClassSymbol, getPosixClasses());
            return x;
        }

        inline SEXP new_date_object(double d) {
            Shield<SEXP> x(Rf_ScalarReal(d));
            Rf_setAttrib(x, R_ClassSymbol, Rf_mkString("Date"));
            return x;
        }

    }


}

#endif