Added 2 new operations 'NTPTimestampToUNIXTimestamp' and 'UNIXTimestampToNTPTimestamp' allowing to convert NTP timestamp to UNIX timestamp and the other way round

This commit is contained in:
kossithedon 2024-05-19 00:10:13 +02:00
parent 18159ce806
commit f0e00716d8
No known key found for this signature in database
GPG key ID: C482A9E4338AB371
5 changed files with 661 additions and 0 deletions

View file

@ -332,6 +332,8 @@
"To UNIX Timestamp", "To UNIX Timestamp",
"Windows Filetime to UNIX Timestamp", "Windows Filetime to UNIX Timestamp",
"UNIX Timestamp to Windows Filetime", "UNIX Timestamp to Windows Filetime",
"NTP Timestamp to Unix Timestamp",
"UNIX Timestamp to NTP Timestamp",
"DateTime Delta", "DateTime Delta",
"Extract dates", "Extract dates",
"Get Time", "Get Time",

View file

@ -0,0 +1,139 @@
/**
* @author kossithedon [kossivijunior@yahoo.fr]
* @copyright Crown Copyright 2024
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import BigNumber from "bignumber.js";
import OperationError from "../errors/OperationError.mjs";
import RemoveWhitespace from "./RemoveWhitespace.mjs";
import SwapEndianness from "./SwapEndianness.mjs";
/**
* NTP Timestamp to UNIX Timestamp operation
*/
class NTPTimestampToUNIXTimestamp extends Operation {
/**
* NTPTimestampToUNIXTimestamp constructor
*/
constructor() {
super();
this.name = "NTP Timestamp to UNIX Timestamp";
this.module = "Default";
this.description = "Convert an NTP timestamp to the corresponding UNIX timestamp.<br><br>An NTP timestamp is a 64-bit value representing time in the Network Time Protocol (NTP).<br><br>The NTP timestamp is in a fixed-point decimal format where the integer part represents the number of seconds since a fixed reference point, and the fractional part represents fractions of a second.<br><br>The reference point is the epoch of NTP, which is January 1, 1900, at 00:00:00";
this.infoURL = "https://en.wikipedia.org/wiki/Network_Time_Protocol";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Input: NTP timestamp format",
"type": "option",
"value": ["Fixed-point decimal", "Hex (big-endian)", "Hex (little-endian)"]
},
{
"name": "Output : Unix timestamp unit",
"type": "option",
"value": ["Seconds (s)", "Milliseconds (ms)", "Microseconds (μs)", "Nanoseconds (ns)"]
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [format, unit] = args;
if (!input || input.trim().length === 0) {
return "";
} else {
input = new RemoveWhitespace().run(input, [true, true, true, true, true, false]);
}
if (format.startsWith("Hex")) {
if (input.length != 16) {
return `Error: NTP Timestamp should be 64 bits long`;
}
if (format === "Hex (little-endian)") {
// Convert little-endian to big-endian
input = new SwapEndianness().run(input, ["Raw", input.length, false]);
}
// Getting the 32 bits (8 first hexa values) long seconds part
const hex_ntp_timestamp_seconds_part = input.substring(0, 8);
// Getting the 32 bits (8 last hexa values) long seconds fractions part
const hex_ntp_timestamp_fractions_part = input.substring(input.length - 8, input.length);
// Convert hexadecimal values to decimal values
var ntp_timestamp_seconds_part = new BigNumber(hex_ntp_timestamp_seconds_part, 16);
var ntp_timestamp_fractions_part = new BigNumber(hex_ntp_timestamp_fractions_part, 16);
} else if (format == "Fixed-point decimal") {
// Get the seconds and the seconds fractions parts of the timestamp separated by a "."
const pf_ntp_timestamp_seconds_and_fractions_parts = String(input).split(".");
var ntp_timestamp_seconds_part = new Number(pf_ntp_timestamp_seconds_and_fractions_parts[0]);
var ntp_timestamp_fractions_part = pf_ntp_timestamp_seconds_and_fractions_parts[1];
if (ntp_timestamp_fractions_part == null) {
ntp_timestamp_fractions_part = 0
} else {
ntp_timestamp_fractions_part = new Number(pf_ntp_timestamp_seconds_and_fractions_parts[1]);
}
} else {
throw new OperationError("Unrecognised format");
}
// Set the maximum unsigned positive integer representable in 32 bits
const max_uint32=new Number(Math.pow(2, 32))
// Check whether the seconds and the seconds fractions parts values do
// not exceeds the maximum positive integer representable in 32 bits
if (ntp_timestamp_seconds_part > max_uint32)
{
return `Error: Timestamp seconds part should be 32 bits long. The seconds part '${ntp_timestamp_seconds_part}' of the provided NTP timestamp exceeds the maximum positive integer representable in 32 bits '${max_uint32}'`;
}
if (ntp_timestamp_fractions_part > max_uint32)
{
return `Error: Timestamp fractions seconds part should be 32 bits long. The fractions seconds part '${ntp_timestamp_fractions_part}' of the provided NTP timestamp exceeds the maximum positive integer representable in 32 bits '${max_uint32}'`;
}
// Convert the NTP timestamp seconds part value (seconds elapsed since 01 january
// 1900 midnight) to UNIX timestamp (seconds elapsed since 01 january 1970 midnight)
const unix_timestamp_seconds_part = ntp_timestamp_seconds_part - new Number("2208988800");
// Convert the NTP timestamp seconds fractions part value to seconds
const unix_timestamp_fractions_part = ntp_timestamp_fractions_part / new Number(Math.pow(2, 32));
// Addition the seconds part value to the seconds fractions part value
// to form the UNIX timestamp in seconds
let unix_timestamp=unix_timestamp_seconds_part + unix_timestamp_fractions_part;
// Convert seconds Unix timestamp to requested result unit
if (unit === "Seconds (s)") {
return String(unix_timestamp);
} else if (unit === "Milliseconds (ms)") {
unix_timestamp = unix_timestamp * new Number("1000");
} else if (unit === "Microseconds (μs)") {
unix_timestamp = unix_timestamp * new Number(Math.pow(10, 6));
} else if (unit === "Nanoseconds (ns)") {
unix_timestamp = unix_timestamp * new Number(Math.pow(10, 9));
} else {
throw new OperationError("Unrecognised unit");
}
return String(unix_timestamp);
}
}
export default NTPTimestampToUNIXTimestamp;

View file

@ -0,0 +1,131 @@
/**
* @author kossithedon [kossivijunior@yahoo.fr]
* @copyright Crown Copyright 2024
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import RemoveWhitespace from "./RemoveWhitespace.mjs";
import SwapEndianness from "./SwapEndianness.mjs";
import OperationError from "../errors/OperationError.mjs";
/**
* UNIX Timestamp to NTP Timestamp operation
*/
class NTPTimestampToUNIXTimestamp extends Operation {
/**
* UNIXTimestampToNTPTimestamp constructor
*/
constructor() {
super();
this.name = "UNIX Timestamp to NTP Timestamp";
this.module = "Default";
this.description = "Convert an NTP timestamp to the corresponding UNIX timestamp.<br><br>An NTP timestamp is a 64-bit value representing time in the Network Time Protocol (NTP).<br><br>The NTP timestamp is in a fixed-point decimal format where the integer part represents the number of seconds since a fixed reference point, and the fractional part represents fractions of a second.<br><br>The reference point is the epoch of NTP, which is January 1, 1900, at 00:00:00";
this.infoURL = "https://en.wikipedia.org/wiki/Network_Time_Protocol";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Input : Unix timestamp unit",
"type": "option",
"value": ["Seconds (s)", "Milliseconds (ms)", "Microseconds (μs)", "Nanoseconds (ns)"]
},
{
"name": "Output: NTP timestamp format",
"type": "option",
"value": ["Fixed-point decimal", "Hex (big-endian)", "Hex (little-endian)"]
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [unit, format] = args;
if (!input || input.trim().length === 0) {
return "";
} else {
input = new RemoveWhitespace().run(input, [true, true, true, true, true, false]);
}
let unix_timestamp_seconds;
// Convert the provided Unix timestmap to seconds Unix timestamps
if (unit === "Seconds (s)") {
unix_timestamp_seconds = input;
} else if (unit === "Milliseconds (ms)") {
unix_timestamp_seconds = input / new Number("1000");
} else if (unit === "Microseconds (μs)") {
unix_timestamp_seconds = input / new Number(Math.pow(10, 6));
} else if (unit === "Nanoseconds (ns)") {
unix_timestamp_seconds = input / new Number(Math.pow(10, 9));
} else {
throw new OperationError("Unrecognised unit");
}
// Get the seconds and the fractions seconds parts of the UNIX timestamp
const unix_timestamp_seconds_part = Math.floor(unix_timestamp_seconds);
const unix_timestamp_fractions_part = unix_timestamp_seconds % 1;
// The greatest seconds value is the maximum unsigned positive integer representable
// in 32 bits (2**32) - 2208988800 (seconds elapsed from NTP Epoch and UNIX Epoch)
const greatest_seconds_value = Math.pow(2, 32) - 2208988800
// Check whether the seconds value part do not exceeds the greatest seconds value
if (unix_timestamp_seconds_part > greatest_seconds_value)
{
return `Error: The NTP Timestamp seconds part '${unix_timestamp_seconds_part}' exceeds the greatest authorized seconds value ${greatest_seconds_value} due to an incorrect provided UNIX timestamp`;
}
// Convert the UNIX timestamp seconds part value (seconds elapsed since 01 january
// 1970 midnight) to NTP timestamp (seconds elapsed since 01 january 1900 midnight)
var ntp_timestamp_seconds_part = unix_timestamp_seconds_part + new Number("2208988800");
// Convert the NTP timestamp seconds fractions part value to seconds
var ntp_timestamp_fractions_part = unix_timestamp_fractions_part * (Math.pow(2, 32));
if (format.startsWith("Hex")) {
// Convert Unix timestamp seconds and seconds fractions parts from decimal to hexadecimal
const hex_ntp_timestamp_seconds_part = ntp_timestamp_seconds_part.toString(16);
var hex_ntp_timestamp_fractions_part = ntp_timestamp_fractions_part.toString(16);
if (hex_ntp_timestamp_fractions_part == 0) {
// pad hexadecimal seconds fractions part
hex_ntp_timestamp_fractions_part = "00000000"
}
// Concatenate seconds part hexadecimal value to seconds fractions part
// hexadecimal value to form the big-endian hexadecimal Unix timestamp
const be_hex_ntp_timestamp = hex_ntp_timestamp_seconds_part + hex_ntp_timestamp_fractions_part;
if (format === "Hex (little-endian)") {
// Convert big-endian to little-endian
const le_hex_ntp_timestamp = new SwapEndianness().run(be_hex_ntp_timestamp, ["Raw", 16, false]);
return le_hex_ntp_timestamp;
} else if (format === "Hex (big-endian)") {
return be_hex_ntp_timestamp;
} else {
throw new OperationError("Unrecognised format");
}
} else if (format === "Fixed-point decimal") {
// Construct the NTP timestamp by concatenating the seconds part
// value to the seconds fractions part value separeted by a "."
const pf_ntp_timestamp=ntp_timestamp_seconds_part+'.'+ntp_timestamp_fractions_part;
return pf_ntp_timestamp;
} else {
throw new OperationError("Unrecognised format");
}
}
}
export default NTPTimestampToUNIXTimestamp;

View file

@ -0,0 +1,211 @@
/**
* Set NTP timestamp to UNIX timestamp tests.
*
* @author kossithedon
*
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
name: "Fixed-point decimal NTP Timestamp to Seconds UNIX Timestamp",
input: "3923215437.1842400034",
expectedOutput: "1714226637.4289672",
recipeConfig: [
{
op: "NTP Timestamp to UNIX Timestamp",
args: ["Fixed-point decimal", "Seconds (s)"],
},
],
},
{
name: "Fixed-point decimal NTP Timestamp to Milliseconds UNIX Timestamp",
input: "3923215437.1842400034",
expectedOutput: "1714226637428.9673",
recipeConfig: [
{
op: "NTP Timestamp to UNIX Timestamp",
args: ["Fixed-point decimal", "Milliseconds (ms)"],
},
],
},
{
name: "Fixed-point decimal NTP Timestamp to Microseconds UNIX Timestamp",
input: "3923215437.1842400034",
expectedOutput: "1714226637428967.2",
recipeConfig: [
{
op: "NTP Timestamp to UNIX Timestamp",
args: ["Fixed-point decimal", "Microseconds (μs)"],
},
],
},
{
name: "Fixed-point decimal NTP Timestamp to Nanoseconds UNIX Timestamp",
input: "3923215437.1842400034",
expectedOutput: "1714226637428967200",
recipeConfig: [
{
op: "NTP Timestamp to UNIX Timestamp",
args: ["Fixed-point decimal", "Nanoseconds (ns)"],
},
],
},
{
name: "Big-endian hexadecimal NTP Timestamp to Seconds UNIX Timestamp",
input: "e9d784613df8dd8b",
expectedOutput: "1714226657.2420785",
recipeConfig: [
{
op: "NTP Timestamp to UNIX Timestamp",
args: ["Hex (big-endian)", "Seconds (s)"],
},
],
},
{
name: "Big-endian hexadecimal NTP Timestamp to Milliseconds UNIX Timestamp",
input: "e9d784613df8dd8b",
expectedOutput: "1714226657242.0786",
recipeConfig: [
{
op: "NTP Timestamp to UNIX Timestamp",
args: ["Hex (big-endian)", "Milliseconds (ms)"],
},
],
},
{
name: "Big-endian hexadecimal NTP Timestamp to Microseconds UNIX Timestamp",
input: "e9d784613df8dd8b",
expectedOutput: "1714226657242078.5",
recipeConfig: [
{
op: "NTP Timestamp to UNIX Timestamp",
args: ["Hex (big-endian)", "Microseconds (μs)"],
},
],
},
{
name: "Big-endian hexadecimal NTP Timestamp to Nanoseconds UNIX Timestamp",
input: "e9d784613df8dd8b",
expectedOutput: "1714226657242078500",
recipeConfig: [
{
op: "NTP Timestamp to UNIX Timestamp",
args: ["Hex (big-endian)", "Nanoseconds (ns)"],
},
],
},
{
name: "Little-endian hexadecimal NTP Timestamp to Seconds UNIX Timestamp",
input: "b8dd8fd316487d9e",
expectedOutput: "1714226657.2420785",
recipeConfig: [
{
op: "NTP Timestamp to UNIX Timestamp",
args: ["Hex (little-endian)", "Seconds (s)"],
},
],
},
{
name: "Little-endian hexadecimal NTP Timestamp to Milliseconds UNIX Timestamp",
input: "b8dd8fd316487d9e",
expectedOutput: "1714226657242.0786",
recipeConfig: [
{
op: "NTP Timestamp to UNIX Timestamp",
args: ["Hex (little-endian)", "Milliseconds (ms)"],
},
],
},
{
name: "Little-endian hexadecimal NTP Timestamp to Microseconds UNIX Timestamp",
input: "b8dd8fd316487d9e",
expectedOutput: "1714226657242078.5",
recipeConfig: [
{
op: "NTP Timestamp to UNIX Timestamp",
args: ["Hex (little-endian)", "Microseconds (μs)"],
},
],
},
{
name: "Little-endian hexadecimal NTP Timestamp to Nanoseconds UNIX Timestamp",
input: "b8dd8fd316487d9e",
expectedOutput: "1714226657242078500",
recipeConfig: [
{
op: "NTP Timestamp to UNIX Timestamp",
args: ["Hex (little-endian)", "Nanoseconds (ns)"],
},
],
},
{
name: "Hexadecimal NTP Timestamp to UNIX Timestamp : too long hexadecimal NTP timestamp input",
input: "e9d784613df8dd8bf",
expectedOutput: "Error: NTP Timestamp should be 64 bits long",
recipeConfig: [
{
op: "NTP Timestamp to UNIX Timestamp",
args: ["Hex (big-endian)", "Seconds (s)"],
},
],
},
{
name: "Hexadecimal NTP Timestamp to UNIX Timestamp : too short hexadecimal NTP timestamp input",
input: "b8dd8fd316487d9",
expectedOutput: "Error: NTP Timestamp should be 64 bits long",
recipeConfig: [
{
op: "NTP Timestamp to UNIX Timestamp",
args: ["Hex (little-endian)", "Seconds (s)"],
},
],
},
{
name: "NTP Timestamp to UNIX Timestamp : NTP Timestamp input unrecognised format",
input: "60954b2d-7151-45c7-99cc-aca4ab664a8e",
expectedOutput: "Unrecognised format",
recipeConfig: [
{
op: "NTP Timestamp to UNIX Timestamp",
args: ["uuid", "Seconds (s)"],
},
],
},
{
name: "NTP Timestamp to UNIX Timestamp : UNIX Timestamp output unrecognised unit",
input: "3923215437.1842400034",
expectedOutput: "Unrecognised unit",
recipeConfig: [
{
op: "NTP Timestamp to UNIX Timestamp",
args: ["Fixed-point decimal", "Hours"],
},
],
},
{
name: "NTP Timestamp to UNIX Timestamp : NTP timestamp seconds part is greater than the greatest 32 bits value 4294967296",
input: "4294967297.1842400034",
expectedOutput: "Error: Timestamp seconds part should be 32 bits long. The seconds part '4294967297' of the provided NTP timestamp is greater than the greatest 32 bits value '4294967296'",
recipeConfig: [
{
op: "NTP Timestamp to UNIX Timestamp",
args: ["Fixed-point decimal", "Seconds (s)"],
},
],
},
{
name: "NTP Timestamp to UNIX Timestamp : NTP timestamp seconds fractions part is greater than the greatest 32 bits value 4294967296",
input: "3923215437.4294967297",
expectedOutput: "Error: Timestamp fractions seconds part should be 32 bits long. The fractions seconds part '4294967297' of the provided NTP timestamp is greater than the greatest 32 bits value '4294967296'",
recipeConfig: [
{
op: "NTP Timestamp to UNIX Timestamp",
args: ["Fixed-point decimal", "Seconds (s)"],
},
],
}
]);

View file

@ -0,0 +1,178 @@
/**
* Set UNIX Timestamp to NTP Timestamp tests.
*
* @author kossithedon
*
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
name: "Seconds UNIX Timestamp to Fixed-point decimal NTP Timestamp",
input: "1714226657.2420785",
expectedOutput: "3923215457.1039719424",
recipeConfig: [
{
op: "UNIX Timestamp to NTP Timestamp",
args: ["Seconds (s)", "Fixed-point decimal"],
},
],
},
{
name: "Milliseconds UNIX Timestamp to Fixed-point decimal NTP Timestamp ",
input: "1714226657242.0786",
expectedOutput: "3923215457.1039719424",
recipeConfig: [
{
op: "UNIX Timestamp to NTP Timestamp",
args: ["Milliseconds (ms)", "Fixed-point decimal"],
},
],
},
{
name: "Microseconds UNIX Timestamp to Fixed-point decimal NTP Timestamp ",
input: "1714226657242078.5",
expectedOutput: "3923215457.1039719424",
recipeConfig: [
{
op: "UNIX Timestamp to NTP Timestamp",
args: ["Microseconds (μs)", "Fixed-point decimal"],
},
],
},
{
name: "Nanoseconds UNIX Timestamp to Fixed-point decimal NTP Timestamp",
input: "1714226657242078500",
expectedOutput: "3923215457.1039719424",
recipeConfig: [
{
op: "UNIX Timestamp to NTP Timestamp",
args: ["Nanoseconds (ns)", "Fixed-point decimal"],
},
],
},
{
name: "Seconds UNIX Timestamp to Big-endian hexadecimal NTP Timestamp",
input: "1714226657.2420785",
expectedOutput: "e9d784613df8dc00",
recipeConfig: [
{
op: "UNIX Timestamp to NTP Timestamp",
args: ["Seconds (s)", "Hex (big-endian)"],
},
],
},
{
name: "Milliseconds UNIX Timestamp to Big-endian hexadecimal NTP Timestamp",
input: "1714226657242.0786",
expectedOutput: "e9d784613df8dc00",
recipeConfig: [
{
op: "UNIX Timestamp to NTP Timestamp",
args: ["Milliseconds (ms)", "Hex (big-endian)"],
},
],
},
{
name: "Microseconds UNIX Timestamp to Big-endian hexadecimal NTP Timestamp",
input: "1714226657242078.5",
expectedOutput: "e9d784613df8dc00",
recipeConfig: [
{
op: "UNIX Timestamp to NTP Timestamp",
args: ["Microseconds (μs)", "Hex (big-endian)"],
},
],
},
{
name: "Nanoseconds UNIX Timestamp to Big-endian hexadecimal NTP Timestamp",
input: "1714226657242078500",
expectedOutput: "e9d784613df8dc00",
recipeConfig: [
{
op: "UNIX Timestamp to NTP Timestamp",
args: ["Nanoseconds (ns)", "Hex (big-endian)"],
},
],
},
{
name: "Seconds UNIX Timestamp to Little-endian hexadecimal NTP Timestamp",
input: "1714226657.2420785",
expectedOutput: "00cd8fd316487d9e",
recipeConfig: [
{
op: "UNIX Timestamp to NTP Timestamp",
args: ["Seconds (s)", "Hex (little-endian)"],
},
],
},
{
name: "Milliseconds UNIX Timestamp to Little-endian hexadecimal NTP Timestamp",
input: "1714226657242.0786",
expectedOutput: "00cd8fd316487d9e",
recipeConfig: [
{
op: "UNIX Timestamp to NTP Timestamp",
args: ["Milliseconds (ms)", "Hex (little-endian)"],
},
],
},
{
name: "Microseconds UNIX Timestamp to Little-endian hexadecimal NTP Timestamp",
input: "1714226657242078.5",
expectedOutput: "00cd8fd316487d9e",
recipeConfig: [
{
op: "UNIX Timestamp to NTP Timestamp",
args: ["Microseconds (μs)", "Hex (little-endian)"],
},
],
},
{
name: "Nanoseconds UNIX Timestamp to Little-endian hexadecimal NTP Timestamp",
input: "1714226657242078500",
expectedOutput: "00cd8fd316487d9e",
recipeConfig: [
{
op: "UNIX Timestamp to NTP Timestamp",
args: ["Nanoseconds (ns)", "Hex (little-endian)"],
},
],
},
{
name: "UNIX Timestamp to NTP Timestamp : UNIX Timestamp input unrecognised format",
input: "60954b2d-7151-45c7-99cc-aca4ab664a8e",
expectedOutput: "Unrecognised unit",
recipeConfig: [
{
op: "UNIX Timestamp to NTP Timestamp",
args: ["uuid", "Fixed-point decimal"],
},
],
},
{
name: "UNIX Timestamp to NTP Timestamp : UNIX Timestamp output unrecognised format",
input: "1714226657.2420785",
expectedOutput: "Unrecognised format",
recipeConfig: [
{
op: "UNIX Timestamp to NTP Timestamp",
args: ["Seconds (s)", "Floating-point", ],
},
],
},
{
name: "UNIX Timestamp to NTP Timestamp : NTP timestamp seconds part is greater than the greatest authorized value 2085978496",
input: "2085978497",
expectedOutput: "Error: The UNIX Timestamp seconds part '2085978497' exceeds the greatest authorized seconds value '2085978496' due to an incorrect provided UNIX timestamp",
recipeConfig: [
{
op: "UNIX Timestamp to NTP Timestamp",
args: ["Seconds (s)", "Fixed-point decimal"],
},
],
}
]);