#ifndef __JSYSTEM__JDATEANDTIME__ #define __JSYSTEM__JDATEANDTIME__ #include #include #include #include #include #include #include "JLang/JComparable.hh" #include "JLang/JException.hh" /** * \file * Date and time functions. * * \author mdejong, bjung */ namespace JSYSTEM {} namespace JPP { using namespace JSYSTEM; } namespace JSYSTEM { using JLANG::JComparable; using JLANG::JIOException; using JLANG::JParseError; /** * Get current local date conform ISO-8601 standard. * * \return date */ inline const char* getDate() { static time_t ts; static const size_t MAX_SIZE = 256; static char buffer[MAX_SIZE]; time(&ts); strftime(buffer, MAX_SIZE, "%F", localtime(&ts)); return buffer; } /** * Get current local time conform ISO-8601 standard. * * \return time */ inline const char* getTime() { static time_t ts; static const size_t MAX_SIZE = 256; static char buffer[MAX_SIZE]; time(&ts); strftime(buffer, MAX_SIZE, "%T%z", localtime(&ts)); return buffer; } /** * Auxiliary class for date and time. * * The data structure time_t is used for the internal value and * the data structure tm for the representation. * * The I/O format conforms with ISO-8601 standard * but it is also possible to parse ROOT TTimeStamp::AsString("c"). */ struct JDateAndTime : JComparable { /** * Constructor. * * \param utc UTC */ JDateAndTime(const bool utc = false) { set(utc); } /** * Constructor. * * \param t1 time [s] * \param utc UTC */ JDateAndTime(const time_t t1, const bool utc = false) { set(t1, utc); } /** * Constructor. * * \param t1 time [s] * \param f1 fraction of seconds * \param utc UTC */ JDateAndTime(const time_t t1, const float f1, const bool utc = false) { set(t1, f1, utc); } /** * Constructor. * * \param buffer date and time */ JDateAndTime(const std::string& buffer) { std::istringstream is(buffer); is >> *this; } /** * Less than method. * * \param object date and time * \result true if this date and time is less than given data and time; else false */ inline bool less(const JDateAndTime& object) const { return getElapsedTime(object) > 0.0; } /** * Smart pointer. * * \return pointer to time structure */ const tm* operator->() const { return get(); } /** * Check if UTC time. * * \return true if UTC time; else false */ bool isUTC() const { return utc; } time_t getTime() const { return ts; } //!< time int getSeconds() const { return get()->tm_sec; } //!< seconds after the minute [0-59] int getMinutes() const { return get()->tm_min; } //!< minutes after the hour [0-59] int getHour() const { return get()->tm_hour; } //!< hours after midnight [0-23] int getDay() const { return get()->tm_mday; } //!< day of the month [1-31] int getMonth() const { return get()->tm_mon + 1; } //!< month of the year [1-12] int getYear() const { return get()->tm_year + 1900; } //!< year a.d. int getDST() const { return get()->tm_isdst; } //!< daylight saving time float getFS() const { return fs; } //!< fraction of second /** * Type conversion operator. * * \return ASCII formatted date and time */ operator std::string() const { return this->toString(); } /** * Function to check ISO-8601 conformity. * * \param buffer date and time * \return true if date and time are ISO-8601 conform; else false */ inline static bool isISO8601(const std::string& buffer) { using namespace std; try { JDateAndTime t1(buffer); return true; } catch(const std::exception& error) { return false; } } /** * Get ASCII formatted date and time. * * \return ASCII formatted date and time */ inline std::string toString() const { using namespace std; static const size_t MAX_SIZE = 256; static char buffer[MAX_SIZE]; const size_t pos = strftime(buffer, MAX_SIZE, (isUTC() ? "%FT%TZ" : "%FT%T%z"), this->get()); return string(buffer, pos); } /** * Set date and time. * * \return date and time */ inline const JDateAndTime& operator()() { set(); return *this; } /** * Set to current local time. * * \param utc UTC */ void set(const bool utc = false) { time_t tx; time(&tx); set(tx, utc); } /** * Set to given time. * * \param t1 time [s] * \param utc UTC */ void set(const time_t t1, const bool utc = false) { this->ts = t1; this->utc = utc; } /** * Set to given time. * * \param t1 time [s] * \param f1 fraction of seconds * \param utc UTC */ void set(const time_t t1, const float f1, const bool utc = false) { this->ts = t1; this->fs = f1; this->utc = utc; } /** * Add given time. * * \param t1 time [s] */ void add(const time_t t1) { set(this->ts + t1, this->utc); } /** * Subtract given time. * * \param t1 time [s] */ void sub(const time_t t1) { set(this->ts - t1, this->utc); } /** * Get elapsed time to given date and time. * * \param object date and time * \return time [s] */ double getElapsedTime(const JDateAndTime& object) const { return difftime(object.ts, this->ts) + (object.fs - this->fs); } /** * Read date and time from input stream. * * \param in input stream * \param object date and time * \return input stream */ friend inline std::istream& operator>>(std::istream& in, JDateAndTime& object) { using namespace std; const size_t LENGTH = 10; // date may contain '-' and/or be followed by ' ' string buffer; for (int c; (c = in.peek()) != EOF && isspace((char) in.peek()); ) { in.ignore(1); } for (int c; (c = in.get()) != EOF && (c != ' ' || buffer.length() == LENGTH); ) { buffer.push_back((char) c); } if (in.bad()) { THROW(JIOException, ""); } // separation of date and time from optional time zone size_t pos = string::npos; if (pos == string::npos) { pos = buffer.find('Z', LENGTH); } // UTC if (pos == string::npos) { pos = buffer.find('+', LENGTH); } // optional time zone if (pos == string::npos) { pos = buffer.find('-', LENGTH); } // optional time zone tm tx; object.fs = 0; // fraction of seconds int nd = 0; const string td = buffer.substr(0, pos); const char* pd = NULL; switch (td.length()) { case 29: case 28: case 27: case 26: case 25: case 24: case 23: case 22: case 21: pd = strptime(td.c_str(), "%Y-%m-%d %H:%M:%S", &tx); sscanf(pd, "%f%n", &object.fs, &nd); pd += nd; break; case 19: pd = strptime(td.c_str(), "%Y-%m-%dT%H:%M:%S", &tx); break; case 15: pd = strptime(td.c_str(), "%Y%m%dT%H%M%s", &tx); break; case 10: pd = strptime(td.c_str(), "%Y-%m-%d", &tx); break; } if (pd == NULL || *pd != '\0') { THROW(JParseError, "invalid input <" << buffer << ">"); } tm ty; ty.tm_hour = 0; ty.tm_min = 0; if (pos != string::npos && (buffer[pos] == '+' || buffer[pos] == '-')) { const string tz = buffer.substr(pos + 1); const char* pz = tz.c_str(); switch (tz.length()) { case 2: pz = strptime(tz.c_str(), "%H", &ty); break; case 4: pz = strptime(tz.c_str(), "%H%M", &ty); break; case 5: pz = strptime(tz.c_str(), "%H:%M", &ty); break; } if (pz == NULL || *pz != '\0') { THROW(JParseError, "invalid input <" << buffer << ">"); } } tx.tm_isdst = 0; // switch off day light saving time time_t t1 = mktime(&tx); t1 -= (ty.tm_hour * 60 + ty.tm_min) * 60; // correct time zone t1 += mktime(localtime(&t1)) - mktime(gmtime(&t1)); // object.set(t1, buffer[pos] == 'Z'); return in; } /** * Write date and time to output stream. * * \param out output stream * \param object date and time * \return output stream */ friend inline std::ostream& operator<<(std::ostream& out, const JDateAndTime& object) { return out << object.toString(); } private: /** * Get representation. */ tm* get() const { return (this->tp = (utc ? gmtime(&ts) : localtime(&ts))); } time_t ts; //!< value float fs = 0.0; //!< fraction of second mutable tm* tp; //!< representation bool utc = false; //!< UTC }; /** * Function object to get current date and time. */ static JDateAndTime getDateAndTime; } #endif