From: Willy Tarreau Date: Wed, 30 Sep 2026 07:23:47 +0000 (+0200) Subject: BUG/MINOR: sample: apply the ms_/us_ time offsets in the input unit X-Git-Tag: v3.5-dev8~86 X-Git-Url: https://git.kaiwu.me/?a=commitdiff_plain;h=31703b81bb12cf1c80362a46a0d89af07afff327;p=haproxy.git BUG/MINOR: sample: apply the ms_/us_ time offsets in the input unit The documentation of ms_ltime(), ms_utime(), us_ltime() and us_utime() states that their optional 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. --- diff --git a/src/sample.c b/src/sample.c index 0064252ae..54d8c88d7 100644 --- a/src/sample.c +++ b/src/sample.c @@ -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;