From 36dce79934614ae4d19c019152b2738d7c92d07a Mon Sep 17 00:00:00 2001 From: Christopher Krah <48338417+chrikrah@users.noreply.github.com> Date: Sun, 8 Nov 2026 11:09:02 +0100 Subject: [PATCH 1/2] Test parsing a negative timestamp between -1 and 0 Signed-off-by: Christopher Krah <48338417+chrikrah@users.noreply.github.com> --- tests/openmetrics/test_parser.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/openmetrics/test_parser.py b/tests/openmetrics/test_parser.py index 684d9a82..78b7af83 100644 --- a/tests/openmetrics/test_parser.py +++ b/tests/openmetrics/test_parser.py @@ -627,6 +627,20 @@ def test_null_byte(self): metric_family = CounterMetricFamily("a", "he\0lp") self.assertEqual([metric_family], list(families)) + def test_negative_subsecond_timestamps(self): + families = text_string_to_metric_families("""# TYPE a counter +# HELP a help +a_total{foo="1"} 1 -0.500000000 +a_total{foo="2"} 1 -1.500000000 # {a="b"} 0.5 -0.250000000 +# EOF +""") + a = CounterMetricFamily("a", "help", labels=["foo"]) + a.add_metric(["1"], 1, timestamp=Timestamp(-0.5, 500000000)) + a.add_metric(["2"], 1, timestamp=Timestamp(-1, 500000000)) + a.samples[1] = a.samples[1]._replace(exemplar=Exemplar({"a": "b"}, 0.5, Timestamp(-0.25, 250000000))) + self.assertEqual([a], list(families)) + self.assertEqual("-0.500000000", str(a.samples[0].timestamp)) + def test_timestamps(self): families = text_string_to_metric_families("""# TYPE a counter # HELP a help From 3bb5be2d7adcaf401bc667207b3ccadd38ca4819 Mon Sep 17 00:00:00 2001 From: Christopher Krah <48338417+chrikrah@users.noreply.github.com> Date: Sun, 8 Nov 2026 11:09:02 +0100 Subject: [PATCH 2/2] Keep the sign of a negative timestamp between -1 and 0 in the OpenMetrics parser Signed-off-by: Christopher Krah <48338417+chrikrah@users.noreply.github.com> --- prometheus_client/openmetrics/parser.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/prometheus_client/openmetrics/parser.py b/prometheus_client/openmetrics/parser.py index adb3a388..ebd6da10 100644 --- a/prometheus_client/openmetrics/parser.py +++ b/prometheus_client/openmetrics/parser.py @@ -91,7 +91,12 @@ def _parse_timestamp(timestamp): try: # aaaa.bbbb. Nanosecond resolution supported. parts = timestamp.split('.', 1) - return Timestamp(int(parts[0]), int(parts[1][:9].ljust(9, "0"))) + sec = int(parts[0]) + nsec = int(parts[1][:9].ljust(9, "0")) + if sec == 0 and parts[0].startswith('-'): + # int("-0") is 0, so carry the sign the way Timestamp(-0.5, 500000000) does. + return Timestamp(-nsec / 1e9, nsec) + return Timestamp(sec, nsec) except ValueError: # Float. ts = float(timestamp)