diff --git a/example/custom-bar-chart/custom-chart.ts b/example/custom-bar-chart/custom-chart.ts index 2d76f45..bb04338 100644 --- a/example/custom-bar-chart/custom-chart.ts +++ b/example/custom-bar-chart/custom-chart.ts @@ -20,6 +20,7 @@ import { dateFormatter, getCfForColumn, getChartContext, + getCustomCalendarGuidFromColumn, isDateColumn, isDateNumColumn, PointVal, @@ -29,6 +30,10 @@ import { VisualProps, } from '@thoughtspot/ts-chart-sdk'; import { ChartConfigEditorDefinition } from '@thoughtspot/ts-chart-sdk/src'; +import { + generateMapOptions, + getDataFormatter, +} from '@thoughtspot/ts-chart-sdk/src/utils/formatting-util'; import Chart from 'chart.js/auto'; import ChartDataLabels from 'chartjs-plugin-datalabels'; import _ from 'lodash'; @@ -47,6 +52,9 @@ Chart.register(ChartDataLabels); let globalChartReference: Chart; +let locale; +let quarterStartMonth; + const exampleClientState = { id: 'chart-id', name: 'custom-bar-chart', @@ -54,14 +62,26 @@ const exampleClientState = { }; function getDataForColumn(column: ChartColumn, dataArr: DataPointsArray) { + const formatter = getDataFormatter(column, { isMillisIncluded: false }); const idx = _.findIndex(dataArr.columns, (colId) => column.id === colId); - return _.map(dataArr.dataValue, (row) => { + const dataForCol = _.map(dataArr.dataValue, (row) => { const colValue = row[idx]; - if (isDateColumn(column) || isDateNumColumn(column)) { - return dateFormatter(colValue, column); - } return colValue; }); + const options = generateMapOptions( + locale, + quarterStartMonth, + column, + dataForCol, + ); + const formattedValuesForData = _.map(dataArr.dataValue, (row) => { + const colValue = row[idx]; + if (getCustomCalendarGuidFromColumn(column)) + return formatter(colValue.v.s, options); + return formatter(colValue, options); + }); + + return formattedValuesForData; } function getColumnDataModel( @@ -190,6 +210,8 @@ function insertCustomFont(customFontFaces) { function render(ctx: CustomChartContext) { const chartModel = ctx.getChartModel(); const appConfig = ctx.getAppConfig(); + locale = appConfig?.localeOptions?.locale; + quarterStartMonth = appConfig?.localeOptions?.quarterStartMonth; ctx.emitEvent(ChartToTSEvent.UpdateVisualProps, { visualProps: JSON.parse( diff --git a/src/utils/date-formatting.ts b/src/utils/date-formatting.ts index 76c8087..1fcf005 100644 --- a/src/utils/date-formatting.ts +++ b/src/utils/date-formatting.ts @@ -14,6 +14,7 @@ import { ColumnType, DataType, } from '../types/answer-column.types'; +import { dateFormats } from './translations/date-formatter'; export interface CustomCalendarDate { v: { @@ -23,12 +24,142 @@ export interface CustomCalendarDate { d: string; } +export const dateFormatPresets = { + DATE_SHORT: 'DATE_SHORT', + DATE_SHORT_WITH_HOUR: 'DATE_SHORT_WITH_HOUR', + DATE_SHORT_WITH_HOUR_WITHOUT_YEAR: 'DATE_SHORT_WITH_HOUR_WITHOUT_YEAR', + DATETIME_SHORT: 'DATETIME_SHORT', + DATETIME_SHORT_WITHOUT_YEAR: 'DATETIME_SHORT_WITHOUT_YEAR', + DATETIME_SHORT_WITH_SECONDS: 'DATETIME_SHORT_WITH_SECONDS', + DATETIME_SHORT_WITH_MILLIS: 'DATETIME_SHORT_WITH_MILLIS', + MONTH_WITH_YEAR: 'MONTH_WITH_YEAR', + QUARTER_WITH_YEAR: 'QUARTER_WITH_YEAR', + QUARTER_WITH_2_DIGIT_YEAR: 'QUARTER_WITH_2_DIGIT_YEAR', + DEFAULT_TIME_FORMAT: 'DEFAULT_TIME_FORMAT', + TIME_24_WITH_SECONDS: 'TIME_24_WITH_SECONDS', + DATE_SHORT_2_DIGIT_YEAR: 'DATE_SHORT_2_DIGIT_YEAR', + DATETIME_24_SHORT_WITHOUT_YEAR: 'DATETIME_24_SHORT_WITHOUT_YEAR', + DATETIME_24_SHORT: 'DATETIME_24_SHORT', + DATETIME_SHORT_WITH_SECONDS_WITHOUT_YEAR: + 'DATETIME_SHORT_WITH_SECONDS_WITHOUT_YEAR', + DATETIME_SHORT_WITH_MILLIS_WITHOUT_YEAR: + 'DATETIME_SHORT_WITH_MILLIS_WITHOUT_YEAR', + DATETIME_24_SHORT_WITH_MILLIS_WITHOUT_YEAR: + 'DATETIME_24_SHORT_WITH_MILLIS_WITHOUT_YEAR', + DATETIME_24_SHORT_WITH_MILLIS: 'DATETIME_24_SHORT_WITH_MILLIS', + MONTH_WITH_DAY_AND_YEAR: 'MONTH_WITH_DAY_AND_YEAR', + MONTH_WITH_2_DIGIT_YEAR: 'MONTH_WITH_2_DIGIT_YEAR', + DAY_WITH_MONTH_NUM: 'DAY_WITH_MONTH_NUM', + DATE_SHORT_WITH_HOUR_24_WITHOUT_YEAR: + 'DATE_SHORT_WITH_HOUR_24_WITHOUT_YEAR', + DATE_SHORT_WITH_HOUR_24: 'DATE_SHORT_WITH_HOUR_24', + QUARTER: 'QUARTER', + MONTH_ONLY: 'MONTH_ONLY', + DATETIME_WITH_SHORT_OFFSET: 'DATETIME_WITH_SHORT_OFFSET', +}; +const yearlessFormats = { + DATE_SHORT: 'DAY_WITH_MONTH', + DATE_SHORT_WITH_HOUR: 'DATE_SHORT_WITH_HOUR_WITHOUT_YEAR', + DATETIME_SHORT: 'DATETIME_SHORT_WITHOUT_YEAR', + DATETIME_SHORT_WITH_SECONDS: 'DATETIME_SHORT_WITH_SECONDS_WITHOUT_YEAR', + DATETIME_SHORT_WITH_MILLIS: 'DATETIME_SHORT_WITH_MILLIS_WITHOUT_YEAR', + MONTH_WITH_YEAR: 'MONTH_ONLY', + QUARTER_WITH_YEAR: 'QUARTER', + QUARTER_WITH_2_DIGIT_YEAR: 'QUARTER', + DATE_SHORT_2_DIGIT_YEAR: 'DAY_WITH_MONTH', + DATETIME_24_SHORT: 'DATETIME_24_SHORT_WITHOUT_YEAR', + DATETIME_24_SHORT_WITH_MILLIS: 'DATETIME_24_SHORT_WITH_MILLIS_WITHOUT_YEAR', + MONTH_WITH_DAY_AND_YEAR: 'DAY_WITH_MONTH', + MONTH_WITH_2_DIGIT_YEAR: 'DAY_WITH_MONTH', + DATE_SHORT_WITH_HOUR_24: 'DATE_SHORT_WITH_HOUR_24_WITHOUT_YEAR', +}; + +const dateNumTypes = { + DATE_NUM_ABS_DAY: 'DATE_NUM_ABS_DAY', + DATE_NUM_ABS_MONTH: 'DATE_NUM_ABS_MONTH', + DATE_NUM_ABS_QUARTER: 'DATE_NUM_ABS_QUARTER', + DATE_NUM_ABS_YEAR: 'DATE_NUM_ABS_YEAR', + DATE_NUM_DAY_IN_MONTH: 'DATE_NUM_DAY_IN_MONTH', + DATE_NUM_DAY_IN_QUARTER: 'DATE_NUM_DAY_IN_QUARTER', + DATE_NUM_DAY_IN_YEAR: 'DATE_NUM_DAY_IN_YEAR', + DATE_NUM_DAY_OF_WEEK: 'DATE_NUM_DAY_OF_WEEK', + DATE_NUM_MONTH_IN_QUARTER: 'DATE_NUM_MONTH_IN_QUARTER', + DATE_NUM_MONTH_IN_YEAR: 'DATE_NUM_MONTH_IN_YEAR', + DATE_NUM_QUARTER_IN_YEAR: 'DATE_NUM_QUARTER_IN_YEAR', + DATE_NUM_WEEK_IN_YEAR: 'DATE_NUM_WEEK_IN_YEAR', + DATE_NUM_WEEK_IN_QUARTER: 'DATE_NUM_WEEK_IN_QUARTER', + DATE_NUM_WEEK_IN_MONTH: 'DATE_NUM_WEEK_IN_MONTH', + DATE_NUM_HOUR_IN_DAY: 'DATE_NUM_HOUR_IN_DAY', +}; + +const weekdays = [ + 'Sunday', + 'Monday', + 'Tuesday', + 'Wednesday', + 'Thursday', + 'Friday', + 'Saturday', +]; + +const months = [ + 'January', + 'February', + 'March', + 'April', + 'May', + 'June', + 'July', + 'August', + 'September', + 'October', + 'November', + 'December', +]; + +export const bucketizationToDatePreset = { + HOURLY: dateFormatPresets.DATE_SHORT_WITH_HOUR, // hourly + DAILY: dateFormatPresets.DATE_SHORT, // daily + WEEKLY: dateFormatPresets.DATE_SHORT, // weekly + MONTHLY: dateFormatPresets.MONTH_WITH_YEAR, + QUARTERLY: dateFormatPresets.QUARTER_WITH_YEAR, // quarterly + YEARLY: 'yyyy', // yearly +}; +const dateFormatPresetsToLuxonPresets = { + [dateFormatPresets.TIME_24_WITH_SECONDS]: DateTime.TIME_24_WITH_SECONDS, +}; + +export const timeBuckets = { + NO_BUCKET: 'ms', + HOURLY: 'h', + DAILY: 'd', + WEEKLY: 'w', + MONTHLY: 'M', + QUARTERLY: 'Q', + YEARLY: 'y', + DAY_OF_WEEK: 'dow', + DAY_OF_MONTH: 'dom', + DAY_OF_QUARTER: 'doq', + DAY_OF_YEAR: 'doy', + WEEK_OF_MONTH: 'wom', + WEEK_OF_QUARTER: 'woq', + WEEK_OF_YEAR: 'woy', + MONTH_OF_QUARTER: 'moq', + MONTH_OF_YEAR: 'moy', + QUARTER_OF_YEAR: 'qoy', +}; + +const DEFAULT_QUARTER_START_MONTH = 1; + export const isDateColumn = (col: ChartColumn) => DataType[col.dataType] === 'DATE' || DataType[col.dataType] === 'DATE_TIME'; export const isAttribute = (col: ChartColumn) => col.type === ColumnType.ATTRIBUTE; +export const isDateTimeColumn = (col: ChartColumn) => + DataType[col.dataType] === 'DATE_TIME'; + export const getCustomCalendarGuidFromColumn = (col: ChartColumn) => col.calenderGuid; @@ -59,6 +190,33 @@ export const isTimeColumn = (col: ChartColumn) => { return DataType[col.dataType] === 'TIME'; }; +export const getEffectiveDateNumDataType = (col: ChartColumn) => { + switch (col.timeBucket) { + case ColumnTimeBucket.DAY_OF_WEEK: + return dateNumTypes.DATE_NUM_DAY_OF_WEEK; + case ColumnTimeBucket.DAY_OF_MONTH: + return dateNumTypes.DATE_NUM_DAY_IN_MONTH; + case ColumnTimeBucket.DAY_OF_QUARTER: + return dateNumTypes.DATE_NUM_DAY_IN_QUARTER; + case ColumnTimeBucket.DAY_OF_YEAR: + return dateNumTypes.DATE_NUM_DAY_IN_YEAR; + case ColumnTimeBucket.WEEK_OF_MONTH: + return dateNumTypes.DATE_NUM_WEEK_IN_MONTH; + case ColumnTimeBucket.WEEK_OF_QUARTER: + return dateNumTypes.DATE_NUM_WEEK_IN_QUARTER; + case ColumnTimeBucket.WEEK_OF_YEAR: + return dateNumTypes.DATE_NUM_WEEK_IN_YEAR; + case ColumnTimeBucket.MONTH_OF_QUARTER: + return dateNumTypes.DATE_NUM_MONTH_IN_QUARTER; + case ColumnTimeBucket.MONTH_OF_YEAR: + return dateNumTypes.DATE_NUM_MONTH_IN_YEAR; + case ColumnTimeBucket.QUARTER_OF_YEAR: + return dateNumTypes.DATE_NUM_QUARTER_IN_YEAR; + default: + return undefined; + } +}; + /** * Determines if the given column has a custom calendar. * @@ -81,6 +239,13 @@ export function getStartEpoch(date: CustomCalendarDate): number | null { return null; } +function getMonthOfYear(num: any, options: any) { + let monthNum = num + options.quarterStartMonth - 1; + monthNum = monthNum > 12 ? monthNum - 12 : monthNum; + + return months[monthNum - 1]; // -1 as monthNum is 1 indexed +} + export function getDisplayString(date: CustomCalendarDate): string | null { if (_.has(date, 'd')) { return date.d; @@ -88,6 +253,257 @@ export function getDisplayString(date: CustomCalendarDate): string | null { return null; } +const useQuarterStart = (luxonDate: any, quarterStartMonth: any) => { + const newLuxonDate = luxonDate; + newLuxonDate.quarterStartMonth = quarterStartMonth; + return newLuxonDate; +}; + +export const getCustomCalendarValueFromEpoch = ( + col: ChartColumn, + dateEpoch: number, + displayToCustomCalendarValueMap: any, +) => { + if ( + hasCustomCalendar(col) && + _.has(displayToCustomCalendarValueMap, dateEpoch) + ) { + return displayToCustomCalendarValueMap[dateEpoch]; + } + return null; +}; +const parseDate = (dateString: string, format: string) => { + return DateTime.fromFormat( + dateString, + dateFormats[format] || format, + ).toJSDate(); +}; + +function sanitizeDate(inputDate: string | number, format: string) { + if (typeof inputDate === 'string') { + if (!_.isNaN(Number(inputDate))) { + return parseInt(inputDate, 10); + } + return parseDate(inputDate, format); + } + return inputDate; +} + +/** + * Get the formatted date based on the format tokens + * @param {number} epochMillis + * @param {string} format: use dateFormatPresets to get localized formatted date + * or pass the format pattern for non localized results + * @returns {string} + */ +const formatDateTime = ( + epochMillis: number, + format: string, + useSystemCalendar?: boolean, + options?: any, +) => { + let newFormat = format; + let luxonDate; + try { + luxonDate = DateTime.fromMillis(epochMillis * 1000); + } catch (e) { + return 'Invalid Date'; + } + if (dateFormats[newFormat]) { + if (_.get(options, 'omitYear')) { + if (yearlessFormats[newFormat as keyof typeof yearlessFormats]) { + newFormat = + yearlessFormats[newFormat as keyof typeof yearlessFormats]; + } + } + newFormat = dateFormats[newFormat]; + } + const customCalendarOverridesFiscalOffset = _.get( + options, + 'customCalendarOverridesFiscalOffset', + ); + // if format preset is a luxon preset + if (!newFormat || dateFormatPresetsToLuxonPresets[newFormat]) { + // Note: this will not add FY to the year in case of custom + // quarterStartMonth but the year would be the correct fiscal year + return luxonDate.toLocaleString( + dateFormatPresetsToLuxonPresets[newFormat], + ); + } + // qqq is not supported in luxon + newFormat = newFormat.replace(/qqq/, "'Q'q"); + // support YYYY and YY + newFormat = newFormat.replace(/(YYYY|YY)/, _.lowerCase); + const quarterStartMonth = options.quarterStartMonth; + if ( + quarterStartMonth > 1 && + !useSystemCalendar && + !customCalendarOverridesFiscalOffset + ) { + newFormat = newFormat.replace(/[yyyy||yy]/, "'FY' $&"); + } + return useQuarterStart( + luxonDate, + useSystemCalendar ? DEFAULT_QUARTER_START_MONTH : quarterStartMonth, + ).toFormat(newFormat); +}; + +function getSpecialFormatData(value: any) { + if (value === '{Empty}' || value === '{Null}') { + return value; + } + if (value === null || value === undefined) { + return '{Null}'; + } + if (value === '') { + return '{Empty}'; + } + return null; +} + +function getDayOfWeek(num: any) { + const new_num = num % 7; + return weekdays[new_num]; +} + +function getOrdinalSuffixedValue(i: number | string): string { + let ni = i; + // eslint-disable-next-line radix + ni = parseInt(ni.toString()); + const j = ni % 10; + const k = ni % 100; + // eslint-disable-next-line eqeqeq + if (j == 1 && k != 11) { + return `${ni}st`; + } + // eslint-disable-next-line eqeqeq + if (j == 2 && k != 12) { + return `${ni}nd`; + } + // eslint-disable-next-line eqeqeq + if (j == 3 && k != 13) { + return `${ni}rd`; + } + return `${ni}th`; +} + +export function formatDateNum( + effectiveDataType: string | undefined, + value: number | string, + formatPattern: string, + options: any, +) { + let newValue = value; + if (_.isString(newValue)) { + // eslint-disable-next-line radix + newValue = parseInt(value.toString()); + } + + if (!value && value !== 0) { + return '{Null}'; + } + const specialVal = getSpecialFormatData(value); + if (specialVal) { + return specialVal; + } + switch (effectiveDataType) { + case dateNumTypes.DATE_NUM_ABS_DAY: + case dateNumTypes.DATE_NUM_ABS_MONTH: + case dateNumTypes.DATE_NUM_ABS_QUARTER: + case dateNumTypes.DATE_NUM_ABS_YEAR: + return `${value}`; + case dateNumTypes.DATE_NUM_DAY_IN_MONTH: + return formatPattern === 'e' + ? `${value}` + : `${getOrdinalSuffixedValue(value)} day of month`; + case dateNumTypes.DATE_NUM_DAY_IN_QUARTER: + return formatPattern === 'm' + ? `${value}` + : `${getOrdinalSuffixedValue(value)} day of quarter`; + case dateNumTypes.DATE_NUM_DAY_IN_YEAR: + return formatPattern === 'j' + ? `${value}` + : `${getOrdinalSuffixedValue(value)} day of year`; + case dateNumTypes.DATE_NUM_DAY_OF_WEEK: + return formatPattern === 'e' + ? // eslint-disable-next-line @typescript-eslint/no-use-before-define + getDayOfWeek(value) + : `${value}`; + case dateNumTypes.DATE_NUM_MONTH_IN_QUARTER: + return formatPattern === 'm' + ? `${value}` + : `${getOrdinalSuffixedValue(value)} month of quarter`; + case dateNumTypes.DATE_NUM_MONTH_IN_YEAR: + return formatPattern === 'm' + ? // eslint-disable-next-line @typescript-eslint/no-use-before-define + getMonthOfYear(value, options) + : `${value}`; + case dateNumTypes.DATE_NUM_WEEK_IN_YEAR: + // +1 to value as Falcon values start with 0. + return formatPattern === 'V' + ? `${value}` + : `${getOrdinalSuffixedValue(value)} week of year`; + case dateNumTypes.DATE_NUM_WEEK_IN_QUARTER: + case dateNumTypes.DATE_NUM_WEEK_IN_MONTH: + return `${value}`; + case dateNumTypes.DATE_NUM_HOUR_IN_DAY: + return `${value}`; + default: + console.log( + 'unknown effectiveDataType for date num', + effectiveDataType, + ); + return value; + } +} + +/** + * + * @param {number|string} inputDate Can be either a parseable format of date or an epoch value. + * @param {string} format a dateFormatPresets or a format pattern string. + * @param {boolean} useSystemCalendar If any custom calendar setting (e.g. quarterStartMonth) + * is to be ignored. + * @return {string} Returns the formatted date per the format. + */ +export function formatDate( + inputDate: number | string, + format: string, + useSystemCalendar: boolean, + options: any, +): string { + let formatPattern = format; + let newInputDate: any = inputDate; + if (newInputDate === undefined || newInputDate === null) { + return '{Null}'; + } + if (!formatPattern) { + formatPattern = dateFormatPresets.DATE_SHORT; + } + if ( + newInputDate === '{Null}' || + newInputDate === '{Empty}' || + newInputDate === '{Other}' + ) { + return newInputDate; + } + newInputDate = sanitizeDate(newInputDate, format); + if (_.isNaN(newInputDate)) { + return '{Null}'; + } + let epochMillis = newInputDate; + if (_.isDate(epochMillis)) { + epochMillis = newInputDate.getTime(); + } + if (!_.isNumber(epochMillis)) { + console.log( + 'formatDate could not convert input date to a timestamp', + inputDate, + ); + return `${inputDate}`; + } + return formatDateTime(epochMillis, format, useSystemCalendar, options); +} + /** * Formats the date value based on the column's properties and custom calendar settings. * diff --git a/src/utils/date-utils.ts b/src/utils/date-utils.ts new file mode 100644 index 0000000..de16543 --- /dev/null +++ b/src/utils/date-utils.ts @@ -0,0 +1,20 @@ +import _ from 'lodash'; +import { ChartColumn, ColumnTimeBucket } from '../types/answer-column.types'; +import { bucketizationToDatePreset, timeBuckets } from './date-formatting'; + +export function getFormatPatternForBucket(bucket: ColumnTimeBucket): any { + return bucketizationToDatePreset[ + ColumnTimeBucket[bucket] as keyof typeof bucketizationToDatePreset + ]; +} + +export const getTimeBucket = (col: ChartColumn): string => + _.get(timeBuckets, ColumnTimeBucket[col.timeBucket], timeBuckets.NO_BUCKET); + +export const showDateFinancialYearFormat = (col: ChartColumn) => { + const supportedBucketizations = [timeBuckets.QUARTERLY, timeBuckets.YEARLY]; + const currentBucketization = getTimeBucket(col); + return supportedBucketizations.some((supportedBucketization) => { + return supportedBucketization === currentBucketization; + }); +}; diff --git a/src/utils/formatting-util.ts b/src/utils/formatting-util.ts new file mode 100644 index 0000000..6d10734 --- /dev/null +++ b/src/utils/formatting-util.ts @@ -0,0 +1,148 @@ +import _ from 'lodash'; +import { CustomChartContext } from '../main/custom-chart-context'; +import { + ChartColumn, + ColumnAggregationType, + ColumnTimeBucket, + ColumnType, + DataType, +} from '../types/answer-column.types'; +import { + CustomCalendarDate, + dateFormatPresets, + formatDate, + formatDateNum, + getCustomCalendarGuidFromColumn, + getCustomCalendarValueFromEpoch, + getDisplayString, + getEffectiveDateNumDataType, + hasCustomCalendar, + isDateColumn, + isDateNumColumn, + isDateTimeColumn, +} from './date-formatting'; +import { + getFormatPatternForBucket, + showDateFinancialYearFormat, +} from './date-utils'; + +interface formatOptionsType { + isMillisIncluded: boolean; +} + +const getBucketization = (col: ChartColumn) => col.timeBucket; + +export const getFormatPattern = (col: ChartColumn): string => + getFormatPatternForBucket(getBucketization(col)) || col.format?.pattern; + +function getBaseTypeFormatterInstanceExpensive( + col: ChartColumn, + options: formatOptionsType, +): any { + let formatPattern = getFormatPattern(col); + // TODO: add numberic formatter if the col is numeric. + if (isDateColumn(col)) { + const showFinancialFormat = showDateFinancialYearFormat(col); + const isDateTime = isDateTimeColumn(col); + if (!formatPattern) { + if (isDateTime) { + if (options.isMillisIncluded) { + formatPattern = + dateFormatPresets.DATETIME_SHORT_WITH_MILLIS; + } else { + formatPattern = + dateFormatPresets.DATETIME_SHORT_WITH_SECONDS; + } + } + } + return (dataValue: any, options?: any) => { + const customCalendarValueFromEpoch: CustomCalendarDate = + getCustomCalendarValueFromEpoch( + col, + dataValue, + options?.displayToCustomCalendarValueMap, + ); + const customCalendarDisplayStr = getDisplayString( + customCalendarValueFromEpoch, + ); + if (customCalendarValueFromEpoch && customCalendarDisplayStr) { + return customCalendarDisplayStr; + } + const customCalendarOverridesFiscalOffset = + hasCustomCalendar(col) && + getCustomCalendarGuidFromColumn(col) !== 'FISCAL_CALENDER_GUID'; // TODO: replace with guid we get from ts-app; + const optionsWithFiscalOffset = { + ...options, + customCalendarOverridesFiscalOffset: + !!customCalendarOverridesFiscalOffset, + }; + return formatDate( + dataValue, + formatPattern, + !showFinancialFormat, + optionsWithFiscalOffset, + ); + }; + } + if (isDateNumColumn(col)) { + return (dataValue: any, options?: any) => { + const customCalendarValueFromEpoch: CustomCalendarDate = + getCustomCalendarValueFromEpoch( + col, + dataValue, + options?.displayToCustomCalendarValueMap, + ); + const customCalendarDisplayStr = getDisplayString( + customCalendarValueFromEpoch, + ); + if (customCalendarValueFromEpoch && customCalendarDisplayStr) { + return customCalendarDisplayStr; + } + return formatDateNum( + getEffectiveDateNumDataType(col), + dataValue, + formatPattern, + options, + ); + }; + } + return (dataValue: any, options?: any) => { + return dataValue; + }; +} +export const getDataFormatter = ( + col: ChartColumn, + options: formatOptionsType, + aggrTypeOverride?: ColumnAggregationType, +) => { + // TODO: number formatter for column based on column type based on + // aggregation type + + return getBaseTypeFormatterInstanceExpensive(col, options); +}; +export const generateMapOptions = ( + locale: string, + quarterStartMonth: number, + col: ChartColumn, + data: any, +): any => { + let customCalenderMap = {}; + + if ( + getCustomCalendarGuidFromColumn(col) !== null && + getCustomCalendarGuidFromColumn(col) !== undefined && + getCustomCalendarGuidFromColumn(col) !== '' + ) { + for (let i = 0; i < data.length; i++) { + customCalenderMap = { + ...customCalenderMap, + [data[i].v.s]: data[i], + }; + } + } + return { + locale, + quarterStartMonth, + displayToCustomCalendarValueMap: customCalenderMap, + }; +}; diff --git a/src/utils/translations/date-formatter.ts b/src/utils/translations/date-formatter.ts new file mode 100644 index 0000000..0af8af3 --- /dev/null +++ b/src/utils/translations/date-formatter.ts @@ -0,0 +1,36 @@ +import _ from 'lodash'; + +export const dateFormats: any = { + DATE_SHORT: 'dd/MM/yyyy', + DATE_SHORT_2_DIGIT_YEAR: 'dd/MM/yy', + DATE_SHORT_WITH_HOUR: 'dd/MM/yyyy hh a', + DATE_SHORT_WITH_HOUR_WITHOUT_YEAR: 'dd/MM hh a', + DATE_SHORT_WITH_HOUR_24: 'dd/MM/yy HH', + DATE_SHORT_WITH_HOUR_24_WITHOUT_YEAR: 'dd/MM HH', + DATETIME_SHORT: 'dd/MM/yyyy hh:mm a', + DATETIME_SHORT_WITHOUT_YEAR: 'dd/MM hh:mm a', + DATETIME_24_SHORT: 'dd/MM/yy HH:mm', + DATETIME_24_SHORT_WITH_MILLIS: 'dd/MM/yyyy HH:mm:ss.S', + DATETIME_24_SHORT_WITH_MILLIS_WITHOUT_YEAR: 'dd/MM HH:mm:ss.S', + DATETIME_SHORT_WITH_SECONDS: 'dd/MM/yyyy HH:mm:ss', + DATETIME_SHORT_WITH_SECONDS_WITHOUT_YEAR: 'dd/MM HH:mm:ss', + DATETIME_SHORT_WITH_MILLIS: 'MM/dd/yyyy HH:mm:ss.S', + DATETIME_SHORT_WITH_MILLIS_WITHOUT_YEAR: 'MM/dd HH:mm:ss.S', + QUARTER_WITH_YEAR: "'Q'q yyyy", + QUARTER_WITH_2_DIGIT_YEAR: "'Q'q yy", + DEFAULT_TIME_FORMAT: 'dd MMM, yyyy hh:mm:ss a ZZZZ', + MONTH_WITH_YEAR: 'MMM yyyy', + MONTH_WITH_DAY_AND_YEAR: 'dd MMM, yyyy', + MONTH_WITH_2_DIGIT_YEAR: 'MMM yy', + DAY_WITH_MONTH: 'dd MMM', + DAY_WITH_MONTH_NUM: 'dd/MM', + QUARTER: "'Q'q", + MONTH_ONLY: 'MMM', + DATETIME_WITH_SHORT_OFFSET: 'dd/MM/yyyy HH:mm:ss ZZZZ', +}; + +// TODO: discuss the current working. + +export function updateDateFormats(obj: any) { + _.merge(dateFormats, obj); +}