Skip to content

Commit

Permalink
feat: Added new date wrapper (#1627)
Browse files Browse the repository at this point in the history
  • Loading branch information
petertonysmith94 authored Feb 26, 2024
1 parent a84b384 commit 30e21d1
Show file tree
Hide file tree
Showing 21 changed files with 435 additions and 130 deletions.
6 changes: 6 additions & 0 deletions .changeset/afraid-avocados-compare.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@fuel-ts/account": minor
"@fuel-ts/utils": minor
---

Add the DateTime class, which allows for the conversion between common date time formats.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { launchNode } from '@fuel-ts/account/test-utils';
import { Provider, fromTai64ToUnix } from 'fuels';
import { Provider, DateTime } from 'fuels';

/**
* @group node
Expand All @@ -15,7 +15,7 @@ test('produceBlocks with custom timestamp docs snippet', async () => {
}
const lastBlockNumber = latestBlock.height;
// #region Provider-produceBlocks-custom-timestamp
const lastBlockTimestamp = fromTai64ToUnix(latestBlock.time);
const lastBlockTimestamp = DateTime.fromTai64(latestBlock.time).toUnixMilliseconds();
const latestBlockNumber = await provider.produceBlocks(3, lastBlockTimestamp + 1000);
// #endregion Provider-produceBlocks-custom-timestamp
expect(latestBlockNumber.toHex()).toBe(lastBlockNumber.add(3).toHex());
Expand Down
93 changes: 93 additions & 0 deletions apps/docs-snippets/src/guide/types/date-time.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import { DateTime } from 'fuels';

/**
* @group node
*/
describe(__filename, () => {
it('should be able to be created from multiple sources', () => {
// #region create-from-multiple-sources
// #import { DateTime };

const tai64: DateTime = DateTime.fromTai64('4611686020108779339');
const unixSeconds: DateTime = DateTime.fromUnixSeconds(1681391398);
const unixMilliseconds: DateTime = DateTime.fromUnixMilliseconds(1681391398000);
// #endregion create-from-multiple-sources

expect(tai64).toBeDefined();
expect(tai64.toTai64()).toBe('4611686020108779339');
expect(unixSeconds).toBeDefined();
expect(unixSeconds.toUnixSeconds()).toBe(1681391398);
expect(unixMilliseconds).toBeDefined();
expect(unixMilliseconds.toUnixMilliseconds()).toBe(1681391398000);
});

it('should be able to create fromTai64 and convert toTai64', () => {
// #region from-tai-64-and-to-tai-64
// #import { DateTime };

const date: DateTime = DateTime.fromTai64('4611686020108779339');
// #context console.log(date.toIso); // "4611686020108779339"

const tai64: string = date.toTai64();
// #context console.log(tai64); // "4611686020108779339"
// #endregion from-tai-64-and-to-tai-64

expect(date).toBeDefined();
expect(date.toISOString()).toEqual('2023-04-13T13:09:58.000Z');
expect(tai64).toEqual('4611686020108779339');
});

it('should be able to create fromUnixMilliseconds and convert toUnixMilliseconds', () => {
// #region from-unix-milliseconds-and-to-unix-milliseconds
// #import { DateTime };

const date: DateTime = DateTime.fromUnixMilliseconds(1681391398000);

const unixMilliseconds: number = date.toUnixMilliseconds();
// #context console.log(unixMilliseconds); // 1681391398000
// #endregion from-unix-milliseconds-and-to-unix-milliseconds

expect(date).toBeDefined();
expect(unixMilliseconds).toEqual(1681391398000);
});

it('should be able to create fromUnixSeconds and convert toUnixSeconds', () => {
// #region from-unix-seconds-and-to-unix-seconds
// #import { DateTime };

const date: DateTime = DateTime.fromUnixSeconds(1681391398);

const unixSeconds: number = date.toUnixSeconds();
// #context console.log(unixSeconds); // 1681391398
// #endregion from-unix-seconds-and-to-unix-seconds

expect(date).toBeDefined();
expect(unixSeconds).toEqual(1681391398);
});

/**
* Utility methods
*/
it('should extend the Date class', () => {
// #region date-object-methods
// #import { DateTime };

const dateTime: DateTime = DateTime.fromUnixMilliseconds(1681391398000);

// Extends the Date object
const date: Date = dateTime;

// Date object methods
date.getTime(); // 1681391398000
date.toISOString(); // 2023-04-13T13:09:58.000Z
date.toDateString(); // Thu Apr 13 2023
// #endregion date-object-methods

expect(dateTime).toBeDefined();
expect(date).toBeInstanceOf(Date);
expect(date.getTime()).toEqual(1681391398000);
expect(date.toISOString()).toEqual('2023-04-13T13:09:58.000Z');
expect(date.toDateString()).toEqual('Thu Apr 13 2023');
expect(date.toISOString()).toEqual(dateTime.toISOString());
});
});
6 changes: 5 additions & 1 deletion apps/docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,10 @@ export default defineConfig({
text: 'Vectors',
link: '/guide/types/vectors',
},
{
text: 'Date Time',
link: '/guide/types/date-time',
},
],
},
{
Expand Down Expand Up @@ -323,7 +327,7 @@ export default defineConfig({
},
{
text: 'Addresses',
link: '/guide/addresses',
link: '/guide/addresses/',
collapsed: true,
items: [
{
Expand Down
2 changes: 2 additions & 0 deletions apps/docs/spell-check-custom-words.txt
Original file line number Diff line number Diff line change
Expand Up @@ -295,3 +295,5 @@ AbstractAddress
ContractFactory
ScriptTransactionRequest
CDN
DateTime
Atomique
59 changes: 59 additions & 0 deletions apps/docs/src/guide/types/date-time.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# DateTime

To allow for easier manipulation of date and time, the SDK exports the `DateTime` class which is a wrapper around the [built-in](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) `Date` class. Below we will go over the methods of instantiation, utility functions and time formats.

Internally the transactions and other time/date assets are encoded using the [`TAI64`](#tai-format) format. We return a `DateTime` class, to allow of easier conversion and formatting between the two formats.

## Instantiating a `DateTime`

We have a host of static method for **instantiation** of our `DateTime` class.

<<< @/../../docs-snippets/src/guide/types/date-time.test.ts#create-from-multiple-sources{ts:line-numbers}

### TAI64

`fromTai64` is a _static_ method, that allows the creation of `DateTime` class from a `TAI64` string.

`toTai64` is an _instance_ method, that allows the conversion of a `DateTime` class to a `TAI64` string.

<<< @/../../docs-snippets/src/guide/types/date-time.test.ts#from-tai-64-and-to-tai-64{ts:line-numbers}

### UNIX

`fromUnixMilliseconds` is a _static_ method, that allows the creation of `DateTime` class from a UNIX Milliseconds number.

`toUnixMilliseconds` is an _instance_ method, that allows the conversion of a `DateTime` class to a `UNIX` number in milliseconds.

<<< @/../../docs-snippets/src/guide/types/date-time.test.ts#from-unix-milliseconds-and-to-unix-milliseconds{ts:line-numbers}

`fromUnixSeconds` is a _static_ method, that allows the creation of `DateTime` class from a UNIX Seconds number.

`toUnixSeconds` is an _instance_ method, that allows the conversion of a `DateTime` class to a `UNIX` number in seconds.

<<< @/../../docs-snippets/src/guide/types/date-time.test.ts#from-unix-seconds-and-to-unix-seconds{ts:line-numbers}

### Date

The `DateTime` class extends the functionality of the `Date` object, so all method are available for your usages.

<<< @/../../docs-snippets/src/guide/types/date-time.test.ts#date-object-methods{ts:line-numbers}

## Formats

Here we will go over the different date/time formats that we use in the SDK. Internally the blockchain uses the `TAI64` format, but we also support the `UNIX` format for ease of use.

### UNIX Format

UNIX time is the number of seconds that have elapsed since **00:00:00 Coordinated Universal Time (UTC), Thursday, 1 January 1970**, minus leap seconds. Every day is treated as if it contains exactly 86400 seconds, so leap seconds are ignored.

### TAI Format

TAI stands for _Temps Atomique International_ and is the current international real-time standard [Source](https://cr.yp.to/libtai/tai64.html).

We use `TAI64` is a 64-bit integer representing the number of nanoseconds since the epoch.

- the TAI second beginning exactly _(2^62 - s) seconds_ before the beginning of 1970 TAI, if s is between 0 inclusive and 2^62 exclusive; or

- the TAI second beginning exactly _(2^62 + s) seconds_ after the beginning of 1970 TAI, if s is between -2^62 inclusive and 0 exclusive.

[Source](https://cr.yp.to/libtai/tai64.html)
3 changes: 2 additions & 1 deletion packages/account/codegen.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"AssetId": "string",
"ContractId": "string",
"Salt": "string",
"Nonce": "string"
"Nonce": "string",
"Tai64Timestamp": "string"
},
"useTypeImports": true,
"nonOptionalTypename": true,
Expand Down
15 changes: 7 additions & 8 deletions packages/account/src/providers/provider.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type { BytesLike } from '@fuel-ts/interfaces';
import { BN, bn } from '@fuel-ts/math';
import type { Receipt } from '@fuel-ts/transactions';
import { InputType, ReceiptType, TransactionType } from '@fuel-ts/transactions';
import { arrayify, hexlify } from '@fuel-ts/utils';
import { DateTime, arrayify, hexlify } from '@fuel-ts/utils';
import { versions } from '@fuel-ts/versions';
import * as fuelTsVersionsMod from '@fuel-ts/versions';

Expand All @@ -25,8 +25,7 @@ import type {
} from './transaction-request';
import { ScriptTransactionRequest, CreateTransactionRequest } from './transaction-request';
import { TransactionResponse } from './transaction-response';
import { fromTai64ToDate } from './transaction-summary';
import { fromTai64ToUnix, fromUnixToTai64, sleep } from './utils';
import { sleep } from './utils';
import * as gasMod from './utils/gas';

afterEach(() => {
Expand Down Expand Up @@ -293,8 +292,8 @@ describe('Provider', () => {

expect(producedBlock).toBeDefined();

const oldest = new Date(fromTai64ToDate(timeLastBlockProduced || ''));
const newest = new Date(fromTai64ToDate(producedBlock?.time || ''));
const oldest: Date = DateTime.fromTai64(timeLastBlockProduced);
const newest: Date = DateTime.fromTai64(producedBlock?.time || DateTime.TAI64_NULL);

expect(newest >= oldest).toBeTruthy();
// #endregion Provider-produce-blocks
Expand All @@ -312,9 +311,9 @@ describe('Provider', () => {
}
const { time: latestBlockTimestampBeforeProduce, height: latestBlockNumberBeforeProduce } =
block;
const latestBlockUnixTimestampBeforeProduce = fromTai64ToUnix(
const latestBlockUnixTimestampBeforeProduce = DateTime.fromTai64(
latestBlockTimestampBeforeProduce
);
).toUnixMilliseconds();

const amountOfBlocksToProduce = 3;
const blockTimeInterval = 100; // 100ms
Expand All @@ -340,7 +339,7 @@ describe('Provider', () => {
}));
const expectedBlocks = Array.from({ length: amountOfBlocksToProduce }, (_, i) => ({
height: latestBlockNumberBeforeProduce.add(i + 1).toString(10),
time: fromUnixToTai64(startTime + i * blockTimeInterval),
time: DateTime.fromUnixMilliseconds(startTime + i * blockTimeInterval).toTai64(),
}));
expect(producedBlocks).toEqual(expectedBlocks);
});
Expand Down
7 changes: 3 additions & 4 deletions packages/account/src/providers/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
InputMessageCoder,
TransactionCoder,
} from '@fuel-ts/transactions';
import { arrayify, hexlify } from '@fuel-ts/utils';
import { arrayify, hexlify, DateTime } from '@fuel-ts/utils';
import { checkFuelCoreVersionCompatibility } from '@fuel-ts/versions';
import { equalBytes } from '@noble/curves/abstract/utils';
import { Network } from 'ethers';
Expand Down Expand Up @@ -45,7 +45,6 @@ import { TransactionResponse } from './transaction-response';
import { processGqlReceipt } from './transaction-summary/receipt';
import {
calculatePriceWithFactor,
fromUnixToTai64,
getGasUsedFromReceipts,
getReceiptsWithMissingData,
} from './utils';
Expand Down Expand Up @@ -1394,13 +1393,13 @@ export default class Provider {
* Lets you produce blocks with custom timestamps and the block number of the last block produced.
*
* @param amount - The amount of blocks to produce
* @param startTime - The UNIX timestamp to set for the first produced block
* @param startTime - The UNIX timestamp (milliseconds) to set for the first produced block
* @returns A promise that resolves to the block number of the last produced block.
*/
async produceBlocks(amount: number, startTime?: number) {
const { produceBlocks: latestBlockHeight } = await this.operations.produceBlocks({
blocksToProduce: bn(amount).toString(10),
startTimestamp: startTime ? fromUnixToTai64(startTime) : undefined,
startTimestamp: startTime ? DateTime.fromUnixMilliseconds(startTime).toTai64() : undefined,
});
return bn(latestBlockHeight);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
import { type BN } from '@fuel-ts/math';
import { type Transaction } from '@fuel-ts/transactions';
import { hexlify } from '@fuel-ts/utils';
import { DateTime, hexlify } from '@fuel-ts/utils';

import type { GqlGasCosts } from '../__generated__/operations';
import type { TransactionResultReceipt } from '../transaction-response';
import { getGasUsedFromReceipts } from '../utils';

import { calculateTransactionFee } from './calculate-transaction-fee';
import { fromTai64ToDate } from './date';
import {
getOperations,
getTransactionTypeName,
Expand Down Expand Up @@ -83,10 +82,10 @@ export function assembleTransactionSummary<TTransactionType = void>(
const mintedAssets = extractMintedAssetsFromReceipts(receipts);
const burnedAssets = extractBurnedAssetsFromReceipts(receipts);

let date: Date | undefined;
let date: DateTime | undefined;

if (time) {
date = fromTai64ToDate(time);
date = DateTime.fromTai64(time);
}

const transactionSummary: TransactionSummary<TTransactionType> = {
Expand Down
43 changes: 0 additions & 43 deletions packages/account/src/providers/transaction-summary/date.test.ts

This file was deleted.

9 changes: 0 additions & 9 deletions packages/account/src/providers/transaction-summary/date.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,4 @@ export * from './operations';
export * from './get-transaction-summary';
export * from './assemble-transaction-summary';
export * from './receipt';
export * from './date';
export * from './calculate-transaction-fee';
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ type IProcessGraphqlStatusResponse = Pick<

/** @hidden */
export const processGraphqlStatus = (gqlTransactionStatus?: GraphqlTransactionStatus) => {
let time: Time;
let time: Time | undefined;
let blockId: BlockId | undefined;
let status: TransactionStatus | undefined;

Expand Down
1 change: 0 additions & 1 deletion packages/account/src/providers/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,3 @@ export * from './block-explorer';
export * from './gas';
export * from './json';
export * from './sleep';
export * from './time';
Loading

0 comments on commit 30e21d1

Please sign in to comment.