diff --git a/src/CONST.ts b/src/CONST.ts index 0a262d868de9..a5c61ff76ace 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -134,6 +134,8 @@ const CONST = { SQL_DATE_TIME: 'YYYY-MM-DD HH:mm:ss', FNS_FORMAT_STRING: 'yyyy-MM-dd', LOCAL_TIME_FORMAT: 'h:mm a', + YEAR_MONTH_FORMAT: 'yyyyMM', + MONTH_FORMAT: 'MMMM', WEEKDAY_TIME_FORMAT: 'eeee', MONTH_DAY_ABBR_FORMAT: 'MMM d', SHORT_DATE_FORMAT: 'MM-dd', diff --git a/src/components/AutoUpdateTime.js b/src/components/AutoUpdateTime.js index cb15cb20b4ea..e7d8b133e903 100644 --- a/src/components/AutoUpdateTime.js +++ b/src/components/AutoUpdateTime.js @@ -24,7 +24,7 @@ const propTypes = { function AutoUpdateTime(props) { /** - * @returns {moment} Returns the locale moment object + * @returns {Date} Returns the locale Date object */ const getCurrentUserLocalTime = useCallback( () => DateUtils.getLocalDateFromDatetime(props.preferredLocale, null, props.timezone.selected), diff --git a/src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js b/src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js index 62a1a50b3297..7a3c55305a33 100644 --- a/src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js +++ b/src/components/NewDatePicker/CalendarPicker/generateMonthMatrix.js @@ -1,5 +1,4 @@ -import moment from 'moment'; -import CONST from '../../../CONST'; +import {getDaysInMonth, startOfMonth, getDay, addDays, format} from 'date-fns'; /** * Generates a matrix representation of a month's calendar given the year and month. @@ -26,25 +25,25 @@ export default function generateMonthMatrix(year, month) { } // Get the number of days in the month and the first day of the month - const daysInMonth = moment([year, month]).daysInMonth(); - const firstDay = moment([year, month, 1]).locale(CONST.LOCALES.EN); + const firstDayOfMonth = startOfMonth(new Date(year, month, 1)); + const daysInMonth = getDaysInMonth(firstDayOfMonth); // Create a matrix to hold the calendar days const matrix = []; let currentWeek = []; // Add null values for days before the first day of the month - for (let i = 0; i < firstDay.weekday(); i++) { + for (let i = 0; i < getDay(firstDayOfMonth); i++) { currentWeek.push(null); } // Add calendar days to the matrix for (let i = 1; i <= daysInMonth; i++) { - const day = moment([year, month, i]).locale(CONST.LOCALES.EN); - currentWeek.push(day.date()); + const currentDate = addDays(firstDayOfMonth, i - 1); + currentWeek.push(Number(format(currentDate, 'd'))); // Start a new row when the current week is full - if (day.weekday() === 6) { + if (getDay(currentDate) === 6) { matrix.push(currentWeek); currentWeek = []; } diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts index 97184100cfcf..a6f2860310c2 100644 --- a/src/libs/DateUtils.ts +++ b/src/libs/DateUtils.ts @@ -73,7 +73,7 @@ function setLocale(localeString: string) { /** * Gets the user's stored time zone NVP and returns a localized - * Moment object for the given ISO-formatted datetime string + * Date object for the given ISO-formatted datetime string */ function getLocalDateFromDatetime(locale: string, datetime: string, currentSelectedTimezone = timezone.selected): Date { setLocale(locale); @@ -350,10 +350,10 @@ const DateUtils = { setTimezoneUpdated, getMicroseconds, getDBTime, + setLocale, subtractMillisecondsFromDateTime, getDateStringFromISOTimestamp, getStatusUntilDate, - setLocale, isToday, isTomorrow, isYesterday, diff --git a/src/libs/EmojiUtils.js b/src/libs/EmojiUtils.js index 80665541e24b..136eee5a4116 100644 --- a/src/libs/EmojiUtils.js +++ b/src/libs/EmojiUtils.js @@ -1,5 +1,5 @@ import _ from 'underscore'; -import moment from 'moment'; +import {getUnixTime} from 'date-fns'; import Str from 'expensify-common/lib/str'; import Onyx from 'react-native-onyx'; import lodashGet from 'lodash/get'; @@ -220,7 +220,7 @@ function getFrequentlyUsedEmojis(newEmoji) { let frequentEmojiList = [...frequentlyUsedEmojis]; const maxFrequentEmojiCount = CONST.EMOJI_FREQUENT_ROW_COUNT * CONST.EMOJI_NUM_PER_ROW - 1; - const currentTimestamp = moment().unix(); + const currentTimestamp = getUnixTime(new Date()); _.each([].concat(newEmoji), (emoji) => { let currentEmojiCount = 1; const emojiIndex = _.findIndex(frequentEmojiList, (e) => e.code === emoji.code); diff --git a/src/libs/actions/IOU.js b/src/libs/actions/IOU.js index c21e2dabe4a0..18418af797f1 100644 --- a/src/libs/actions/IOU.js +++ b/src/libs/actions/IOU.js @@ -2,7 +2,7 @@ import Onyx from 'react-native-onyx'; import _ from 'underscore'; import lodashGet from 'lodash/get'; import Str from 'expensify-common/lib/str'; -import moment from 'moment'; +import {format} from 'date-fns'; import CONST from '../../CONST'; import ROUTES from '../../ROUTES'; import ONYXKEYS from '../../ONYXKEYS'; @@ -110,7 +110,7 @@ Onyx.connect({ * @param {String} id */ function resetMoneyRequestInfo(id = '') { - const created = currentDate || moment().format('YYYY-MM-DD'); + const created = currentDate || format(new Date(), CONST.DATE.FNS_FORMAT_STRING); Onyx.merge(ONYXKEYS.IOU, { id, amount: 0, diff --git a/src/libs/actions/MapboxToken.js b/src/libs/actions/MapboxToken.js index e5824ef0302d..1d4e21ab66ee 100644 --- a/src/libs/actions/MapboxToken.js +++ b/src/libs/actions/MapboxToken.js @@ -1,5 +1,5 @@ import _ from 'underscore'; -import moment from 'moment'; +import {isAfter} from 'date-fns'; import Onyx from 'react-native-onyx'; import {AppState} from 'react-native'; import lodashGet from 'lodash/get'; @@ -42,7 +42,7 @@ const setExpirationTimer = () => { }, REFRESH_INTERVAL); }; -const hasTokenExpired = () => moment().isAfter(currentToken.expiration); +const hasTokenExpired = () => isAfter(new Date(), new Date(currentToken.expiration)); const clearToken = () => { console.debug('[MapboxToken] Deleting the token stored in Onyx'); diff --git a/src/libs/actions/Report.js b/src/libs/actions/Report.js index e21d9fdd75c6..2780d8440eb2 100644 --- a/src/libs/actions/Report.js +++ b/src/libs/actions/Report.js @@ -4,7 +4,7 @@ import lodashGet from 'lodash/get'; import ExpensiMark from 'expensify-common/lib/ExpensiMark'; import Onyx from 'react-native-onyx'; import Str from 'expensify-common/lib/str'; -import moment from 'moment'; +import {format as timezoneFormat, utcToZonedTime} from 'date-fns-tz'; import ONYXKEYS from '../../ONYXKEYS'; import * as Pusher from '../Pusher/pusher'; import LocalNotification from '../Notification/LocalNotification'; @@ -1734,7 +1734,7 @@ function hasAccountIDEmojiReacted(accountID, users, skinTone) { * @param {Number} [skinTone] */ function addEmojiReaction(reportID, reportActionID, emoji, skinTone = preferredSkinTone) { - const createdAt = moment().utc().format(CONST.DATE.SQL_DATE_TIME); + const createdAt = timezoneFormat(utcToZonedTime(new Date(), 'UTC'), CONST.DATE.FNS_DB_FORMAT_STRING); const optimisticData = [ { onyxMethod: Onyx.METHOD.MERGE, diff --git a/src/libs/actions/User.js b/src/libs/actions/User.js index 1830d1e51f6f..78bd52988cdf 100644 --- a/src/libs/actions/User.js +++ b/src/libs/actions/User.js @@ -1,7 +1,7 @@ import _ from 'underscore'; import lodashGet from 'lodash/get'; import Onyx from 'react-native-onyx'; -import moment from 'moment'; +import {isBefore} from 'date-fns'; import ONYXKEYS from '../../ONYXKEYS'; import * as API from '../API'; import CONST from '../../CONST'; @@ -460,7 +460,7 @@ function isBlockedFromConcierge(blockedFromConciergeNVP) { return false; } - return moment().isBefore(moment(blockedFromConciergeNVP.expiresAt), 'day'); + return isBefore(new Date(), new Date(blockedFromConciergeNVP.expiresAt)); } function triggerNotifications(onyxUpdates) { diff --git a/src/pages/EnablePayments/AdditionalDetailsStep.js b/src/pages/EnablePayments/AdditionalDetailsStep.js index c304103f69c7..bd068ad9abcc 100644 --- a/src/pages/EnablePayments/AdditionalDetailsStep.js +++ b/src/pages/EnablePayments/AdditionalDetailsStep.js @@ -3,7 +3,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import {withOnyx} from 'react-native-onyx'; import {View} from 'react-native'; -import moment from 'moment/moment'; +import {subYears} from 'date-fns'; import {parsePhoneNumber} from 'awesome-phonenumber'; import IdologyQuestions from './IdologyQuestions'; import ScreenWrapper from '../../components/ScreenWrapper'; @@ -80,8 +80,9 @@ const fieldNameTranslationKeys = { }; function AdditionalDetailsStep({walletAdditionalDetails, translate, currentUserPersonalDetails}) { - const minDate = moment().subtract(CONST.DATE_BIRTH.MAX_AGE, 'Y').toDate(); - const maxDate = moment().subtract(CONST.DATE_BIRTH.MIN_AGE_FOR_PAYMENT, 'Y').toDate(); + const currentDate = new Date(); + const minDate = subYears(currentDate, CONST.DATE_BIRTH.MAX_AGE); + const maxDate = subYears(currentDate, CONST.DATE_BIRTH.MIN_AGE_FOR_PAYMENT); const shouldAskForFullSSN = walletAdditionalDetails.errorCode === CONST.WALLET.ERROR.SSN; /** diff --git a/src/pages/ReimbursementAccount/IdentityForm.js b/src/pages/ReimbursementAccount/IdentityForm.js index 8e13a49b68d9..20c6e10ec64d 100644 --- a/src/pages/ReimbursementAccount/IdentityForm.js +++ b/src/pages/ReimbursementAccount/IdentityForm.js @@ -1,7 +1,7 @@ import React from 'react'; import {View} from 'react-native'; import PropTypes from 'prop-types'; -import moment from 'moment/moment'; +import {subYears} from 'date-fns'; import _ from 'underscore'; import TextInput from '../../components/TextInput'; import styles from '../../styles/styles'; @@ -134,8 +134,8 @@ function IdentityForm(props) { const dobErrorText = (props.errors.dob ? props.translate('bankAccount.error.dob') : '') || (props.errors.dobAge ? props.translate('bankAccount.error.age') : ''); const identityFormInputKeys = ['firstName', 'lastName', 'dob', 'ssnLast4']; - const minDate = moment().subtract(CONST.DATE_BIRTH.MAX_AGE, 'Y').toDate(); - const maxDate = moment().subtract(CONST.DATE_BIRTH.MIN_AGE_FOR_PAYMENT, 'Y').toDate(); + const minDate = subYears(new Date(), CONST.DATE_BIRTH.MAX_AGE); + const maxDate = subYears(new Date(), CONST.DATE_BIRTH.MIN_AGE_FOR_PAYMENT); return ( diff --git a/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.js b/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.js index 8b4406329616..886a3949766d 100644 --- a/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.js +++ b/src/pages/settings/Profile/PersonalDetails/DateOfBirthPage.js @@ -1,8 +1,8 @@ -import moment from 'moment'; import PropTypes from 'prop-types'; import React, {useCallback} from 'react'; import {withOnyx} from 'react-native-onyx'; import lodashGet from 'lodash/get'; +import {subYears} from 'date-fns'; import CONST from '../../../../CONST'; import ONYXKEYS from '../../../../ONYXKEYS'; import ROUTES from '../../../../ROUTES'; @@ -84,8 +84,8 @@ function DateOfBirthPage({translate, privatePersonalDetails}) { inputID="dob" label={translate('common.date')} defaultValue={privatePersonalDetails.dob || ''} - minDate={moment().subtract(CONST.DATE_BIRTH.MAX_AGE, 'years').toDate()} - maxDate={moment().subtract(CONST.DATE_BIRTH.MIN_AGE, 'years').toDate()} + minDate={subYears(new Date(), CONST.DATE_BIRTH.MAX_AGE)} + maxDate={subYears(new Date(), CONST.DATE_BIRTH.MIN_AGE)} /> )} diff --git a/src/pages/wallet/WalletStatementPage.js b/src/pages/wallet/WalletStatementPage.js index 91563a44ddd5..b220776cd9ef 100644 --- a/src/pages/wallet/WalletStatementPage.js +++ b/src/pages/wallet/WalletStatementPage.js @@ -2,7 +2,7 @@ import React, {useEffect} from 'react'; import PropTypes from 'prop-types'; import lodashGet from 'lodash/get'; import {withOnyx} from 'react-native-onyx'; -import moment from 'moment'; +import {format, getMonth, getYear} from 'date-fns'; import Str from 'expensify-common/lib/str'; import Navigation from '../../libs/Navigation/Navigation'; import withLocalize, {withLocalizePropTypes} from '../../components/withLocalize'; @@ -19,6 +19,7 @@ import CONST from '../../CONST'; import FullPageOfflineBlockingView from '../../components/BlockingViews/FullPageOfflineBlockingView'; import {withNetwork} from '../../components/OnyxProvider'; import networkPropTypes from '../../components/networkPropTypes'; +import DateUtils from '../../libs/DateUtils'; const propTypes = { /** The route object passed to this page from the navigator */ @@ -55,7 +56,7 @@ function WalletStatementPage(props) { const yearMonth = lodashGet(props.route.params, 'yearMonth', null); useEffect(() => { - const currentYearMonth = moment().format('YYYYMM'); + const currentYearMonth = format(new Date(), CONST.DATE.YEAR_MONTH_FORMAT); if (!yearMonth || yearMonth.length !== 6 || yearMonth > currentYearMonth) { Navigation.dismissModal(); } @@ -63,7 +64,7 @@ function WalletStatementPage(props) { }, []); useEffect(() => { - moment.locale(props.preferredLocale); + DateUtils.setLocale(props.preferredLocale); }, [props.preferredLocale]); const processDownload = () => { @@ -84,9 +85,9 @@ function WalletStatementPage(props) { User.generateStatementPDF(yearMonth); }; - const year = yearMonth.substring(0, 4) || moment().year(); - const month = yearMonth.substring(4) || moment().month(); - const monthName = moment(month, 'M').format('MMMM'); + const year = yearMonth.substring(0, 4) || getYear(new Date()); + const month = yearMonth.substring(4) || getMonth(new Date()); + const monthName = format(new Date(year, month), CONST.DATE.MONTH_FORMAT); const title = `${monthName} ${year} statement`; const url = `${CONFIG.EXPENSIFY.EXPENSIFY_URL}statement.php?period=${yearMonth}`; diff --git a/tests/actions/ReportTest.js b/tests/actions/ReportTest.js index 06d8304111cb..c7ef68547cdc 100644 --- a/tests/actions/ReportTest.js +++ b/tests/actions/ReportTest.js @@ -1,7 +1,7 @@ import _ from 'underscore'; import Onyx from 'react-native-onyx'; import lodashGet from 'lodash/get'; -import moment from 'moment'; +import {utcToZonedTime} from 'date-fns-tz'; import {beforeEach, beforeAll, afterEach, describe, it, expect} from '@jest/globals'; import ONYXKEYS from '../../src/ONYXKEYS'; import CONST from '../../src/CONST'; @@ -19,6 +19,7 @@ import OnyxUpdateManager from '../../src/libs/actions/OnyxUpdateManager'; import waitForNetworkPromises from '../utils/waitForNetworkPromises'; import getIsUsingFakeTimers from '../utils/getIsUsingFakeTimers'; +const UTC = 'UTC'; jest.mock('../../src/libs/actions/Report', () => { const originalModule = jest.requireActual('../../src/libs/actions/Report'); @@ -275,7 +276,7 @@ describe('actions/Report', () => { .then(() => { // The report will be read expect(ReportUtils.isUnread(report)).toBe(false); - expect(moment.utc(report.lastReadTime).valueOf()).toBeGreaterThanOrEqual(moment.utc(currentTime).valueOf()); + expect(utcToZonedTime(report.lastReadTime, UTC).getTime()).toBeGreaterThanOrEqual(utcToZonedTime(currentTime, UTC).getTime()); // And no longer show the green dot for unread mentions in the LHN expect(ReportUtils.isUnreadWithMention(report)).toBe(false); @@ -301,7 +302,7 @@ describe('actions/Report', () => { // The report will be read, the green dot for unread mentions will go away, and the lastReadTime updated expect(ReportUtils.isUnread(report)).toBe(false); expect(ReportUtils.isUnreadWithMention(report)).toBe(false); - expect(moment.utc(report.lastReadTime).valueOf()).toBeGreaterThanOrEqual(moment.utc(currentTime).valueOf()); + expect(utcToZonedTime(report.lastReadTime, UTC).getTime()).toBeGreaterThanOrEqual(utcToZonedTime(currentTime, UTC).getTime()); expect(report.lastMessageText).toBe('Current User Comment 1'); // When another comment is added by the current user @@ -313,7 +314,7 @@ describe('actions/Report', () => { .then(() => { // The report will be read and the lastReadTime updated expect(ReportUtils.isUnread(report)).toBe(false); - expect(moment.utc(report.lastReadTime).valueOf()).toBeGreaterThanOrEqual(moment.utc(currentTime).valueOf()); + expect(utcToZonedTime(report.lastReadTime, UTC).getTime()).toBeGreaterThanOrEqual(utcToZonedTime(currentTime, UTC).getTime()); expect(report.lastMessageText).toBe('Current User Comment 2'); // When another comment is added by the current user @@ -325,7 +326,7 @@ describe('actions/Report', () => { .then(() => { // The report will be read and the lastReadTime updated expect(ReportUtils.isUnread(report)).toBe(false); - expect(moment.utc(report.lastReadTime).valueOf()).toBeGreaterThanOrEqual(moment.utc(currentTime).valueOf()); + expect(utcToZonedTime(report.lastReadTime, UTC).getTime()).toBeGreaterThanOrEqual(utcToZonedTime(currentTime, UTC).getTime()); expect(report.lastMessageText).toBe('Current User Comment 3'); const USER_1_BASE_ACTION = { diff --git a/tests/ui/UnreadIndicatorsTest.js b/tests/ui/UnreadIndicatorsTest.js index eadc94da6e37..361eb8f87081 100644 --- a/tests/ui/UnreadIndicatorsTest.js +++ b/tests/ui/UnreadIndicatorsTest.js @@ -3,7 +3,8 @@ import Onyx from 'react-native-onyx'; import {Linking, AppState} from 'react-native'; import {fireEvent, render, screen, waitFor} from '@testing-library/react-native'; import lodashGet from 'lodash/get'; -import moment from 'moment'; +import {subMinutes, format, addSeconds, subSeconds} from 'date-fns'; +import {utcToZonedTime} from 'date-fns-tz'; import App from '../../src/App'; import CONST from '../../src/CONST'; import ONYXKEYS from '../../src/ONYXKEYS'; @@ -117,7 +118,6 @@ const USER_B_ACCOUNT_ID = 2; const USER_B_EMAIL = 'user_b@test.com'; const USER_C_ACCOUNT_ID = 3; const USER_C_EMAIL = 'user_c@test.com'; -const MOMENT_FORMAT = 'YYYY-MM-DD HH:mm:ss.SSS'; let reportAction3CreatedDate; let reportAction9CreatedDate; @@ -142,9 +142,9 @@ function signInAndGetAppWithUnreadChat() { return waitForBatchedUpdates(); }) .then(() => { - const MOMENT_TEN_MINUTES_AGO = moment().subtract(10, 'minutes'); - reportAction3CreatedDate = MOMENT_TEN_MINUTES_AGO.clone().add(30, 'seconds').format(MOMENT_FORMAT); - reportAction9CreatedDate = MOMENT_TEN_MINUTES_AGO.clone().add(90, 'seconds').format(MOMENT_FORMAT); + const TEN_MINUTES_AGO = subMinutes(new Date(), 10); + reportAction3CreatedDate = format(addSeconds(TEN_MINUTES_AGO, 30), CONST.DATE.FNS_DB_FORMAT_STRING); + reportAction9CreatedDate = format(addSeconds(TEN_MINUTES_AGO, 90), CONST.DATE.FNS_DB_FORMAT_STRING); // Simulate setting an unread report and personal details Onyx.merge(`${ONYXKEYS.COLLECTION.REPORT}${REPORT_ID}`, { @@ -161,7 +161,7 @@ function signInAndGetAppWithUnreadChat() { [createdReportActionID]: { actionName: CONST.REPORT.ACTIONS.TYPE.CREATED, automatic: false, - created: MOMENT_TEN_MINUTES_AGO.clone().format(MOMENT_FORMAT), + created: format(TEN_MINUTES_AGO, CONST.DATE.FNS_DB_FORMAT_STRING), reportActionID: createdReportActionID, message: [ { @@ -176,14 +176,14 @@ function signInAndGetAppWithUnreadChat() { }, ], }, - 1: TestHelper.buildTestReportComment(MOMENT_TEN_MINUTES_AGO.clone().add(10, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID, '1'), - 2: TestHelper.buildTestReportComment(MOMENT_TEN_MINUTES_AGO.clone().add(20, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID, '2'), + 1: TestHelper.buildTestReportComment(format(addSeconds(TEN_MINUTES_AGO, 10), CONST.DATE.FNS_DB_FORMAT_STRING), USER_B_ACCOUNT_ID, '1'), + 2: TestHelper.buildTestReportComment(format(addSeconds(TEN_MINUTES_AGO, 20), CONST.DATE.FNS_DB_FORMAT_STRING), USER_B_ACCOUNT_ID, '2'), 3: TestHelper.buildTestReportComment(reportAction3CreatedDate, USER_B_ACCOUNT_ID, '3'), - 4: TestHelper.buildTestReportComment(MOMENT_TEN_MINUTES_AGO.clone().add(40, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID, '4'), - 5: TestHelper.buildTestReportComment(MOMENT_TEN_MINUTES_AGO.clone().add(50, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID, '5'), - 6: TestHelper.buildTestReportComment(MOMENT_TEN_MINUTES_AGO.clone().add(60, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID, '6'), - 7: TestHelper.buildTestReportComment(MOMENT_TEN_MINUTES_AGO.clone().add(70, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID, '7'), - 8: TestHelper.buildTestReportComment(MOMENT_TEN_MINUTES_AGO.clone().add(80, 'seconds').format(MOMENT_FORMAT), USER_B_ACCOUNT_ID, '8'), + 4: TestHelper.buildTestReportComment(format(addSeconds(TEN_MINUTES_AGO, 40), CONST.DATE.FNS_DB_FORMAT_STRING), USER_B_ACCOUNT_ID, '4'), + 5: TestHelper.buildTestReportComment(format(addSeconds(TEN_MINUTES_AGO, 50), CONST.DATE.FNS_DB_FORMAT_STRING), USER_B_ACCOUNT_ID, '5'), + 6: TestHelper.buildTestReportComment(format(addSeconds(TEN_MINUTES_AGO, 60), CONST.DATE.FNS_DB_FORMAT_STRING), USER_B_ACCOUNT_ID, '6'), + 7: TestHelper.buildTestReportComment(format(addSeconds(TEN_MINUTES_AGO, 70), CONST.DATE.FNS_DB_FORMAT_STRING), USER_B_ACCOUNT_ID, '7'), + 8: TestHelper.buildTestReportComment(format(addSeconds(TEN_MINUTES_AGO, 80), CONST.DATE.FNS_DB_FORMAT_STRING), USER_B_ACCOUNT_ID, '8'), 9: TestHelper.buildTestReportComment(reportAction9CreatedDate, USER_B_ACCOUNT_ID, '9'), }); Onyx.merge(ONYXKEYS.PERSONAL_DETAILS_LIST, { @@ -287,10 +287,10 @@ describe('Unread Indicators', () => { signInAndGetAppWithUnreadChat() .then(() => { // Simulate a new report arriving via Pusher along with reportActions and personalDetails for the other participant - // We set the created moment 5 seconds in the past to ensure that time has passed when we open the report + // We set the created date 5 seconds in the past to ensure that time has passed when we open the report const NEW_REPORT_ID = '2'; - const NEW_REPORT_CREATED_MOMENT = moment().subtract(5, 'seconds'); - const NEW_REPORT_FIST_MESSAGE_CREATED_MOMENT = NEW_REPORT_CREATED_MOMENT.add(1, 'seconds'); + const NEW_REPORT_CREATED_DATE = subSeconds(new Date(), 5); + const NEW_REPORT_FIST_MESSAGE_CREATED_DATE = addSeconds(NEW_REPORT_CREATED_DATE, 1); const createdReportActionID = NumberUtils.rand64(); const commentReportActionID = NumberUtils.rand64(); @@ -306,7 +306,7 @@ describe('Unread Indicators', () => { reportID: NEW_REPORT_ID, reportName: CONST.REPORT.DEFAULT_REPORT_NAME, lastReadTime: '', - lastVisibleActionCreated: DateUtils.getDBTime(NEW_REPORT_FIST_MESSAGE_CREATED_MOMENT.utc().valueOf()), + lastVisibleActionCreated: DateUtils.getDBTime(utcToZonedTime(NEW_REPORT_FIST_MESSAGE_CREATED_DATE, 'UTC').valueOf()), lastMessageText: 'Comment 1', participantAccountIDs: [USER_C_ACCOUNT_ID], }, @@ -318,14 +318,14 @@ describe('Unread Indicators', () => { [createdReportActionID]: { actionName: CONST.REPORT.ACTIONS.TYPE.CREATED, automatic: false, - created: NEW_REPORT_CREATED_MOMENT.format(MOMENT_FORMAT), + created: format(NEW_REPORT_CREATED_DATE, CONST.DATE.FNS_DB_FORMAT_STRING), reportActionID: createdReportActionID, }, [commentReportActionID]: { actionName: CONST.REPORT.ACTIONS.TYPE.ADDCOMMENT, actorAccountID: USER_C_ACCOUNT_ID, person: [{type: 'TEXT', style: 'strong', text: 'User C'}], - created: NEW_REPORT_FIST_MESSAGE_CREATED_MOMENT.format(MOMENT_FORMAT), + created: format(NEW_REPORT_FIST_MESSAGE_CREATED_DATE, CONST.DATE.FNS_DB_FORMAT_STRING), message: [{type: 'COMMENT', html: 'Comment 1', text: 'Comment 1'}], reportActionID: commentReportActionID, }, diff --git a/tests/unit/CalendarPickerTest.js b/tests/unit/CalendarPickerTest.js index 71e31695a801..512a86a25e19 100644 --- a/tests/unit/CalendarPickerTest.js +++ b/tests/unit/CalendarPickerTest.js @@ -1,10 +1,17 @@ import {render, fireEvent, within} from '@testing-library/react-native'; -import moment from 'moment'; +import {format, eachMonthOfInterval, subYears, addYears} from 'date-fns'; +import DateUtils from '../../src/libs/DateUtils'; import CalendarPicker from '../../src/components/NewDatePicker/CalendarPicker'; import CONST from '../../src/CONST'; -moment.locale(CONST.LOCALES.EN); -const monthNames = moment.localeData().months(); +DateUtils.setLocale(CONST.LOCALES.EN); +const fullYear = new Date().getFullYear(); +const monthsArray = eachMonthOfInterval({ + start: new Date(fullYear, 0, 1), // January 1st of the current year + end: new Date(fullYear, 11, 31), // December 31st of the current year +}); +// eslint-disable-next-line rulesdir/prefer-underscore-method +const monthNames = monthsArray.map((monthDate) => format(monthDate, CONST.DATE.MONTH_FORMAT)); jest.mock('@react-navigation/native', () => ({ useNavigation: () => ({navigate: jest.fn()}), @@ -33,8 +40,8 @@ describe('CalendarPicker', () => { test('displays the current month and year', () => { const currentDate = new Date(); - const maxDate = moment(currentDate).add(1, 'Y').toDate(); - const minDate = moment(currentDate).subtract(1, 'Y').toDate(); + const maxDate = addYears(new Date(currentDate), 1); + const minDate = subYears(new Date(currentDate), 1); const {getByText} = render( { beforeAll(() => { Onyx.init({ keys: ONYXKEYS, initialKeyStates: { [ONYXKEYS.SESSION]: {accountID: 999}, - [ONYXKEYS.PERSONAL_DETAILS_LIST]: {999: {timezone: {selected: 'UTC'}}}, + [ONYXKEYS.PERSONAL_DETAILS_LIST]: {999: {timezone: {selected: UTC}}}, }, }); return waitForBatchedUpdates(); @@ -73,7 +73,7 @@ describe('DateUtils', () => { Intl.DateTimeFormat = jest.fn(() => ({ resolvedOptions: () => ({timeZone: 'America/Chicago'}), })); - Onyx.set(ONYXKEYS.PERSONAL_DETAILS_LIST, {999: {timezone: {selected: 'UTC', automatic: true}}}).then(() => { + Onyx.set(ONYXKEYS.PERSONAL_DETAILS_LIST, {999: {timezone: {selected: UTC, automatic: true}}}).then(() => { const result = DateUtils.getCurrentTimezone(); expect(result).toEqual({ selected: 'America/Chicago', @@ -84,12 +84,12 @@ describe('DateUtils', () => { it('should not update timezone if automatic and selected timezone match', () => { Intl.DateTimeFormat = jest.fn(() => ({ - resolvedOptions: () => ({timeZone: 'UTC'}), + resolvedOptions: () => ({timeZone: UTC}), })); - Onyx.set(ONYXKEYS.PERSONAL_DETAILS_LIST, {999: {timezone: {selected: 'UTC', automatic: true}}}).then(() => { + Onyx.set(ONYXKEYS.PERSONAL_DETAILS_LIST, {999: {timezone: {selected: UTC, automatic: true}}}).then(() => { const result = DateUtils.getCurrentTimezone(); expect(result).toEqual({ - selected: 'UTC', + selected: UTC, automatic: true, }); }); diff --git a/tests/unit/EmojiTest.js b/tests/unit/EmojiTest.js index 2cc38648f0d9..d10da618480e 100644 --- a/tests/unit/EmojiTest.js +++ b/tests/unit/EmojiTest.js @@ -1,5 +1,5 @@ import _ from 'underscore'; -import moment from 'moment'; +import {getUnixTime} from 'date-fns'; import Onyx from 'react-native-onyx'; import lodashGet from 'lodash/get'; import Emoji from '../../assets/emojis'; @@ -206,7 +206,7 @@ describe('EmojiTest', () => { return waitForBatchedUpdates().then(() => { // When add a new emoji - const currentTime = moment().unix(); + const currentTime = getUnixTime(new Date()); const smileEmoji = {code: '😄', name: 'smile'}; const newEmoji = [smileEmoji]; User.updateFrequentlyUsedEmojis(EmojiUtils.getFrequentlyUsedEmojis(newEmoji)); @@ -254,7 +254,7 @@ describe('EmojiTest', () => { return waitForBatchedUpdates().then(() => { // When add an emoji that exists in the list - const currentTime = moment().unix(); + const currentTime = getUnixTime(new Date()); const newEmoji = [smileEmoji]; User.updateFrequentlyUsedEmojis(EmojiUtils.getFrequentlyUsedEmojis(newEmoji)); @@ -296,7 +296,7 @@ describe('EmojiTest', () => { return waitForBatchedUpdates().then(() => { // When add multiple emojis that either exist or not exist in the list - const currentTime = moment().unix(); + const currentTime = getUnixTime(new Date()); const newEmoji = [smileEmoji, zzzEmoji, impEmoji]; User.updateFrequentlyUsedEmojis(EmojiUtils.getFrequentlyUsedEmojis(newEmoji)); @@ -467,7 +467,7 @@ describe('EmojiTest', () => { return waitForBatchedUpdates().then(() => { // When add new emojis - const currentTime = moment().unix(); + const currentTime = getUnixTime(new Date()); const newEmoji = [bookEmoji, smileEmoji, zzzEmoji, impEmoji, smileEmoji]; User.updateFrequentlyUsedEmojis(EmojiUtils.getFrequentlyUsedEmojis(newEmoji)); diff --git a/tests/unit/createOrUpdateStagingDeployTest.js b/tests/unit/createOrUpdateStagingDeployTest.js index dd87e74f6faa..9183268f15f0 100644 --- a/tests/unit/createOrUpdateStagingDeployTest.js +++ b/tests/unit/createOrUpdateStagingDeployTest.js @@ -2,7 +2,7 @@ * @jest-environment node */ const core = require('@actions/core'); -const moment = require('moment'); +const fns = require('date-fns'); const CONST = require('../../.github/libs/CONST'); const GitUtils = require('../../.github/libs/GitUtils'); const GithubUtils = require('../../.github/libs/GithubUtils'); @@ -168,7 +168,7 @@ describe('createOrUpdateStagingDeployCash', () => { expect(result).toStrictEqual({ owner: CONST.GITHUB_OWNER, repo: CONST.APP_REPO, - title: `Deploy Checklist: New Expensify ${moment().format('YYYY-MM-DD')}`, + title: `Deploy Checklist: New Expensify ${fns.format(new Date(), 'yyyy-MM-dd')}`, labels: [CONST.LABELS.STAGING_DEPLOY], html_url: 'https://github.com/Expensify/App/issues/29', assignees: [CONST.APPLAUSE_BOT],