]> git.kaiwu.me - haproxy.git/commitdiff
BUG/MINOR: sample: apply the ms_/us_ time offsets in the input unit
authorWilly Tarreau <w@1wt.eu>
Wed, 30 Sep 2026 07:23:47 +0000 (09:23 +0200)
committerWilly Tarreau <w@1wt.eu>
Wed, 30 Sep 2026 14:11:24 +0000 (16:11 +0200)
The documentation of ms_ltime(), ms_utime(), us_ltime() and us_utime()
states that their optional <offset> is expressed in milliseconds or in
microseconds, that is in the same unit as their input. The four of them
however split the input into a number of seconds and a sub-second part
first, and then add the offset to the number of seconds, so the offset
was really applied in seconds and could never shift the sub-second part.

With int(1234567890123),ms_utime("%H:%M:%S.%3N",877) the result was
23:46:07.123, that is 877 seconds later, instead of the 23:31:31.000
the documentation describes.

The offset is now added to the input before it is split, which also
lets it carry the sub-second part as intended. The plain ltime() and
utime() take their offset in seconds and are unaffected.

The bug was introduced with the converters in 2.9-dev3 with commit
5e63e1636a ("MEDIUM: sample: implement us and ms variant of utime and
ltime"), so the fix must be backported as far as 3.0.

src/sample.c

index 0064252ae41975b67b4ebb7b0458857374ecd10c..54d8c88d78f406d407b07850ebf059753fc1e452 100644 (file)
@@ -2720,12 +2720,16 @@ error:
 static int sample_conv_us_ltime(const struct arg *args, struct sample *smp, void *private)
 {
        struct buffer *temp;
-       time_t curr_date = smp->data.u.sint / 1000000; /* convert us to s */
-       uint64_t ns = (smp->data.u.sint % 1000000) * 1000; /*  us part to ns */
+       long long date = smp->data.u.sint;
+       time_t curr_date;
+       uint64_t ns;
 
-       /* add offset */
+       /* add offset, which is expressed in the same unit as the input */
        if (args[1].type == ARGT_SINT)
-               curr_date += args[1].data.sint;
+               date += args[1].data.sint;
+
+       curr_date = date / 1000000; /* convert us to s */
+       ns = (date % 1000000) * 1000; /*  us part to ns */
 
        temp = conv_time_common(args[0].data.str.area, curr_date, ns, 1);
        smp->data.u.str = *temp;
@@ -2739,12 +2743,16 @@ static int sample_conv_us_ltime(const struct arg *args, struct sample *smp, void
 static int sample_conv_ms_ltime(const struct arg *args, struct sample *smp, void *private)
 {
        struct buffer *temp;
-       time_t curr_date = smp->data.u.sint / 1000; /* convert ms to s */
-       uint64_t ns = (smp->data.u.sint % 1000) * 1000000; /*  ms part to ns */
+       long long date = smp->data.u.sint;
+       time_t curr_date;
+       uint64_t ns;
 
-       /* add offset */
+       /* add offset, which is expressed in the same unit as the input */
        if (args[1].type == ARGT_SINT)
-               curr_date += args[1].data.sint;
+               date += args[1].data.sint;
+
+       curr_date = date / 1000; /* convert ms to s */
+       ns = (date % 1000) * 1000000; /*  ms part to ns */
 
        temp = conv_time_common(args[0].data.str.area, curr_date, ns, 1);
        smp->data.u.str = *temp;
@@ -2794,12 +2802,16 @@ static int sample_conv_sdbm(const struct arg *arg_p, struct sample *smp, void *p
 static int sample_conv_us_utime(const struct arg *args, struct sample *smp, void *private)
 {
        struct buffer *temp;
-       time_t curr_date = smp->data.u.sint / 1000000; /* convert us to s */
-       uint64_t ns = (smp->data.u.sint % 1000000) * 1000; /*  us part to ns */
+       long long date = smp->data.u.sint;
+       time_t curr_date;
+       uint64_t ns;
 
-       /* add offset */
+       /* add offset, which is expressed in the same unit as the input */
        if (args[1].type == ARGT_SINT)
-               curr_date += args[1].data.sint;
+               date += args[1].data.sint;
+
+       curr_date = date / 1000000; /* convert us to s */
+       ns = (date % 1000000) * 1000; /*  us part to ns */
 
        temp = conv_time_common(args[0].data.str.area, curr_date, ns, 0);
        smp->data.u.str = *temp;
@@ -2813,12 +2825,16 @@ static int sample_conv_us_utime(const struct arg *args, struct sample *smp, void
 static int sample_conv_ms_utime(const struct arg *args, struct sample *smp, void *private)
 {
        struct buffer *temp;
-       time_t curr_date = smp->data.u.sint / 1000; /* convert ms to s */
-       uint64_t ns = (smp->data.u.sint % 1000) * 1000000; /*  ms part to ns */
+       long long date = smp->data.u.sint;
+       time_t curr_date;
+       uint64_t ns;
 
-       /* add offset */
+       /* add offset, which is expressed in the same unit as the input */
        if (args[1].type == ARGT_SINT)
-               curr_date += args[1].data.sint;
+               date += args[1].data.sint;
+
+       curr_date = date / 1000; /* convert ms to s */
+       ns = (date % 1000) * 1000000; /*  ms part to ns */
 
        temp = conv_time_common(args[0].data.str.area, curr_date, ns, 0);
        smp->data.u.str = *temp;