]> git.ipfire.org Git - thirdparty/rrdtool-1.x.git/commitdiff
Add --utc to graph option. 1088/head
authorJean-Yves Avenard <jean-yves@avenard.org>
Thu, 17 Jan 2013 18:20:36 +0000 (05:20 +1100)
committerJean-Yves Avenard <jyavenard@mozilla.com>
Tue, 21 Jul 2020 13:04:52 +0000 (23:04 +1000)
Allow to generate a graph as if the current timezone was UTC (e.g set TZ=UTC).
This allows to easily calculate daily average ranging from midgnight to midnight rather than say the last 24 hours.

bindings/python/rrdtoolmodule.c
doc/rrdgraph.pod
src/rrd_graph.c
src/rrd_graph.h
src/rrd_tool.c

index f02058204e3919c9ecd13f0da371662bb5757d29..1ab4635848ed3c5a502442e38f3d60c340a02b2d 100644 (file)
@@ -582,6 +582,7 @@ static char _rrdtool_graph__doc__[] = "Create a graph based on one or more " \
     [-b|--base value]\n\
     [-W|--watermark string]\n\
     [-Z|--use-nan-for-all-missing-data]\n\
+    [--utc]\n\
     DEF:vname=rrdfile:ds-name:CF[:step=step][:start=time][:end=time]\n\
     CDEF:vname=RPN expression\n\
     VDEF=vname:RPN expression\n\n\
@@ -1094,7 +1095,7 @@ _rrdtool_lastupdate(PyObject *Py_UNUSED(self), PyObject *args)
             }
 
             PyDict_SetItemString(ds_dict, ds_names[i], val);
-            
+
             if (val != Py_None)
                 Py_DECREF(val);
 
@@ -1204,7 +1205,7 @@ _rrdtool_fetch_cb_wrapper(
         rrd_set_error("expected 'start' key in callback return value to be "
             "of type int");
         goto gil_release_err;
-    } else if (PyObject_RichCompareBool(tmp, tmp_min_ts, Py_EQ) || 
+    } else if (PyObject_RichCompareBool(tmp, tmp_min_ts, Py_EQ) ||
                PyObject_RichCompareBool(tmp, po_start, Py_LT)) {
         rrd_set_error("expected 'start' value in callback return dict to be "
             "equal or earlier than passed start timestamp");
index 71ee3d851953a6acfbabd1f9f84042047911c1bd..ad13726f5617a5b04eb9964f1fada38fd941586e 100644 (file)
@@ -562,6 +562,11 @@ If one DS is missing, either because the RRD is not available or
 because it does not contain the requested DS name, just assume that we
 got empty values instead of raising a fatal error.
 
+[B<--utc>]
+
+Force the timezone to be UTC. Equivalent to doing TZ=UTC rrdtool graph .... 
+This is useful to calculate daily average ranging from midnight to midnight rather than say the last 24 hours.
+
 =head2 Data and variables
 
 B<DEF:>I<vname>B<=>I<rrdfile>B<:>I<ds-name>B<:>I<CF>[B<:step=>I<step>][B<:start=>I<time>][B<:end=>I<time>]
index bf7742923624279370b668f659c9b9bb49722ff7..17496ec9ed3fb0967b33ce8cb81490126135db3b 100644 (file)
 #include "plbasename.h"
 #endif
 
-#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__CYGWIN32__)
+#if defined(_WIN32)
+#define timegm _mkgmtime
+#if !defined(__CYGWIN__) && !defined(__CYGWIN32__)
 #include <io.h>
 #include <fcntl.h>
 #endif
+#endif
 
 #include <time.h>
+#define LOCALTIME_R(a,b,c) (c ? gmtime_r(a,b) : localtime_r(a,b))
+#define MKTIME(a,b) (b ? timegm(a) : mktime(a))
 
 #include <locale.h>
 
@@ -1544,12 +1549,13 @@ int data_proc(
 time_t find_first_time(
     time_t start,       /* what is the initial time */
     enum tmt_en baseint,    /* what is the basic interval */
-    long basestep       /* how many if these do we jump a time */
+    long basestep,      /* how many if these do we jump a time */
+    int utc             /* set to 1 if we force the UTC timezone */
     )
 {
     struct tm tm;
 
-    localtime_r(&start, &tm);
+    LOCALTIME_R(&start, &tm, utc);
 
     switch (baseint) {
     case TMT_SECOND:
@@ -1605,20 +1611,21 @@ time_t find_first_time(
     tm.tm_year + 1900) %basestep;
 
     }
-    return mktime(&tm);
+    return MKTIME(&tm, utc);
 }
 
 /* identify the point where the next gridline, label ... gets placed */
 time_t find_next_time(
     time_t current,     /* what is the initial time */
     enum tmt_en baseint,    /* what is the basic interval */
-    long basestep       /* how many if these do we jump a time */
+    long basestep,      /* how many if these do we jump a time */
+    int utc             /* set to 1 if we force the UTC timezone */
     )
 {
     struct tm tm;
     time_t    madetime;
 
-    localtime_r(&current, &tm);
+    LOCALTIME_R(&current, &tm, utc);
 
     /* let mktime figure this dst on its own */
     //tm.tm_isdst = -1;
@@ -1668,7 +1675,7 @@ time_t find_next_time(
         case TMT_YEAR:
             tm.       tm_year += basestep;
         }
-        madetime = mktime(&tm);
+        madetime = MKTIME(&tm, utc);
     } while (madetime == -1 && limit-- >= 0);   /* this is necessary to skip impossible times
                                                    like the daylight saving time skips */
     return madetime;
@@ -1840,7 +1847,7 @@ int print_calc(
     /* wow initializing tmvdef is quite a task :-) */
     time_t    now = time(NULL);
 
-    localtime_r(&now, &tmvdef);
+    LOCALTIME_R(&now, &tmvdef, im->extra_flags & FORCE_UTC_TIME);
     for (i = 0; i < im->gdes_c; i++) {
         vidx = im->gdes[i].vidx;
         switch (im->gdes[i].gf) {
@@ -1852,7 +1859,7 @@ int print_calc(
              */
             if (im->gdes[vidx].gf == GF_VDEF) { /* simply use vals */
                 printval = im->gdes[vidx].vf.val;
-                localtime_r(&im->gdes[vidx].vf.when, &tmvdef);
+                LOCALTIME_R(&im->gdes[vidx].vf.when, &tmvdef, im->extra_flags & FORCE_UTC_TIME);
             } else {    /* need to calculate max,min,avg etcetera */
                 max_ii = ((im->gdes[vidx].end - im->gdes[vidx].start)
                           / im->gdes[vidx].step * im->gdes[vidx].ds_cnt);
@@ -3021,14 +3028,19 @@ void vertical_grid(
     if (!(im->extra_flags & NOMINOR)) {
         for (ti = find_first_time(im->start,
                                   im->xlab_user.gridtm,
-                                  im->xlab_user.gridst),
+                                  im->xlab_user.gridst,
+                                  im->extra_flags & FORCE_UTC_TIME),
              timajor =
              find_first_time(im->start,
                              im->xlab_user.mgridtm,
-                             im->xlab_user.mgridst);
+                             im->xlab_user.mgridst,
+                             im->extra_flags & FORCE_UTC_TIME);
              ti < im->end && ti != -1;
              ti =
-             find_next_time(ti, im->xlab_user.gridtm, im->xlab_user.gridst)
+             find_next_time(ti,
+                            im->xlab_user.gridtm,
+                            im->xlab_user.gridst,
+                            im->extra_flags & FORCE_UTC_TIME)
             ) {
             /* are we inside the graph ? */
             if (ti < im->start || ti > im->end)
@@ -3036,7 +3048,8 @@ void vertical_grid(
             while (timajor < ti && timajor != -1) {
                 timajor = find_next_time(timajor,
                                          im->xlab_user.mgridtm,
-                                         im->xlab_user.mgridst);
+                                         im->xlab_user.mgridst,
+                                         im->extra_flags & FORCE_UTC_TIME);
             }
             if (timajor == -1)
                 break;  /* fail in case of problems with time increments */
@@ -3057,9 +3070,13 @@ void vertical_grid(
     /* paint the major grid */
     for (ti = find_first_time(im->start,
                               im->xlab_user.mgridtm,
-                              im->xlab_user.mgridst);
+                              im->xlab_user.mgridst,
+                              im->extra_flags & FORCE_UTC_TIME);
          ti < im->end && ti != -1;
-         ti = find_next_time(ti, im->xlab_user.mgridtm, im->xlab_user.mgridst)
+         ti = find_next_time(ti,
+                             im->xlab_user.mgridtm,
+                             im->xlab_user.mgridst,
+                             im->extra_flags & FORCE_UTC_TIME)
         ) {
         /* are we inside the graph ? */
         if (ti < im->start || ti > im->end)
@@ -3079,18 +3096,22 @@ void vertical_grid(
          find_first_time(im->start -
                          im->xlab_user.precis / 2,
                          im->xlab_user.labtm,
-                         im->xlab_user.labst);
+                         im->xlab_user.labst,
+                         im->extra_flags & FORCE_UTC_TIME);
          (ti <=
           im->end -
           im->xlab_user.precis / 2) && ti != -1;
-         ti = find_next_time(ti, im->xlab_user.labtm, im->xlab_user.labst)
+         ti = find_next_time(ti,
+                             im->xlab_user.labtm,
+                             im->xlab_user.labst,
+                             im->extra_flags & FORCE_UTC_TIME)
         ) {
         tilab = ti + im->xlab_user.precis / 2;  /* correct time for the label */
         /* are we inside the graph ? */
         if (tilab < im->start || tilab > im->end)
             continue;
 #ifdef HAVE_STRFTIME
-        localtime_r(&tilab, &tm);
+        LOCALTIME_R(&tilab, &tm, im->extra_flags & FORCE_UTC_TIME);
         strftime(graph_label, 99, im->xlab_user.stst, &tm);
 #else
 # error "your libc has no strftime I guess we'll abort the exercise here."
@@ -5009,7 +5030,8 @@ void rrd_graph_options(
         {"left-axis-format",   1012, OPTPARSE_REQUIRED},
         {"left-axis-formatter",1013, OPTPARSE_REQUIRED},
         {"right-axis-formatter",1014, OPTPARSE_REQUIRED},
-        {"allow-shrink",        1015, OPTPARSE_NONE},
+        {"allow-shrink",       1015, OPTPARSE_NONE},
+        {"utc",                1016, OPTPARSE_NONE},
         {0}
 };
 /* *INDENT-ON* */
@@ -5360,6 +5382,9 @@ void rrd_graph_options(
                 return;
             }
             break;
+        case 1016:
+            im->extra_flags |= FORCE_UTC_TIME;
+            break;
         case 'z':
             im->lazy = 1;
             break;
index a2f4faa4bf7f0629bf8b9b1b2564ed1821e620f8..b2e622b2d88b34b27049cf242a1a276d63863dd4 100644 (file)
@@ -45,6 +45,7 @@
 #define FULL_SIZE_MODE     0x200    /* -width and -height indicate the total size of the image */
 #define NO_RRDTOOL_TAG 0x400  /* disable the rrdtool tag */
 #define ALLOW_MISSING_DS 0x800  /* missing DS is not fatal */
+#define FORCE_UTC_TIME 0x1000   /* Work in UTC timezone instead of localtimg */
 
 #define gdes_fetch_key(x)  sprintf_alloc("%s:%s:%d:%d:%d:%d:%d:%d",x.rrd,x.daemon,x.cf,x.cf_reduce,x.start_orig,x.end_orig,x.step_orig,x.step)
 
@@ -415,11 +416,13 @@ int       data_proc(
 time_t    find_first_time(
     time_t,
     enum tmt_en,
-    long);
+    long,
+    int);
 time_t    find_next_time(
     time_t,
     enum tmt_en,
-    long);
+    long,
+    int);
 int       print_calc(
     image_desc_t *);
 int       leg_place(
index 1600a7dfef1e094385a0e180b6b7972c3525ff02..6bd433b237e017ea601a4a0bd70b70fc9c3d63b0 100644 (file)
@@ -180,6 +180,7 @@ static void PrintUsage(
            "\t\t[-t|--title string]\n"
            "\t\t[-W|--watermark string]\n"
            "\t\t[-Z|--use-nan-for-all-missing-data]\n"
+           "\t\t[--utc]\n"
            "\t\t[DEF:vname=rrd:ds-name:CF]\n");
     const char *help_graph3 =
         N_("\t\t[CDEF:vname=rpn-expression]\n"