Skip to content

Commit

Permalink
Add Timestamp renderer
Browse files Browse the repository at this point in the history
  • Loading branch information
webmaster128 committed Jul 14, 2022
1 parent fc6a954 commit 944fb9d
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 1 deletion.
21 changes: 21 additions & 0 deletions packages/proto-signing/src/testdata/timestamp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[
[0, 0, "1970-01-01T00:00:00.000000000Z"],
[0, 1, "1970-01-01T00:00:00.000000001Z"],
[0, 10, "1970-01-01T00:00:00.000000010Z"],
[0, 100, "1970-01-01T00:00:00.000000100Z"],
[0, 1000, "1970-01-01T00:00:00.000001000Z"],
[0, 10000, "1970-01-01T00:00:00.000010000Z"],
[0, 100000, "1970-01-01T00:00:00.000100000Z"],
[0, 1000000, "1970-01-01T00:00:00.001000000Z"],
[0, 10000000, "1970-01-01T00:00:00.010000000Z"],
[0, 100000000, "1970-01-01T00:00:00.100000000Z"],
[0, 999999999, "1970-01-01T00:00:00.999999999Z"],
[0, 1000000000, null],
[1, 0, "1970-01-01T00:00:01.000000000Z"],
[2, 0, "1970-01-01T00:00:02.000000000Z"],
[2, 6, "1970-01-01T00:00:02.000000006Z"],
[2, 6, "1970-01-01T00:00:02.000000006Z"],
[1657797740, 983000000, "2022-07-14T11:22:20.983000000Z"],
[-1, 0, "1969-12-31T23:59:59.000000000Z"],
[0, -1, null]
]
25 changes: 25 additions & 0 deletions packages/proto-signing/src/textual/valuerenderers.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,23 @@ import coinData from "../testdata/coin.json";
import coinsData from "../testdata/coins.json";
import decimals from "../testdata/decimals.json";
import integers from "../testdata/integers.json";
import timestampData from "../testdata/timestamp.json";
import {
DisplayUnit,
formatBytes,
formatCoin,
formatCoins,
formatDecimal,
formatInteger,
formatTimestamp,
} from "./valuerenderers";

type TestDataCoin = Array<[Coin, DisplayUnit, string]>;
type TestDataCoins = Array<[Coin[], Record<string, DisplayUnit>, string]>;
/** First argument is an array of bytes (0-255), second argument is the expected string */
type TestDataBytes = Array<[number[], string]>;
/** First argument is seconds, second argument is nanor and third argument is the expected string or null on error */
type TestDataTimestamp = Array<[number, number, string | null]>;

describe("valuerenderers", () => {
describe("formatInteger", () => {
Expand Down Expand Up @@ -90,4 +94,25 @@ describe("valuerenderers", () => {
}
});
});

describe("formatTimestamp", () => {
it("works", () => {
expect(formatTimestamp(0, 0)).toEqual("1970-01-01T00:00:00.000000000Z");
expect(formatTimestamp(0, 1)).toEqual("1970-01-01T00:00:00.000000001Z");
expect(formatTimestamp(1, 2)).toEqual("1970-01-01T00:00:01.000000002Z");
expect(formatTimestamp(5, 0)).toEqual("1970-01-01T00:00:05.000000000Z");

for (const [seconds, nanos, expected] of timestampData as TestDataTimestamp) {
if (expected === null) {
expect(() => formatTimestamp(seconds, nanos))
.withContext(`Input seconds=${seconds}, nanos=${nanos}`)
.toThrowError();
} else {
expect(formatTimestamp(seconds, nanos))
.withContext(`Input seconds=${seconds}, nanos=${nanos}`)
.toEqual(expected);
}
}
});
});
});
27 changes: 26 additions & 1 deletion packages/proto-signing/src/textual/valuerenderers.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { toBase64 } from "@cosmjs/encoding";
import { Decimal } from "@cosmjs/math";
import { Decimal, Uint32 } from "@cosmjs/math";
import { DenomUnit } from "cosmjs-types/cosmos/bank/v1beta1/bank";
import { Coin } from "cosmjs-types/cosmos/base/v1beta1/coin";

Expand Down Expand Up @@ -40,3 +40,28 @@ export function formatCoins(input: Coin[], units: Record<string, DisplayUnit>):
export function formatBytes(data: Uint8Array): string {
return toBase64(data);
}

export interface DateWithNanoseconds extends Date {
/** Nanoseconds after the time stored in a vanilla Date (millisecond granularity) */
nanoseconds?: number;
}

function toRfc3339WithNanoseconds(dateTime: DateWithNanoseconds): string {
const millisecondIso = dateTime.toISOString();
const nanoseconds = dateTime.nanoseconds?.toString() ?? "";
return `${millisecondIso.slice(0, -1)}${nanoseconds.padStart(6, "0")}Z`;
}

function fromSeconds(seconds: number, nanos = 0): DateWithNanoseconds {
const checkedNanos = new Uint32(nanos).toNumber();
if (checkedNanos > 999_999_999) {
throw new Error("Nano seconds must not exceed 999999999");
}
const out: DateWithNanoseconds = new Date(seconds * 1000 + Math.floor(checkedNanos / 1000000));
out.nanoseconds = checkedNanos % 1000000;
return out;
}

export function formatTimestamp(seconds: number, nanos: number): string {
return toRfc3339WithNanoseconds(fromSeconds(seconds, nanos));
}

0 comments on commit 944fb9d

Please sign in to comment.