implement basic operations over class Time
[libi2ncommon] / src / timefunc.cpp
index 6792e20..30df7a6 100644 (file)
@@ -1,13 +1,29 @@
+/*
+The software in this package is distributed under the GNU General
+Public License version 2 (with a special exception described below).
+
+A copy of GNU General Public License (GPL) is included in this distribution,
+in the file COPYING.GPL.
+
+As a special exception, if other files instantiate templates or use macros
+or inline functions from this file, or you compile this file and link it
+with other works to produce a work based on this file, this file
+does not by itself cause the resulting work to be covered
+by the GNU General Public License.
+
+However the source code for this file must still be made available
+in accordance with section (3) of the GNU General Public License.
+
+This exception does not invalidate any other reasons why a work based
+on this file might be covered by the GNU General Public License.
+*/
 /** @file
  * @brief time related functions.
  *
  * @copyright Copyright © 2001-2008 by Intra2net AG
- * @license commercial
- * @contact info@intra2net.com
  *
  */
 
-
 #include <string>
 #include <sstream>
 #include <iostream>
@@ -19,8 +35,8 @@
 
 #include <time.h>
 #include <unistd.h>
+#include <string.h>
 #include <sys/timeb.h>
-#include <sys/syscall.h>
 
 #include <timefunc.hxx>
 #include <i18n.h>
@@ -52,9 +68,10 @@ double prec_time(void)
 }
 
 // converts ISO-DATE: 2003-06-13
-int date_to_seconds(const std::string &date)
+time_t date_to_seconds(const std::string &date)
 {
-    int rtn = -1, year = -1, month = -1, day = -1;
+    time_t rtn = 0;
+    int year = -1, month = -1, day = -1;
     
     string::size_type pos = date.find("-");
     if (pos == string::npos)
@@ -79,9 +96,9 @@ int date_to_seconds(const std::string &date)
     
     if (year < 0 || month == -1 || day == -1)
         return rtn;
-    
+
     struct tm tm_struct;
-    bzero (&tm_struct, sizeof(struct tm));
+    memset(&tm_struct, 0, sizeof(struct tm));
     tm_struct.tm_year = year;
     tm_struct.tm_mon = month;
     tm_struct.tm_mday = day;
@@ -98,16 +115,11 @@ string make_nice_time(int seconds)
     int days=seconds/86400;
     seconds%=86400;
 
-    int hours=seconds/3600;
-    seconds%=3600;
-
-    int minutes=seconds/60;
-    seconds%=60;
-
-    if (days==1)
-        out << i18n("1 day") << ", ";
-    else if (days>1)
-        out << days << ' ' << i18n("days") << ", ";
+    int hours,minutes;
+    split_daysec(seconds,&hours,&minutes,&seconds);
+    
+    if (days>0)
+        out << days << " " << i18n_plural("day", "days", days) << ", ";
 
     out << setfill('0');
     out << setw(2) << hours << ':' << setw(2) << minutes << ':' << setw(2) << seconds;
@@ -115,13 +127,27 @@ string make_nice_time(int seconds)
     return out.str();
 }
 
-string format_full_time(int seconds)
+string format_full_time(time_t seconds)
+{
+    char buf[50];
+    memset (buf, 0, 50);
+    struct tm ta;
+    if (localtime_r((time_t *)&seconds, &ta) == NULL)
+        memset (&ta, 0, sizeof(struct tm));
+
+    strftime (buf, 49, "%d.%m.%Y %H:%M", &ta);
+    return string(buf);
+}
+
+string format_date(time_t seconds)
 {
     char buf[50];
     memset (buf, 0, 50);
-    struct tm *ta = localtime ((time_t *)&seconds);
+    struct tm ta;
+    if (localtime_r((time_t *)&seconds, &ta) == NULL)
+        memset (&ta, 0, sizeof(struct tm));
 
-    strftime (buf, 49, "%d.%m.%Y %H:%M", ta);
+    strftime (buf, 49, "%d.%m.%Y", &ta);
     return string(buf);
 }
 
@@ -144,7 +170,32 @@ void seconds_to_hour_minute(int seconds, int *hour, int *minute)
     }
 }
 
-std::string output_hour_minute(int hour, int minute, bool h_for_00)
+/**
+    * Split seconds into hours, minutes and seconds
+    * @param [in] daysec Seconds since start of day
+    * @param [out] outhours hours
+    * @param [out] outminutes minutes
+    * @param [out] outseconds seconds
+    */
+void split_daysec(int daysec, int *outhours, int *outminutes, int *outseconds)
+{
+    int hours=daysec/3600;
+    daysec%=3600;
+
+    int minutes=daysec/60;
+    daysec%=60;
+
+    if (outhours)
+        *outhours=hours;
+
+    if (outminutes)
+        *outminutes=minutes;
+
+    if (outseconds)
+        *outseconds=daysec;
+}
+
+std::string output_hour_minute(int hour, int minute, bool h_for_00, int seconds)
 {
     ostringstream out;
     
@@ -152,7 +203,7 @@ std::string output_hour_minute(int hour, int minute, bool h_for_00)
         out << '0';
     out << hour;
     
-    if (!h_for_00 || minute != 0)
+    if (!h_for_00 || minute != 0 || seconds > 0)
     {
         out << ':';
         if (minute >= 0 && minute < 10)
@@ -162,165 +213,17 @@ std::string output_hour_minute(int hour, int minute, bool h_for_00)
     else
         out << 'h';
 
-    return out.str();
-}
-
-void WEEK::set(const std::string& daystring)
-{
-    int len=daystring.length();
-    for (int p=0; p < len; p++)
+    if (seconds > 0)
     {
-        char nr[2];
-        nr[0]=daystring[p];
-        nr[1]=0;
-        istringstream c(nr);
-        int wnr=-1;
-        if (!(c >> wnr) || wnr<0 || wnr >6)
-            throw range_error("illegal weekday >"+string(nr)+"< in "+daystring);
-
-        days.set(wnr);
+        out << ':';
+        if (seconds > 0 && seconds < 10)
+            out << '0';
+        out << seconds;
     }
-}
-
-std::string WEEK::get_daystring() const
-{
-    ostringstream out;
-    for (int i = 0; i < 7; i++)
-        if (days[i])
-            out << i;
 
     return out.str();
 }
 
-std::string WEEK::get_displaystring() const
-{
-    string weekdays_str;
-
-    // From Monday to Saturday
-    int j;
-    for (int i = 1; i < 7; i++)
-    {
-        if (days[i])
-        {
-            if (!weekdays_str.empty())
-                weekdays_str += ", ";
-
-            weekdays_str += get_day_display(static_cast<WEEKDAY>(i));
-
-            // check if we can group two or more days
-            j = i;
-            while (days[j] && j < 7)
-                j++;
-            j--;
-
-            // Sunday end of week? j -> 7
-            if (j-i > 0 && j == 6 && days[0])
-                j++;
-
-            if (j-i > 1) 
-            {
-                if (j == 7)
-                    weekdays_str += "-" + get_day_display(SU);
-                else
-                    weekdays_str += "-" + get_day_display(static_cast<WEEKDAY>(j));
-
-                i = j;
-            }
-        }
-    }
-
-    // special: sunday
-    if (days[0] && j != 7) 
-    {
-        if (!weekdays_str.empty())
-            weekdays_str += ", ";
-
-        weekdays_str += get_day_display(SU);
-    }
-
-    return weekdays_str;
-}
-
-std::string WEEK::get_netfilterstring() const
-{
-    string out;
-    for (int i = 0; i < 7; i++)
-        if (days[i])
-        {
-            if (!out.empty())
-                out+=","; 
-            out+=get_english_display(static_cast<WEEKDAY>(i));;
-        }
-            
-    return out;
-}
-
-std::string WEEK::get_day_display(WEEKDAY day)
-{
-    string weekday_str;
-
-    switch (day) {
-        case MO:
-            weekday_str = i18n("Mon");
-            break;
-        case TU:
-            weekday_str = i18n("Tue");
-            break;
-        case WE:
-            weekday_str = i18n("Wed");
-            break;
-        case TH:
-            weekday_str = i18n("Thu");
-            break;
-        case FR:
-            weekday_str = i18n("Fri");
-            break;
-        case SA:
-            weekday_str = i18n("Sat");
-            break;
-        case SU:
-            weekday_str = i18n("Sun");
-            break;
-        default:
-            break;
-    }
-
-    return weekday_str;
-}
-
-std::string WEEK::get_english_display(WEEKDAY day)
-{
-    string weekday_str;
-
-    switch (day) {
-        case MO:
-            weekday_str = "Mon";
-            break;
-        case TU:
-            weekday_str = "Tue";
-            break;
-        case WE:
-            weekday_str = "Wed";
-            break;
-        case TH:
-            weekday_str = "Thu";
-            break;
-        case FR:
-            weekday_str = "Fri";
-            break;
-        case SA:
-            weekday_str = "Sat";
-            break;
-        case SU:
-            weekday_str = "Sun";
-            break;
-        default:
-            break;
-    }
-
-    return weekday_str;
-}
-
 string get_month_name(unsigned char month)
 {
     string rtn;
@@ -819,7 +722,7 @@ Intervals& Intervals::operator-=(const Intervals& other)
 bool monotonic_clock_gettime(long int& seconds, long int& nano_seconds)
 {
     struct timespec tp[1];
-    int res= ::syscall(__NR_clock_gettime, CLOCK_MONOTONIC, tp);
+    int res= clock_gettime (CLOCK_MONOTONIC, tp);
     if (0 == res)
     {
         seconds= tp->tv_sec;
@@ -831,6 +734,26 @@ bool monotonic_clock_gettime(long int& seconds, long int& nano_seconds)
 
 /**
  * @brief fetches the value from the monotonic clock source.
+ * @return the time since system start in nanoseconds, 0 if read was unsuccessful
+ */
+long long monotonic_clock_gettime_nano()
+{
+    long int seconds;
+    long int nano_seconds;
+    long long nano=0;
+
+    if (monotonic_clock_gettime(seconds,nano_seconds))
+    {
+        nano=seconds;
+        nano*=1000000000LL;
+        nano+=nano_seconds;
+    }
+
+    return nano;
+}
+
+/**
+ * @brief fetches the value from the monotonic clock source.
  * @param[out] seconds the seconds.
  * @param[out] nano_seconds the nano seconds.
  * @return @a true if the clock was successfully read.
@@ -838,7 +761,7 @@ bool monotonic_clock_gettime(long int& seconds, long int& nano_seconds)
 bool realtime_clock_gettime(long int& seconds, long int& nano_seconds)
 {
     struct timespec tp[1];
-    int res= ::syscall(__NR_clock_gettime, CLOCK_REALTIME, tp);
+    int res= clock_gettime(CLOCK_REALTIME, tp);
     if (0 == res)
     {
         seconds= tp->tv_sec;
@@ -848,3 +771,205 @@ bool realtime_clock_gettime(long int& seconds, long int& nano_seconds)
 } // eo realtime_clock_gettime(long int&,long int&)
 
 
+namespace I2n {
+
+namespace clock {
+
+    namespace {
+
+        static inline clockid_t
+        clockid_of_flags (const enum type::id      id,
+                          const enum type::variant var) NOEXCEPT
+        {
+            clockid_t cid = CLOCK_MONOTONIC_COARSE;
+
+            switch (id) {
+
+                default:
+                case type::mono: {
+                    switch (var) {
+                        default: {
+                            break;
+                        }
+                        case type::raw: {
+                            cid = CLOCK_MONOTONIC_RAW;
+                            break;
+                        }
+                        case type::exact: {
+                            cid = CLOCK_MONOTONIC;
+                            break;
+                        }
+                    }
+                    break;
+                }
+
+                case type::real: {
+                    if (var == type::exact) {
+                        cid = CLOCK_REALTIME;
+                    } else {
+                        cid = CLOCK_REALTIME_COARSE;
+                    }
+                    break;
+                }
+
+                case type::boot: {
+                    if (var & type::exact) {
+                        cid = CLOCK_BOOTTIME;
+                    }
+                    break;
+                }
+
+                case type::cpu: {
+                    if (var == type::thread) {
+                        cid = CLOCK_THREAD_CPUTIME_ID;
+                    } else {
+                        cid = CLOCK_PROCESS_CPUTIME_ID;
+                    }
+                    break;
+                }
+            } /* [switch id] */
+
+            return cid;
+        }
+
+        static const struct timespec zero_time = { 0, 0 };
+
+    } /* [namespace] */
+
+    Time::Time (const enum type::id id,
+                const enum type::variant var) NOEXCEPT
+        : value   (zero_time)
+        , id      (id)
+        , variant (var)
+        , err     (0)
+    { }
+
+    int64_t
+    Time::as_nanosec (void) const NOEXCEPT
+    {
+        return int64_t (this->value.tv_sec) * TIME_CONST_FACTOR_NANO
+             + this->value.tv_nsec;
+    }
+
+    long
+    Time::as_nanosec_L (void) const NOEXCEPT /* likely to overflow */
+    { return static_cast<long>(this->as_nanosec ()); }
+
+    Time &
+    Time::operator= (Time t2) NOEXCEPT
+    {
+        this->swap (t2);
+
+        return *this;
+    }
+
+    Time &
+    Time::operator= (struct timespec ts) NOEXCEPT
+    {
+        std::swap (this->value, ts);
+        this->id      = clock::type::mono;
+        this->variant = clock::type::dflt;
+        this->err     = 0;
+
+        return *this;
+    }
+
+    void
+    Time::unset (void) NOEXCEPT
+    { this->value = zero_time; }
+
+    bool
+    Time::set (void) NOEXCEPT
+    {
+        struct timespec now;
+
+        errno = 0;
+        if (clock_gettime (clockid_of_flags (this->id, this->variant), &now)
+            == -1)
+        {
+            this->err = errno;
+            this->unset ();
+
+            return false;
+        }
+        this->err   = 0;
+        this->value = now;
+
+        return true;
+    }
+
+    Time &
+    Time::add (const time_t sec, const long nsec) NOEXCEPT
+    {
+        this->value.tv_sec  += sec;
+        this->value.tv_nsec += nsec;
+
+        this->carry_nsec ();
+
+        return *this;
+    }
+
+    Time &
+    Time::subtract (const time_t sec, const long nsec) NOEXCEPT
+    {
+        this->value.tv_sec  -= sec;
+        this->value.tv_nsec -= nsec;
+
+        this->carry_nsec ();
+
+        return *this;
+    }
+
+    Time &
+    Time::scale (const time_t factor) NOEXCEPT
+    {
+        this->value.tv_sec  *= factor;
+        this->value.tv_nsec *= factor;
+
+        this->carry_nsec ();
+
+        return *this;
+    }
+
+    boost::optional<Time>
+    now (const enum type::id id, const enum type::variant var) NOEXCEPT
+    {
+        Time ret (id, var);
+
+        if (!ret.set ()) {
+            return boost::none;
+        }
+
+        return ret;
+    }
+
+    Time
+    zero (const enum type::id id, const enum type::variant var) NOEXCEPT
+    { return Time (id, var); }
+
+    int
+    compare (const Time &t1, const Time &t2) NOEXCEPT
+    {
+        if (t1.value.tv_sec < t2.value.tv_sec) {
+            return -1;
+        }
+
+        if (t1.value.tv_sec > t2.value.tv_sec) {
+            return 1;
+        }
+
+        if (t1.value.tv_nsec < t2.value.tv_nsec) {
+            return -1;
+        }
+
+        if (t1.value.tv_nsec > t2.value.tv_nsec) {
+            return 1;
+        }
+
+        return 0;
+    }
+
+} /* [namespace clock] */
+
+} /* [namespace I2n] */
+