Skip to content

Commit

Permalink
feat(cli): format dates (#170)
Browse files Browse the repository at this point in the history
Custom date formatting + timezone conversion
  • Loading branch information
Leo4815162342 authored Mar 4, 2024
1 parent e5b361b commit 1b4292f
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 8 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"chalk": "3.0.0",
"cli-progress": "3.10.0",
"commander": "5.0.0",
"dayjs": "1.11.10",
"debug": "4.3.4",
"fastest-validator": "1.10.0",
"fs-extra": "10.1.0",
Expand Down
6 changes: 6 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 25 additions & 2 deletions src/cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,18 @@ import { processData } from '../processor';
import { formatBytes } from '../utils/formatBytes';
import chalk from 'chalk';
import debug from 'debug';
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import tz from 'dayjs/plugin/timezone';

import { version } from '../../package.json';
import { BatchStreamWriter } from '../stream-writer';
import { BufferObject } from '../buffer-fetcher/types';
import { formatTimeDuration } from '../utils/formatTimeDuration';

dayjs.extend(utc);
dayjs.extend(tz);

const DEBUG_NAMESPACE = 'dukascopy-node:cli';

export async function run(argv: NodeJS.Process['argv']) {
Expand Down Expand Up @@ -47,7 +53,9 @@ export async function run(argv: NodeJS.Process['argv']) {
failAfterRetryCount,
retryOnEmpty,
pauseBetweenRetriesMs,
fileName: customFileName
fileName: customFileName,
dateFormat,
timeZone
} = input;

if (isDebugActive) {
Expand Down Expand Up @@ -187,7 +195,22 @@ export async function run(argv: NodeJS.Process['argv']) {
ignoreFlats
});

await batchStreamWriter.writeBatch(processedBatch);
await batchStreamWriter.writeBatch(
processedBatch,
dateFormat
? timeStamp => {
if (dateFormat === 'iso') {
return new Date(timeStamp).toISOString();
}

if (timeZone) {
return dayjs(timeStamp).tz(timeZone).format(dateFormat);
}

return dayjs(timeStamp).utc().format(dateFormat);
}
: undefined
);
}

if (isLastBatch) {
Expand Down
12 changes: 10 additions & 2 deletions src/cli/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export interface CliConfig extends ConfigBase {
debug: boolean;
inline: boolean;
fileName: string;
dateFormat: string;
timeZone: string;
}

const now = 'now';
Expand Down Expand Up @@ -44,6 +46,8 @@ const commanderSchema = program
.option('-bp, --batch-pause <value>', 'Pause between batches in ms', Number, 1000)
.option('-ch, --cache', 'Use cache', false)
.option('-chpath, --cache-path <value>', 'Folder path for cache data', './.dukascopy-cache')
.option('-df, --date-format <value>', 'Date format', '')
.option('-tz, --time-zone <value>', 'Timezone', '')
.option('-r, --retries <value>', 'Number of retries for a failed artifact download', Number, 0)
.option('-rp, --retry-pause <value>', 'Pause between retries in milliseconds', Number, 500)
.option(
Expand Down Expand Up @@ -95,7 +99,9 @@ export function getConfigFromCliArgs(argv: NodeJS.Process['argv']) {
pauseBetweenRetriesMs: options.retryPause,
debug: options.debug,
inline: options.inline,
fileName: options.fileName
fileName: options.fileName,
dateFormat: options.dateFormat,
timeZone: options.timeZone
};

const cliSchema: InputSchema<CliConfig> = {
Expand All @@ -105,7 +111,9 @@ export function getConfigFromCliArgs(argv: NodeJS.Process['argv']) {
silent: { type: 'boolean', required: false } as RuleBoolean,
debug: { type: 'boolean', required: false } as RuleBoolean,
inline: { type: 'boolean', required: false } as RuleBoolean,
fileName: { type: 'string', required: false } as RuleString
fileName: { type: 'string', required: false } as RuleString,
dateFormat: { type: 'string', required: false } as RuleString,
timeZone: { type: 'string', required: false } as RuleString
}
};

Expand Down
16 changes: 12 additions & 4 deletions src/stream-writer/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export class BatchStreamWriter {
private initHeaders() {
const bodyHeaders =
this.timeframe === Timeframe.tick
? ['timestamp', 'askPrice', 'bidPrice', 'askVolume', 'bidVolume']
? ['timestamp', 'askPrice', 'bidPrice', 'askVolume', 'bidVolume'] // TODO: add custom header names as cli options
: ['timestamp', 'open', 'high', 'low', 'close', 'volume'];

if (!this.volumes) {
Expand All @@ -114,21 +114,25 @@ export class BatchStreamWriter {
return bodyHeaders;
}

public async writeBatch(batch: number[][]) {
const batchWithinRange: number[][] = [];
public async writeBatch(batch: number[][], dateFormatter?: (timestamp: number) => string) {
const batchWithinRange: (number | string)[][] = [];

for (let j = 0; j < batch.length; j++) {
const item = batch[j];
const isItemInRange =
item.length > 0 && item[0] >= this.startDateTs && item[0] < this.endDateTs;

if (isItemInRange) {
if (dateFormatter) {
//@ts-expect-error TODO: fix this
item[0] = dateFormatter(item[0]);
}
batchWithinRange.push(item);
}
}

for (let i = 0; i < batchWithinRange.length; i++) {
const item = batchWithinRange[i];
let item = batchWithinRange[i];

const isFirstItem = i === 0;
const isLastItem = i === batchWithinRange.length - 1;
Expand All @@ -152,6 +156,10 @@ export class BatchStreamWriter {
body += ',' + (!this.isInline ? '\n' : '');
}

if (dateFormatter && (this.format === Format.json || this.format === Format.array)) {
item[0] = `"${item[0]}"`;
}

if (this.format === Format.json) {
const jsonObjectBody = item.map((val, i) => `"${this.bodyHeaders[i]}":${val}`).join(',');
body += `{${jsonObjectBody}}`;
Expand Down

0 comments on commit 1b4292f

Please sign in to comment.