Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion config/eslint/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ const restrictedImportPaths = [
},
{
name: 'date-fns/locale',
message: "Do not import 'date-fns/locale' directly. Please use the submodule import instead, like 'date-fns/locale/en-GB'.",
message: "Do not import 'date-fns/locale' directly. Please use the submodule import instead, like 'date-fns/locale/en-US'.",
},
{
name: 'expensify-common',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@ const LOCALIZED_TOKENS = [
{token: 'eeee', label: 'eeee (weekday name)'},
{token: 'eee', label: 'eee (short weekday)'},
{token: 'do', label: 'do (ordinal day)'},
// date-fns' localized date/time formats. These exist precisely to defer the clock convention, ordering and
// separators to the locale, so they are meaningless without one.
{token: 'PPPP', label: 'PPPP (localized long date with weekday)'},
{token: 'PPP', label: 'PPP (localized long date)'},
{token: 'PP', label: 'PP (localized medium date)'},
{token: 'P', label: 'P (localized short date)'},
{token: 'pppp', label: 'pppp (localized full time)'},
{token: 'ppp', label: 'ppp (localized long time)'},
{token: 'pp', label: 'pp (localized medium time)'},
{token: 'p', label: 'p (localized short time)'},
{token: 'aaaa', label: 'aaaa (AM/PM)'},
{token: 'aaa', label: 'aaa (AM/PM)'},
{token: 'aa', label: 'aa (AM/PM)'},
Expand All @@ -55,16 +65,7 @@ const DATE_FNS_MODULES = new Set(['date-fns', 'date-fns-tz']);
* `CONST.DATE.*` formats with no language-dependent tokens. Anything else in `CONST.DATE` is treated as localized, so a
* newly added format is guarded by default rather than silently escaping this rule.
*/
const MACHINE_DATE_CONSTANTS = new Set([
'FNS_FORMAT_STRING',
'FNS_DATE_TIME_FORMAT_STRING',
'FNS_DB_FORMAT_STRING',
'FNS_TIMEZONE_FORMAT_STRING',
'YEAR_MONTH_FORMAT',
'SHORT_DATE_FORMAT',
'LOCAL_TIME_FORMAT_WITHOUT_PERIOD',
'TIME_FORMAT_WITHOUT_PERIOD',
]);
const MACHINE_DATE_CONSTANTS = new Set(['FNS_FORMAT_STRING', 'FNS_DATE_TIME_FORMAT_STRING', 'FNS_DB_FORMAT_STRING', 'FNS_TIMEZONE_FORMAT_STRING', 'YEAR_MONTH_FORMAT', 'SHORT_DATE_FORMAT']);

/**
* Strips the single-quoted escaped literals date-fns supports (e.g. the "T" in `yyyy-MM-dd'T'HH:mm`)
Expand Down
8 changes: 5 additions & 3 deletions src/CONST/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -692,9 +692,11 @@ const CONST = {
DATE: {
FNS_FORMAT_STRING: 'yyyy-MM-dd',
FNS_DATE_TIME_FORMAT_STRING: 'yyyy-MM-dd HH:mm:ss',
LOCAL_TIME_FORMAT: 'h:mm a',
LOCAL_TIME_FORMAT_WITHOUT_PERIOD: 'h:mm',
TIME_FORMAT_WITHOUT_PERIOD: 'hh:mm',
// `p` is date-fns' localized time: it resolves each locale's own clock convention rather than fixing the
// US 12-hour one. Ten of the eleven shipped locales use a 24-hour clock, so `h:mm a` was wrong for them
// and the translated AM/PM marker only made a wrong convention read as deliberate. Greek keeps its
// 12-hour clock and its own `μ.μ.` marker. `p` is a date-fns extension, and still needs `{locale}`.
LOCAL_TIME_FORMAT: 'p',
Comment thread
shubham1206agra marked this conversation as resolved.
YEAR_MONTH_FORMAT: 'yyyyMM',
MONTH_FORMAT: 'MMMM',
WEEKDAY_TIME_FORMAT: 'eeee',
Expand Down
4 changes: 2 additions & 2 deletions src/components/AutoUpdateTime.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ type AutoUpdateTimeProps = {
};

function AutoUpdateTime({timezone}: AutoUpdateTimeProps) {
const {translate, getLocalDateFromDatetime} = useLocalize();
const {translate, getLocalDateFromDatetime, dateFnsLocale} = useLocalize();
const styles = useThemeStyles();

const [, setTick] = useState(0);
Expand All @@ -43,7 +43,7 @@ function AutoUpdateTime({timezone}: AutoUpdateTimeProps) {
<View style={[styles.w100, styles.detailsPageSectionContainer]}>
<MenuItemWithTopDescription
style={[styles.ph0]}
title={`${DateUtils.formatToLocalTime(translate, currentUserLocalTime)} ${timezoneName}`}
title={`${DateUtils.formatToLocalTime(currentUserLocalTime, dateFnsLocale)} ${timezoneName}`}
description={translate('detailsPage.localTime')}
interactive={false}
/>
Expand Down
2 changes: 1 addition & 1 deletion src/components/LocaleContextProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ function LocaleContextProvider({children}: LocaleContextProviderProps) {
const formatTravelDate: LocaleContextProps['formatTravelDate'] = (datetime) => {
const date = new Date(datetime);
const formattedDate = formatDate(date, CONST.DATE.MONTH_DAY_YEAR_ABBR_FORMAT, {locale: dateFnsLocale});
const formattedHour = DateUtils.formatTimeWithPeriod(translate, date);
const formattedHour = formatDate(date, CONST.DATE.LOCAL_TIME_FORMAT, {locale: dateFnsLocale});
const at = translateLocalize(currentLocale, 'common.conjunctionAt');
return `${formattedDate} ${at} ${formattedHour}`;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ type PerDiemFieldsProps = {

function PerDiemFields({perDiemCustomUnit, transaction, isReadOnly, didConfirm, transactionID, shouldDisplayFieldError, formError}: PerDiemFieldsProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const {translate, dateFnsLocale} = useLocalize();
const icons = useMemoizedLazyExpensifyIcons(['Stopwatch', 'CalendarSolid']);

const subRates = getSubratesFields(perDiemCustomUnit, transaction);
Expand Down Expand Up @@ -114,7 +114,7 @@ function PerDiemFields({perDiemCustomUnit, transaction, isReadOnly, didConfirm,
<View style={styles.dividerLine} />
<MenuItemWithTopDescription
shouldShowRightIcon={!isReadOnly}
title={getTimeForDisplay(transaction, translate)}
title={getTimeForDisplay(transaction, dateFnsLocale)}
description={translate('iou.time')}
style={[styles.moneyRequestMenuItem]}
titleStyle={styles.flex1}
Expand Down
5 changes: 3 additions & 2 deletions src/components/OnboardingHelpDropdownButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,11 @@ function OnboardingHelpDropdownButton({reportID, shouldUseNarrowLayout, shouldSh
{locale: dateFnsLocale},
)}`,
value: CONST.ONBOARDING_HELP.EVENT_TIME,
description: `${DateUtils.formatTimeInTimeZoneWithPeriod(translate, latestScheduledCall.eventTime, userTimezone)} - ${DateUtils.formatTimeInTimeZoneWithPeriod(
translate,
description: `${DateUtils.formatInTimeZoneWithFallback(latestScheduledCall.eventTime, userTimezone, CONST.DATE.LOCAL_TIME_FORMAT, {locale: dateFnsLocale})} - ${DateUtils.formatInTimeZoneWithFallback(
addMinutes(latestScheduledCall.eventTime, 30),
userTimezone,
CONST.DATE.LOCAL_TIME_FORMAT,
{locale: dateFnsLocale},
)} ${DateUtils.getZoneAbbreviation(new Date(latestScheduledCall.eventTime), userTimezone)}`,
descriptionTextStyle: [styles.themeTextColor, styles.ml2],
displayInDefaultIconColor: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ function ChronosOOOListActions({reportID, action}: ChronosOOOListActionsProps) {
: translate(
'chronos.oooEventSummaryPartialDay',
event.summary,
`${DateUtils.formatToLocalTime(translate, start)} - ${DateUtils.formatToLocalTime(translate, end)}`,
`${DateUtils.formatToLocalTime(start, dateFnsLocale)} - ${DateUtils.formatToLocalTime(end, dateFnsLocale)}`,
DateUtils.formatToLongDateWithWeekday(end, dateFnsLocale),
)}
</Text>
Expand Down
6 changes: 4 additions & 2 deletions src/components/TimeModalPicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ type TimeModalPickerProps = {

function TimeModalPicker({value, errorText, label, onInputChange = () => {}, ref}: TimeModalPickerProps) {
const styles = useThemeStyles();
const {translate} = useLocalize();
const {dateFnsLocale} = useLocalize();
const [isPickerVisible, setIsPickerVisible] = useState(false);
const currentTime = value ? DateUtils.getTime12HourWithTranslatedPeriod(translate, value) : undefined;
// The row shows a localized time, while `TimePicker` still reads `value` through `extractTime12Hour` — that one is
// the picker's English wire format, so rendering it here would put an AM/PM clock next to 24-hour times elsewhere.
const currentTime = value ? DateUtils.formatToLocalTime(value, dateFnsLocale) : undefined;

const hidePickerModal = () => {
setIsPickerVisible(false);
Expand Down
4 changes: 2 additions & 2 deletions src/languages/IntlStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ class IntlStore {
import('./en').then((module: DynamicModule<typeof en>) => {
this.cache.set(LOCALES.EN, flattenObject(extractModuleDefaultExport(module)));
}),
import('date-fns/locale/en-GB').then((module) => {
this.dateUtilsCache.set(LOCALES.EN, module.enGB);
import('date-fns/locale/en-US').then((module) => {
this.dateUtilsCache.set(LOCALES.EN, module.enUS);
}),
shouldPolyfillNumberFormat(LOCALES.EN) ? import('@formatjs/intl-numberformat/locale-data/en') : Promise.resolve(),
shouldPolyfillListFormat(LOCALES.EN) ? import('@formatjs/intl-listformat/locale-data/en') : Promise.resolve(),
Expand Down
Loading
Loading