From f42c5794d5abe90031b391bdf9aaad6a02b337e8 Mon Sep 17 00:00:00 2001 From: Weslley Alves de Oliveira Date: Wed, 25 Oct 2023 15:44:35 -0300 Subject: [PATCH 1/4] Add new method formatWithUTCTimeZone to format the date using the UTC timezone --- src/libs/DateUtils.ts | 20 +++++++++++++++++++- tests/unit/DateUtilsTest.js | 26 ++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts index e03e3dd5568..8012f021772 100644 --- a/src/libs/DateUtils.ts +++ b/src/libs/DateUtils.ts @@ -8,13 +8,14 @@ import { isBefore, isSameDay, isSameYear, + isValid, setDefaultOptions, startOfWeek, subDays, subMilliseconds, subMinutes, } from 'date-fns'; -import {formatInTimeZone, utcToZonedTime, zonedTimeToUtc} from 'date-fns-tz'; +import {formatInTimeZone, utcToZonedTime, zonedTimeToUtc, format as tzFormat} from 'date-fns-tz'; import {enGB, es} from 'date-fns/locale'; import throttle from 'lodash/throttle'; import Onyx from 'react-native-onyx'; @@ -335,6 +336,22 @@ function getStatusUntilDate(inputDate: string): string { return translateLocal('statusPage.untilTime', {time: format(input, `${CONST.DATE.FNS_FORMAT_STRING} ${CONST.DATE.LOCAL_TIME_FORMAT}`)}); } +/** + * Get a date and format this date using the UTC timezone. + * @param datetime + * @param dateFormat + * @returns If the date is valid, returns the formatted date with the UTC timezone, otherwise returns an empty string. + */ +function formatWithUTCTimeZone(datetime: string, dateFormat: string = CONST.DATE.FNS_FORMAT_STRING) { + const date = new Date(datetime); + + if (isValid(date)) { + return tzFormat(utcToZonedTime(date, 'UTC'), dateFormat); + } + + return ''; +} + const DateUtils = { formatToDayOfWeek, formatToLongDateWithWeekday, @@ -356,6 +373,7 @@ const DateUtils = { isToday, isTomorrow, isYesterday, + formatWithUTCTimeZone, }; export default DateUtils; diff --git a/tests/unit/DateUtilsTest.js b/tests/unit/DateUtilsTest.js index 4b76e0f496c..0303085f117 100644 --- a/tests/unit/DateUtilsTest.js +++ b/tests/unit/DateUtilsTest.js @@ -182,4 +182,30 @@ describe('DateUtils', () => { expect(getDBTime).toBe('2022-11-22 03:14:10.792'); }); }); + + describe('formatWithUTCTimeZone', () => { + describe('when the date is invalid', () => { + it('returns an empty string', () => { + const invalidDateStr = ''; + + const formattedDate = DateUtils.formatWithUTCTimeZone(invalidDateStr); + + expect(formattedDate).toEqual(''); + }); + }); + + describe('when the date is valid', () => { + const scenarios = [ + {dateFormat: CONST.DATE.FNS_FORMAT_STRING, expectedResult: '2022-11-07'}, + {dateFormat: CONST.DATE.FNS_TIMEZONE_FORMAT_STRING, expectedResult: '2022-11-07T00:00:00Z'}, + {dateFormat: CONST.DATE.FNS_DB_FORMAT_STRING, expectedResult: '2022-11-07 00:00:00.000'}, + ]; + + test.each(scenarios)('returns the date as string with the format "$dateFormat"', ({dateFormat, expectedResult}) => { + const formattedDate = DateUtils.formatWithUTCTimeZone(datetime, dateFormat); + + expect(formattedDate).toEqual(expectedResult); + }); + }); + }); }); From cb4d259a4ddce924d910c9fb885dde1906e0524c Mon Sep 17 00:00:00 2001 From: Weslley Alves de Oliveira Date: Wed, 25 Oct 2023 16:20:24 -0300 Subject: [PATCH 2/4] Refactor getCreated method to use the method formatWithUTCTimeZone from DateUtils to format the created date --- src/libs/DateUtils.ts | 4 +- src/libs/TransactionUtils.ts | 13 ++---- tests/unit/TransactionUtilsTest.ts | 64 ++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 tests/unit/TransactionUtilsTest.ts diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts index 8012f021772..bed4f079cd0 100644 --- a/src/libs/DateUtils.ts +++ b/src/libs/DateUtils.ts @@ -22,8 +22,8 @@ import Onyx from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import {Timezone} from '@src/types/onyx/PersonalDetails'; -import * as CurrentDate from './actions/CurrentDate'; -import * as Localize from './Localize'; +import * as CurrentDate from '@libs/actions/CurrentDate'; +import * as Localize from '@libs/Localize'; let currentUserAccountID: number | undefined; Onyx.connect({ diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index a30ba7fc272..e6517de0b43 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -1,12 +1,11 @@ -import {format, isValid} from 'date-fns'; import Onyx, {OnyxCollection} from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import {RecentWaypoint, ReportAction, Transaction} from '@src/types/onyx'; import {Comment, Receipt, Waypoint, WaypointCollection} from '@src/types/onyx/Transaction'; -import {isExpensifyCard} from './CardUtils'; -import DateUtils from './DateUtils'; -import * as NumberUtils from './NumberUtils'; +import {isExpensifyCard} from '@libs/CardUtils'; +import DateUtils from '@libs/DateUtils'; +import * as NumberUtils from '@libs/NumberUtils'; type AdditionalTransactionChanges = {comment?: string; waypoints?: WaypointCollection}; @@ -310,12 +309,8 @@ function getTag(transaction: Transaction): string { */ function getCreated(transaction: Transaction, dateFormat: string = CONST.DATE.FNS_FORMAT_STRING): string { const created = transaction?.modifiedCreated ? transaction.modifiedCreated : transaction?.created || ''; - const createdDate = new Date(created); - if (isValid(createdDate)) { - return format(createdDate, dateFormat); - } - return ''; + return DateUtils.formatWithUTCTimeZone(created, dateFormat); } function isDistanceRequest(transaction: Transaction): boolean { diff --git a/tests/unit/TransactionUtilsTest.ts b/tests/unit/TransactionUtilsTest.ts new file mode 100644 index 00000000000..89514e3b667 --- /dev/null +++ b/tests/unit/TransactionUtilsTest.ts @@ -0,0 +1,64 @@ +import type {Transaction} from '../../src/types/onyx'; +import * as TransactionUtils from '../../src/libs/TransactionUtils'; + +function generateTransaction(values: Partial = {}): Transaction { + const reportID = '1'; + const amount = 100; + const currency = 'USD'; + const comment = ''; + const created = '2023-10-01'; + const baseValues = TransactionUtils.buildOptimisticTransaction(amount, currency, reportID, comment, created); + + return {...baseValues, ...values}; +} + +describe('TransactionUtils', () => { + describe('getCreated', () => { + describe('when the transaction property "modifiedCreated" has value', () => { + const transaction = generateTransaction({ + created: '2023-10-01', + modifiedCreated: '2023-10-25', + }); + + it('returns the "modifiedCreated" date with the correct format', () => { + const expectedResult = '2023-10-25'; + + const result = TransactionUtils.getCreated(transaction); + + expect(result).toEqual(expectedResult); + }); + }); + + describe('when the transaction property "modifiedCreated" does not have value', () => { + describe('and the transaction property "created" has value', () => { + const transaction = generateTransaction({ + created: '2023-10-01', + modifiedCreated: undefined, + }); + + it('returns the "created" date with the correct format', () => { + const expectedResult = '2023-10-01'; + + const result = TransactionUtils.getCreated(transaction); + + expect(result).toEqual(expectedResult); + }); + }); + + describe('and the transaction property "created" does not have value', () => { + const transaction = generateTransaction({ + created: undefined, + modifiedCreated: undefined, + }); + + it('returns an empty string', () => { + const expectedResult = ''; + + const result = TransactionUtils.getCreated(transaction); + + expect(result).toEqual(expectedResult); + }); + }); + }); + }); +}); From bb8e3c3042dbc42e4186f9141fdf69b73b91a941 Mon Sep 17 00:00:00 2001 From: Weslley Alves de Oliveira Date: Thu, 26 Oct 2023 00:09:51 -0300 Subject: [PATCH 3/4] Fix Prettier issues --- tests/unit/TransactionUtilsTest.ts | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/unit/TransactionUtilsTest.ts b/tests/unit/TransactionUtilsTest.ts index 89514e3b667..c0033740433 100644 --- a/tests/unit/TransactionUtilsTest.ts +++ b/tests/unit/TransactionUtilsTest.ts @@ -46,19 +46,19 @@ describe('TransactionUtils', () => { }); describe('and the transaction property "created" does not have value', () => { - const transaction = generateTransaction({ - created: undefined, - modifiedCreated: undefined, - }); + const transaction = generateTransaction({ + created: undefined, + modifiedCreated: undefined, + }); - it('returns an empty string', () => { - const expectedResult = ''; + it('returns an empty string', () => { + const expectedResult = ''; - const result = TransactionUtils.getCreated(transaction); + const result = TransactionUtils.getCreated(transaction); - expect(result).toEqual(expectedResult); - }); - }); + expect(result).toEqual(expectedResult); + }); + }); }); }); }); From 7442875a1d7557b0ecda5459413d5d875fc5e077 Mon Sep 17 00:00:00 2001 From: Weslley Alves de Oliveira Date: Mon, 30 Oct 2023 07:06:40 -0300 Subject: [PATCH 4/4] fix: merge conflicts --- src/libs/DateUtils.ts | 6 +++--- src/libs/TransactionUtils.ts | 6 +++--- tests/unit/TransactionUtilsTest.ts | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts index bed4f079cd0..13853189ed2 100644 --- a/src/libs/DateUtils.ts +++ b/src/libs/DateUtils.ts @@ -15,15 +15,15 @@ import { subMilliseconds, subMinutes, } from 'date-fns'; -import {formatInTimeZone, utcToZonedTime, zonedTimeToUtc, format as tzFormat} from 'date-fns-tz'; +import {formatInTimeZone, format as tzFormat, utcToZonedTime, zonedTimeToUtc} from 'date-fns-tz'; import {enGB, es} from 'date-fns/locale'; import throttle from 'lodash/throttle'; import Onyx from 'react-native-onyx'; import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import {Timezone} from '@src/types/onyx/PersonalDetails'; -import * as CurrentDate from '@libs/actions/CurrentDate'; -import * as Localize from '@libs/Localize'; +import * as CurrentDate from './actions/CurrentDate'; +import * as Localize from './Localize'; let currentUserAccountID: number | undefined; Onyx.connect({ diff --git a/src/libs/TransactionUtils.ts b/src/libs/TransactionUtils.ts index e6517de0b43..acf10042b26 100644 --- a/src/libs/TransactionUtils.ts +++ b/src/libs/TransactionUtils.ts @@ -3,9 +3,9 @@ import CONST from '@src/CONST'; import ONYXKEYS from '@src/ONYXKEYS'; import {RecentWaypoint, ReportAction, Transaction} from '@src/types/onyx'; import {Comment, Receipt, Waypoint, WaypointCollection} from '@src/types/onyx/Transaction'; -import {isExpensifyCard} from '@libs/CardUtils'; -import DateUtils from '@libs/DateUtils'; -import * as NumberUtils from '@libs/NumberUtils'; +import {isExpensifyCard} from './CardUtils'; +import DateUtils from './DateUtils'; +import * as NumberUtils from './NumberUtils'; type AdditionalTransactionChanges = {comment?: string; waypoints?: WaypointCollection}; diff --git a/tests/unit/TransactionUtilsTest.ts b/tests/unit/TransactionUtilsTest.ts index c0033740433..e51ffede633 100644 --- a/tests/unit/TransactionUtilsTest.ts +++ b/tests/unit/TransactionUtilsTest.ts @@ -1,5 +1,5 @@ -import type {Transaction} from '../../src/types/onyx'; import * as TransactionUtils from '../../src/libs/TransactionUtils'; +import type {Transaction} from '../../src/types/onyx'; function generateTransaction(values: Partial = {}): Transaction { const reportID = '1';