diff --git a/src/CONST.ts b/src/CONST.ts index 3bce14516b80..49344be12932 100755 --- a/src/CONST.ts +++ b/src/CONST.ts @@ -189,6 +189,7 @@ const CONST = { MONTH_DAY_YEAR_FORMAT: 'MMMM d, yyyy', FNS_TIMEZONE_FORMAT_STRING: "yyyy-MM-dd'T'HH:mm:ssXXX", FNS_DB_FORMAT_STRING: 'yyyy-MM-dd HH:mm:ss.SSS', + ISO_LOCAL_DATE_TIME: 'yyyy-MM-dd HH:mm:ss', LONG_DATE_FORMAT_WITH_WEEKDAY: 'eeee, MMMM d, yyyy', UNIX_EPOCH: '1970-01-01 00:00:00.000', MAX_DATE: '9999-12-31', diff --git a/src/components/LHNOptionsList/OptionRowLHN.tsx b/src/components/LHNOptionsList/OptionRowLHN.tsx index 923337ba9ada..8ff781debad4 100644 --- a/src/components/LHNOptionsList/OptionRowLHN.tsx +++ b/src/components/LHNOptionsList/OptionRowLHN.tsx @@ -109,7 +109,7 @@ function OptionRowLHN({reportID, isFocused = false, onSelectRow = () => {}, opti const emojiCode = optionItem.status?.emojiCode ?? ''; const statusText = optionItem.status?.text ?? ''; - const statusClearAfterDate = optionItem.status?.clearAfter ?? ''; + const statusClearAfterDate = DateUtils.formatUTCToLocal(optionItem.status?.clearAfter ?? ''); const formattedDate = DateUtils.getStatusUntilDate(statusClearAfterDate); const statusContent = formattedDate ? `${statusText ? `${statusText} ` : ''}(${formattedDate})` : statusText; const report = ReportUtils.getReport(optionItem.reportID ?? ''); diff --git a/src/libs/DateUtils.ts b/src/libs/DateUtils.ts index 6da5c8af1ff2..31ac97ade94e 100644 --- a/src/libs/DateUtils.ts +++ b/src/libs/DateUtils.ts @@ -409,7 +409,7 @@ function getDateStringFromISOTimestamp(isoTimestamp: string): string { */ function getThirtyMinutesFromNow(): string { const date = addMinutes(new Date(), 30); - return format(date, 'yyyy-MM-dd HH:mm:ss'); + return format(date, CONST.DATE.ISO_LOCAL_DATE_TIME); } /** @@ -417,7 +417,7 @@ function getThirtyMinutesFromNow(): string { */ function getOneHourFromNow(): string { const date = addHours(new Date(), 1); - return format(date, 'yyyy-MM-dd HH:mm:ss'); + return format(date, CONST.DATE.ISO_LOCAL_DATE_TIME); } /** @@ -425,7 +425,7 @@ function getOneHourFromNow(): string { */ function getEndOfToday(): string { const date = endOfDay(new Date()); - return format(date, 'yyyy-MM-dd HH:mm:ss'); + return format(date, CONST.DATE.ISO_LOCAL_DATE_TIME); } /** @@ -433,7 +433,7 @@ function getEndOfToday(): string { */ function getOneWeekFromNow(): string { const date = addDays(new Date(), 7); - return format(date, 'yyyy-MM-dd HH:mm:ss'); + return format(date, CONST.DATE.ISO_LOCAL_DATE_TIME); } /** @@ -560,7 +560,7 @@ const combineDateAndTime = (updatedTime: string, inputDateTime: string): string let parsedTime: Date | null = null; if (updatedTime.includes('-')) { // it's in "yyyy-MM-dd HH:mm:ss" format - const tempTime = parse(updatedTime, 'yyyy-MM-dd HH:mm:ss', new Date()); + const tempTime = parse(updatedTime, CONST.DATE.ISO_LOCAL_DATE_TIME, new Date()); if (isValid(tempTime)) { parsedTime = tempTime; } @@ -579,7 +579,7 @@ const combineDateAndTime = (updatedTime: string, inputDateTime: string): string let parsedDateTime: Date | null = null; if (inputDateTime.includes(':')) { // Check if it includes time - const tempDateTime = parse(inputDateTime, 'yyyy-MM-dd HH:mm:ss', new Date()); + const tempDateTime = parse(inputDateTime, CONST.DATE.ISO_LOCAL_DATE_TIME, new Date()); if (isValid(tempDateTime)) { parsedDateTime = tempDateTime; } @@ -600,7 +600,7 @@ const combineDateAndTime = (updatedTime: string, inputDateTime: string): string seconds: parsedTime.getSeconds(), }); - return format(updatedDateTime, 'yyyy-MM-dd HH:mm:ss'); + return format(updatedDateTime, CONST.DATE.ISO_LOCAL_DATE_TIME); }; /** @@ -640,8 +640,8 @@ function getTimePeriod(timeString: string): TimePeriod { * returns {Boolean} */ function areDatesIdentical(dateTimeStringFirst: string, dateTimeStringSecond: string): boolean { - const date1 = parse(dateTimeStringFirst, 'yyyy-MM-dd HH:mm:ss', new Date()); - const date2 = parse(dateTimeStringSecond, 'yyyy-MM-dd HH:mm:ss', new Date()); + const date1 = parse(dateTimeStringFirst, CONST.DATE.ISO_LOCAL_DATE_TIME, new Date()); + const date2 = parse(dateTimeStringSecond, CONST.DATE.ISO_LOCAL_DATE_TIME, new Date()); return isSameSecond(date1, date2); } @@ -722,6 +722,30 @@ function formatWithUTCTimeZone(datetime: string, dateFormat: string = CONST.DATE return ''; } +/** + * Format the date from UTC to local timezone + * @param dateString + * @param dateFormat + * @returns + */ + +function formatUTCToLocal(dateString: string, dateFormat = CONST.DATE.ISO_LOCAL_DATE_TIME) { + if (dateString === '' || !dateString) { + return dateString; + } + + const date = parse(dateString, dateFormat, new Date()); + // Check if the date is valid + if (!isValid(date)) { + return ''; + } + + const localTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone; + const utcDate = zonedTimeToUtc(date, 'UTC'); + const localDate = zonedTimeToUtc(utcDate, localTimezone); + return tzFormat(localDate, dateFormat, {timeZone: localTimezone}); +} + /** * * @param timezone @@ -806,6 +830,7 @@ const DateUtils = { getMonthNames, getDaysOfWeek, formatWithUTCTimeZone, + formatUTCToLocal, getWeekStartsOn, getWeekEndsOn, isTimeAtLeastOneMinuteInFuture, diff --git a/src/libs/actions/User.ts b/src/libs/actions/User.ts index 5d089ed6e393..9705a7f48ed1 100644 --- a/src/libs/actions/User.ts +++ b/src/libs/actions/User.ts @@ -20,6 +20,7 @@ import type { ValidateSecondaryLoginParams, } from '@libs/API/parameters'; import {READ_COMMANDS, WRITE_COMMANDS} from '@libs/API/types'; +import DateUtils from '@libs/DateUtils'; import * as ErrorUtils from '@libs/ErrorUtils'; import Log from '@libs/Log'; import Navigation from '@libs/Navigation/Navigation'; @@ -902,19 +903,25 @@ function updateTheme(theme: ValueOf) { * Sets a custom status */ function updateCustomStatus(status: Status) { + const clearAfterInUtc = DateUtils.formatWithUTCTimeZone(status.clearAfter, CONST.DATE.ISO_LOCAL_DATE_TIME); + const newStatus = { + ...status, + clearAfter: clearAfterInUtc, + }; + const optimisticData: OnyxUpdate[] = [ { onyxMethod: Onyx.METHOD.MERGE, key: ONYXKEYS.PERSONAL_DETAILS_LIST, value: { [currentUserAccountID]: { - status, + status: newStatus, }, }, }, ]; - const parameters: UpdateStatusParams = {text: status.text, emojiCode: status.emojiCode, clearAfter: status.clearAfter}; + const parameters: UpdateStatusParams = {text: status.text, emojiCode: status.emojiCode, clearAfter: clearAfterInUtc}; API.write(WRITE_COMMANDS.UPDATE_STATUS, parameters, { optimisticData, diff --git a/src/pages/home/report/ReportActionItemSingle.tsx b/src/pages/home/report/ReportActionItemSingle.tsx index 741422cc7e82..a6aeb68b77c0 100644 --- a/src/pages/home/report/ReportActionItemSingle.tsx +++ b/src/pages/home/report/ReportActionItemSingle.tsx @@ -205,7 +205,8 @@ function ReportActionItemSingle({ ); }; const hasEmojiStatus = !displayAllActors && status?.emojiCode; - const formattedDate = DateUtils.getStatusUntilDate(status?.clearAfter ?? ''); + const statusClearAfter = DateUtils.formatUTCToLocal(status?.clearAfter ?? ''); + const formattedDate = DateUtils.getStatusUntilDate(statusClearAfter); const statusText = status?.text ?? ''; const statusTooltipText = formattedDate ? `${statusText ? `${statusText} ` : ''}(${formattedDate})` : statusText; diff --git a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js index 290d6431492d..ba9039539211 100644 --- a/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js +++ b/src/pages/settings/Profile/CustomStatus/StatusClearAfterPage.js @@ -84,7 +84,7 @@ const useValidateCustomDate = (data) => { function StatusClearAfterPage({currentUserPersonalDetails, customStatus}) { const styles = useThemeStyles(); const {translate} = useLocalize(); - const clearAfter = lodashGet(currentUserPersonalDetails, 'status.clearAfter', ''); + const clearAfter = DateUtils.formatUTCToLocal(lodashGet(currentUserPersonalDetails, 'status.clearAfter', '')); const draftClearAfter = lodashGet(customStatus, 'clearAfter', ''); const [draftPeriod, setDraftPeriod] = useState(getSelectedStatusType(draftClearAfter || clearAfter)); const statusType = useMemo( diff --git a/src/pages/settings/Profile/CustomStatus/StatusPage.js b/src/pages/settings/Profile/CustomStatus/StatusPage.js index f6c5f5543fa0..90700a34587d 100644 --- a/src/pages/settings/Profile/CustomStatus/StatusPage.js +++ b/src/pages/settings/Profile/CustomStatus/StatusPage.js @@ -48,7 +48,7 @@ function StatusPage({draftStatus, currentUserPersonalDetails}) { const [brickRoadIndicator, setBrickRoadIndicator] = useState(''); const currentUserEmojiCode = lodashGet(currentUserPersonalDetails, 'status.emojiCode', ''); const currentUserStatusText = lodashGet(currentUserPersonalDetails, 'status.text', ''); - const currentUserClearAfter = lodashGet(currentUserPersonalDetails, 'status.clearAfter', ''); + const currentUserClearAfter = DateUtils.formatUTCToLocal(lodashGet(currentUserPersonalDetails, 'status.clearAfter', '')); const draftEmojiCode = lodashGet(draftStatus, 'emojiCode'); const draftText = lodashGet(draftStatus, 'text'); const draftClearAfter = lodashGet(draftStatus, 'clearAfter');