summaryrefslogtreecommitdiffstats
path: root/src/libnetdata/parsers/duration.html
diff options
context:
space:
mode:
Diffstat (limited to 'src/libnetdata/parsers/duration.html')
-rw-r--r--src/libnetdata/parsers/duration.html205
1 files changed, 205 insertions, 0 deletions
diff --git a/src/libnetdata/parsers/duration.html b/src/libnetdata/parsers/duration.html
new file mode 100644
index 000000000..8f6f8a416
--- /dev/null
+++ b/src/libnetdata/parsers/duration.html
@@ -0,0 +1,205 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="UTF-8">
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <title>Duration Converter</title>
+ <style>
+ table {
+ width: 50%;
+ border-collapse: collapse;
+ margin-top: 20px;
+ }
+ table, th, td {
+ border: 1px solid black;
+ }
+ th, td {
+ padding: 10px;
+ text-align: center;
+ }
+ .error {
+ color: red;
+ margin-top: 10px;
+ }
+ </style>
+</head>
+<body>
+<h1>Duration Converter</h1>
+<input type="text" id="durationInput" placeholder="Enter duration (e.g., 10d-12h)">
+<div id="errorMessage" class="error"></div>
+
+<table id="resultTable">
+ <thead>
+ <tr>
+ <th>Unit</th>
+ <th>Value</th>
+ <th>Formatted</th>
+ <th>Check</th>
+ </tr>
+ </thead>
+ <tbody>
+ </tbody>
+</table>
+
+<script>
+ const NSEC_PER_USEC = 1000;
+ const USEC_PER_MS = 1000;
+ const NSEC_PER_SEC = 1000000000;
+ const NSEC_PER_MS = USEC_PER_MS * NSEC_PER_USEC;
+ const NSEC_PER_MIN = NSEC_PER_SEC * 60;
+ const NSEC_PER_HOUR = NSEC_PER_MIN * 60;
+ const NSEC_PER_DAY = NSEC_PER_HOUR * 24;
+ const NSEC_PER_WEEK = NSEC_PER_DAY * 7;
+ const NSEC_PER_YEAR = NSEC_PER_DAY * 365;
+ const NSEC_PER_MONTH = NSEC_PER_DAY * 30;
+ const NSEC_PER_QUARTER = NSEC_PER_MONTH * 3;
+
+ const units = [
+ { unit: "ns", formatter: true, multiplier: 1 },
+ { unit: "us", formatter: true, multiplier: NSEC_PER_USEC },
+ { unit: "ms", formatter: true, multiplier: NSEC_PER_MS },
+ { unit: "s", formatter: true, multiplier: NSEC_PER_SEC },
+ { unit: "m", formatter: true, multiplier: NSEC_PER_MIN },
+ { unit: "min", formatter: false, multiplier: NSEC_PER_MIN },
+ { unit: "h", formatter: true, multiplier: NSEC_PER_HOUR },
+ { unit: "d", formatter: true, multiplier: NSEC_PER_DAY },
+ { unit: "w", formatter: false, multiplier: NSEC_PER_WEEK },
+ { unit: "wk", formatter: false, multiplier: NSEC_PER_WEEK },
+ { unit: "mo", formatter: true, multiplier: NSEC_PER_MONTH },
+ { unit: "M", formatter: false, multiplier: NSEC_PER_MONTH },
+ { unit: "q", formatter: false, multiplier: NSEC_PER_QUARTER },
+ { unit: "y", formatter: true, multiplier: NSEC_PER_YEAR },
+ { unit: "Y", formatter: false, multiplier: NSEC_PER_YEAR },
+ { unit: "a", formatter: false, multiplier: NSEC_PER_YEAR }
+ ];
+
+ function durationFindUnit(unit) {
+ if (!unit) return units[0];
+ return units.find(u => u.unit === unit) || null;
+ }
+
+ function roundToResolution(value, resolution) {
+ if (value > 0) return Math.floor((value + (resolution - 1) / 2) / resolution);
+ if (value < 0) return Math.ceil((value - (resolution - 1) / 2) / resolution);
+ return 0;
+ }
+
+ function parseDouble(str) {
+ str = str.trim();
+ const match = str.match(/^[-+]?\d*\.?\d+/);
+ if (match) {
+ const number = parseFloat(match[0]);
+ const remainingStr = str.slice(match[0].length).trim();
+ return { number, remainingStr };
+ }
+ return { number: null, remainingStr: str };
+ }
+
+ function durationParse(duration, unit) {
+ if (!duration || !unit) return false;
+
+ let s = duration.trim();
+ let nsec = 0;
+ let isNegative = false;
+
+ // Handle leading negative sign
+ if (s.startsWith("-")) {
+ isNegative = true;
+ s = s.slice(1).trim();
+ }
+
+ while (s.length > 0) {
+ s = s.trim();
+
+ if (s.startsWith("never") || s.startsWith("off"))
+ return 0;
+
+ const { number, remainingStr } = parseDouble(s);
+ if (number === null) return false;
+
+ s = remainingStr;
+
+ const match = s.match(/^([a-zA-Z]*)/);
+ let currentUnit = unit;
+ if (match && match[0].length > 0) {
+ currentUnit = match[0];
+ s = s.slice(match[0].length).trim();
+ }
+
+ const du = durationFindUnit(currentUnit);
+ if (!du) return false;
+
+ nsec += number * du.multiplier;
+ }
+
+ const unitMultiplier = durationFindUnit(unit).multiplier;
+ nsec = roundToResolution(nsec, unitMultiplier);
+
+ return isNegative ? -nsec : nsec;
+ }
+
+ function durationSnprintf(value, unit) {
+ if (value === 0) return "off";
+
+ const duMin = durationFindUnit(unit);
+ let nsec = Math.abs(value) * duMin.multiplier;
+
+ const isNegative = value < 0;
+ let result = isNegative ? "-" : "";
+
+ for (let i = units.length - 1; i >= 0 && nsec !== 0; i--) {
+ const du = units[i];
+ if (!du.formatter && du !== duMin) continue;
+
+ const multiplier = du.multiplier;
+ const rounded = (du === duMin) ? roundToResolution(nsec, multiplier) * multiplier : nsec;
+ let unitCount = Math.floor(rounded / multiplier);
+
+ if (unitCount !== 0) {
+ result += `${unitCount}${du.unit}`;
+ nsec -= unitCount * multiplier;
+ }
+
+ if (du === duMin) break;
+ }
+
+ return result || "off";
+ }
+
+ function updateTable() {
+ const duration = document.getElementById("durationInput").value;
+ const tableBody = document.getElementById("resultTable").querySelector("tbody");
+ const errorMessage = document.getElementById("errorMessage");
+ tableBody.innerHTML = "";
+ errorMessage.textContent = "";
+
+ units.forEach(unit => {
+ let value = durationParse(duration, unit.unit);
+ let formatted;
+ let check;
+ if(value === false) {
+ value = "-";
+ formatted = "";
+ check = "parsing error";
+ }
+ else {
+ formatted = durationSnprintf(value, unit.unit);
+ const parsedValue = durationParse(formatted, unit.unit);
+ check = (parsedValue === value) ? "ok" : `re-parsing error (${parsedValue})`;
+ }
+
+ const row = `<tr>
+ <td>${unit.unit}</td>
+ <td>${value}</td>
+ <td>${formatted}</td>
+ <td>${check}</td>
+ </tr>`;
+ tableBody.innerHTML += row;
+ });
+ }
+
+ document.getElementById("durationInput").addEventListener("input", updateTable);
+</script>
+</body>
+</html>