#ifndef __JSYSTEM__JDATE__ #define __JSYSTEM__JDATE__ #include #include #include #include #include #include "JLang/JException.hh" /** * \file * Date and time functions. * * \author mdejong, bjung */ namespace JSYSTEM {} namespace JPP { using namespace JSYSTEM; } namespace JSYSTEM { using JLANG::JValueOutOfRange; using JLANG::JParseError; /** * Get current 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 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 { /** * Default constructor. */ JDateAndTime() { set(); } /** * Constructor. * * \param t1 time * \param utc UTC */ JDateAndTime(const time_t t1, const bool utc = false) { set(t1, utc); } /** * Constructor. * * \param buffer date and time */ JDateAndTime(const std::string& buffer) { using namespace std; // separation of date and time from optional time zone const size_t pos = (buffer.find('Z') != string::npos ? buffer.find('Z') : buffer.find('+') != string::npos ? buffer.find('+') : buffer.rfind('-')); if (pos == string::npos) { THROW(JParseError, "invalid input <" << buffer << ">"); } tm tx; long ns = 0; const string td = buffer.substr(0, pos); const char* pd = NULL; switch (td.length()) { case 29: pd = strptime(td.c_str(), "%Y-%m-%d %H:%M:%S.", &tx); sscanf(pd, "%9ld", &ns); pd += 9; 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; const string tz = buffer.substr(pos + 1); const char* pz = tz.c_str(); ty.tm_hour = 0; ty.tm_min = 0; switch (tz.length()) { case 0: break; 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; time_t t1 = mktime(&tx); t1 -= (ty.tm_hour * 60 + ty.tm_min) * 60; // apply read time zone t1 += mktime(localtime(&t1)) - mktime(gmtime(&t1)); // set(t1, buffer[pos] == 'Z'); } /** * Smart pointer. * * \return pointer to time structure */ const tm* operator->() const { return this->tp; } /** * Smart pointer. * * \return pointer to time structure */ tm* operator->() { return this->tp; } /** * 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 tp->tm_sec; } //!< seconds after the minute [0-59] int getMinutes() const { return tp->tm_min; } //!< minutes after the hour [0-59] int getHour() const { return tp->tm_hour; } //!< hours after midnight [0-23] int getDay() const { return tp->tm_mday; } //!< day of the month [1-31] int getMonth() const { return tp->tm_mon + 1; } //!< month of the year [1-12] int getYear() const { return tp->tm_year + 1900; } //!< year a.d. int getDST() const { return tp->tm_isdst; } //!< daylight saving time /** * 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->tp); 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 * \param utc UTC */ void set(const time_t t1, const bool utc = false) { this->ts = t1; this->tp = (utc ? gmtime(&t1) : localtime(&t1)); this->utc = utc; } /** * Add given time. * * \param t1 time */ void add(const time_t t1) { set(this->ts + t1, this->utc); } /** * Subtract given time. * * \param t1 time */ 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); } /** * 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) { std::string buffer; if (in >> buffer) { object = JDateAndTime(buffer); } 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: time_t ts; //!< value tm* tp; //!< representation bool utc = false; //!< UTC }; /** * Function object to get current date and time. */ static JDateAndTime getDateAndTime; } #endif