diff --git a/package.json b/package.json index a80ef50a..36de3802 100644 --- a/package.json +++ b/package.json @@ -16,9 +16,10 @@ "bootstrap-vue": "^2.21.2", "bootswatch": "^4.6.0", "core-js": "^3.11.0", + "date-fns": "^2.21.3", + "date-fns-tz": "^1.1.4", "echarts": "^4.9.0", "humanize-duration": "^3.25.2", - "moment": "^2.29.1", "vue": "^2.6.12", "vue-class-component": "^7.2.5", "vue-echarts": "^5.0.0-beta.0", diff --git a/src/components/ftbot/TradeList.vue b/src/components/ftbot/TradeList.vue index 4df8fd64..a5b19c71 100644 --- a/src/components/ftbot/TradeList.vue +++ b/src/components/ftbot/TradeList.vue @@ -53,7 +53,7 @@ import { Component, Vue, Prop, Watch } from 'vue-property-decorator'; import { namespace } from 'vuex-class'; // eslint-disable-next-line @typescript-eslint/no-unused-vars -import { formatPercent, formatPrice } from '@/shared/formatters'; +import { formatPercent, formatPrice, timestampms } from '@/shared/formatters'; import { Trade } from '@/types'; import DeleteIcon from 'vue-material-design-icons/Delete.vue'; import ForceSellIcon from 'vue-material-design-icons/CloseBoxMultiple.vue'; @@ -115,7 +115,7 @@ export default class TradeList extends Vue { // Added to table-fields for historic trades closedFields: Record[] = [ - { key: 'close_date', label: 'Close date' }, + { key: 'close_timestamp', label: 'Close date', formatter: timestampms }, { key: 'sell_reason', label: 'Close Reason' }, ]; @@ -135,7 +135,7 @@ export default class TradeList extends Vue { label: this.activeTrades ? 'Current profit %' : 'Profit %', formatter: (value) => formatPercent(value, 3), }, - { key: 'open_date', label: 'Open date' }, + { key: 'open_timestamp', label: 'Open date', formatter: (value) => timestampms(value) }, ...(this.activeTrades ? this.openFields : this.closedFields), ]; diff --git a/src/shared/formatters.ts b/src/shared/formatters.ts index dd9574b9..b6d97bc7 100644 --- a/src/shared/formatters.ts +++ b/src/shared/formatters.ts @@ -1,4 +1,5 @@ -import * as moment from 'moment'; +import { parse, toDate, getHours } from 'date-fns'; +import { format, utcToZonedTime } from 'date-fns-tz'; import humanizeDuration from 'humanize-duration'; export function formatPercent(value: number, decimals = 3): string { @@ -10,7 +11,31 @@ export function formatPrice(value: number, decimals = 8): string { } export function dateFromString(datestring: string, format: string): Date { - return moment(datestring, format).toDate(); + return parse(datestring, format, 0); +} + +let timezone = 'UTC'; + +/** + * Set global timezone to use by conversion functions + * @param tz Timezone to set + */ +export function setTimezone(tz: string) { + timezone = tz; +} + +/** + * + * @param ts Convert timestamp or Date to datetime (in correct timezone) + * @returns Date object (in timezone) + */ +function converToTzDate(ts: number | Date): Date { + const date = toDate(ts); + const currentTz = Intl.DateTimeFormat().resolvedOptions().timeZone; + if (timezone === 'UTC') { + return utcToZonedTime(date, currentTz); + } + return date; } /** @@ -18,27 +43,27 @@ export function dateFromString(datestring: string, format: string): Date { * @param ts Timestamp as number or date (in utc!!) */ export function timestampms(ts: number | Date): string { - return moment.utc(ts).format('YYYY-MM-DD HH:mm:ss'); + return format(converToTzDate(ts), 'yyyy-MM-dd HH:mm:ss'); } /** - * Converts timestamp or Date object to YYYY-MM-DD format. + * Converts timestamp or Date object to yyyy-MM-dd format. * @param ts */ export function timestampToDateString(ts: number | Date): string { - return moment(ts).format('YYYY-MM-DD'); + return format(converToTzDate(ts), 'yyyy-MM-dd'); } /** - * Converts a String of the format YYYY-MM-DD to YYYYMMDD. To be used as timerange. - * @param datestring Input string (in the format YYYY-MM-DD) + * Converts a String of the format yyyy-MM-dd to YYYYMMDD. To be used as timerange. + * @param datestring Input string (in the format yyyy-MM-dd) */ export function dateStringToTimeRange(datestring: string): string { return datestring.replace(/-/g, ''); } -export function timestampHour(ts: number | Date): number { - return moment.utc(ts).hour(); +export function timestampHour(ts: number): number { + return getHours(converToTzDate(ts)); } /** @@ -55,4 +80,5 @@ export default { timestampms, timestampToDateString, dateStringToTimeRange, + setTimezone, }; diff --git a/yarn.lock b/yarn.lock index 58ff5c7a..5473ddf8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3971,6 +3971,16 @@ data-urls@^1.0.0, data-urls@^1.1.0: whatwg-mimetype "^2.2.0" whatwg-url "^7.0.0" +date-fns-tz@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/date-fns-tz/-/date-fns-tz-1.1.4.tgz#38282c2bfab08946a4e9bb89d733451e5525048b" + integrity sha512-lQ+FF7xUxxRuRqIY7H/lagnT3PhhSnnvtGHzjE5WZKwRyLU7glJfLys05SZ7zHlEr6RXWiqkmgWq4nCkcElR+g== + +date-fns@^2.21.3: + version "2.21.3" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.21.3.tgz#8f5f6889d7a96bbcc1f0ea50239b397a83357f9b" + integrity sha512-HeYdzCaFflc1i4tGbj7JKMjM4cKGYoyxwcIIkHzNgCkX8xXDNJDZXgDDVchIWpN4eQc3lH37WarduXFZJOtxfw== + de-indent@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d" @@ -7560,11 +7570,6 @@ mkdirp@^1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -moment@^2.29.1: - version "2.29.1" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3" - integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ== - move-concurrently@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"