Skip to content

Commit

Permalink
Switch to native Intl.DateTimeFormat
Browse files Browse the repository at this point in the history
  • Loading branch information
greentore committed Jul 24, 2023
1 parent 053b801 commit 7866a83
Show file tree
Hide file tree
Showing 11 changed files with 144 additions and 62 deletions.
9 changes: 0 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
"blurhash": "2.0.4",
"browser-encrypt-attachment": "0.3.0",
"classnames": "2.3.2",
"dateformat": "5.0.3",
"emojibase": "6.1.0",
"emojibase-data": "7.0.1",
"file-saver": "2.0.5",
Expand Down
44 changes: 0 additions & 44 deletions src/app/atoms/time/Time.jsx

This file was deleted.

36 changes: 36 additions & 0 deletions src/app/atoms/time/Time.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import React from 'react';

import { isInSameDay, DateTime } from '../../utils/time';

interface TimeProps {
timestamp: number;
fullTime?: boolean;
}

function Time({ timestamp, fullTime }: TimeProps) {
const date = new Date(timestamp);

const formattedFullTime = DateTime.full(date);
let formattedDate = formattedFullTime;

if (!fullTime) {
const compareDate = new Date();
const isToday = isInSameDay(date, compareDate);
compareDate.setDate(compareDate.getDate() - 1);
const isYesterday = isInSameDay(date, compareDate);

formattedDate = isToday || isYesterday ? DateTime.time(date) : DateTime.dateISO(date);
if (isYesterday) {
const yesterday = DateTime.relative(-1, 'day') ?? 'Yesterday';
formattedDate = `${yesterday}, ${formattedDate}`;
}
}

return (
<time dateTime={date.toISOString()} title={formattedFullTime}>
{formattedDate}
</time>
);
}

export default Time;
8 changes: 4 additions & 4 deletions src/app/organisms/room/RoomViewContent.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import React, {
import PropTypes from 'prop-types';
import './RoomViewContent.scss';

import dateFormat from 'dateformat';
import { twemojify } from '../../../util/twemojify';

import initMatrix from '../../../client/initMatrix';
import cons from '../../../client/state/cons';
import navigation from '../../../client/state/navigation';
import { openProfileViewer } from '../../../client/action/navigation';
import { diffMinutes, isInSameDay, Throttle } from '../../../util/common';
import { Throttle } from '../../../util/common';
import { diffMinutes, isInSameDay, DateTime } from '../../utils/time'
import { markAsRead } from '../../../client/action/notifications';

import Divider from '../../atoms/divider/Divider';
Expand Down Expand Up @@ -99,7 +99,7 @@ function RoomIntroContainer({ event, timeline }) {
name={room.name}
heading={twemojify(heading)}
desc={desc}
time={event ? `Created at ${dateFormat(event.getDate(), 'dd mmmm yyyy, hh:MM TT')}` : null}
time={event ? `Created on ${DateTime.full(event.getDate())}` : null}
/>
);
}
Expand Down Expand Up @@ -593,7 +593,7 @@ function RoomViewContent({ roomInputRef, eventId, roomTimeline }) {
}
const dayDivider = prevMEvent && !isInSameDay(mEvent.getDate(), prevMEvent.getDate());
if (dayDivider) {
tl.push(<Divider key={`divider-${mEvent.getId()}`} text={`${dateFormat(mEvent.getDate(), 'mmmm dd, yyyy')}`} />);
tl.push(<Divider key={`divider-${mEvent.getId()}`} text={`${DateTime.date(mEvent.getDate())}`} />);
itemCountIndex += 1;
}

Expand Down
6 changes: 3 additions & 3 deletions src/app/organisms/settings/DeviceManage.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React, { useState, useEffect } from 'react';
import './DeviceManage.scss';
import dateFormat from 'dateformat';

import initMatrix from '../../../client/initMatrix';
import { isCrossVerified } from '../../../util/matrixUtil';
import { DateTime } from '../../utils/time';
import { openReusableDialog, openEmojiVerification } from '../../../client/action/navigation';

import Text from '../../atoms/text/Text';
Expand Down Expand Up @@ -184,9 +184,9 @@ function DeviceManage() {
<Text variant="b3">
Last activity
<span style={{ color: 'var(--tc-surface-normal)' }}>
{dateFormat(new Date(lastTS), ' hh:MM TT, dd/mm/yyyy')}
{` ${DateTime.full(new Date(lastTS))}`}
</span>
{lastIP ? ` at ${lastIP}` : ''}
{lastIP ? ` from ${lastIP}` : ''}
</Text>
)}
{isCurrentDevice && (
Expand Down
12 changes: 11 additions & 1 deletion src/app/organisms/settings/Settings.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import settings from '../../../client/state/settings';
import navigation from '../../../client/state/navigation';
import {
toggleSystemTheme, toggleMarkdown, toggleMembershipEvents, toggleNickAvatarEvents,
toggleNotifications, toggleNotificationSounds,
toggleNotifications, toggleNotificationSounds, toggleTime12,
} from '../../../client/action/settings';
import { usePermission } from '../../hooks/usePermission';

Expand Down Expand Up @@ -113,6 +113,16 @@ function AppearanceSection() {
)}
content={<Text variant="b3">Hide nick and avatar change messages from room timeline.</Text>}
/>
<SettingTile
title="12-hour time"
options={(
<Toggle
isActive={settings.isTime12}
onToggle={() => { toggleTime12(); updateState({}); }}
/>
)}
content={<Text variant="b3">Show timestamps in 12-hour format.</Text>}
/>
</div>
</div>
);
Expand Down
67 changes: 67 additions & 0 deletions src/app/utils/time.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import cons from '../../client/state/cons';
import settings from '../../client/state/settings';

function capitalize(string: string) {
return string.charAt(0).toLocaleUpperCase() + string.slice(1);
}

const hourCycle = () => (settings.isTime12 ? 'h12' : 'h23');

let fullFormat: Intl.DateTimeFormat;
let dateFormat: Intl.DateTimeFormat;
let timeFormat: Intl.DateTimeFormat;
let relativeFormat: Intl.RelativeTimeFormat | undefined;

function initDateFormats() {
fullFormat = new Intl.DateTimeFormat('en', {
hourCycle: hourCycle(),
dateStyle: 'full',
timeStyle: 'short',
});

dateFormat = new Intl.DateTimeFormat('en', {
dateStyle: 'long',
});

timeFormat = new Intl.DateTimeFormat('en', {
hourCycle: hourCycle(),
hour: 'numeric',
minute: 'numeric',
});

relativeFormat = Intl.RelativeTimeFormat
? new Intl.RelativeTimeFormat('en', { numeric: 'auto' })
: undefined;
}
initDateFormats();

export class DateTime {
static full = (date: Date) => fullFormat.format(date);

static date = (date: Date) => dateFormat.format(date);

static time = (date: Date) => timeFormat.format(date);

static relative = (value: number, unit: Intl.RelativeTimeFormatUnit) =>
relativeFormat ? capitalize(relativeFormat.format(value, unit)) : undefined;

static dateISO = (date: Date) => date.toISOString().split('T')[0];
}

export function diffMinutes(dt2: Date, dt1: Date): number {
let diff = (dt2.getTime() - dt1.getTime()) / 1000;
diff /= 60;
return Math.abs(Math.round(diff));
}

export function isInSameDay(dt2: Date, dt1: Date): boolean {
return (
dt2.getFullYear() === dt1.getFullYear() &&
dt2.getMonth() === dt1.getMonth() &&
dt2.getDate() === dt1.getDate()
);
}

settings.on(cons.events.settings.TIME12_TOGGLED, () => {
initDateFormats();
});
6 changes: 6 additions & 0 deletions src/client/action/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,9 @@ export function toggleNotificationSounds() {
type: cons.actions.settings.TOGGLE_NOTIFICATION_SOUNDS,
});
}

export function toggleTime12() {
appDispatcher.dispatch({
type: cons.actions.settings.TOGGLE_TIME12,
});
}
2 changes: 2 additions & 0 deletions src/client/state/cons.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ const cons = {
TOGGLE_NICKAVATAR_EVENT: 'TOGGLE_NICKAVATAR_EVENT',
TOGGLE_NOTIFICATIONS: 'TOGGLE_NOTIFICATIONS',
TOGGLE_NOTIFICATION_SOUNDS: 'TOGGLE_NOTIFICATION_SOUNDS',
TOGGLE_TIME12: 'TOGGLE_TIME12',
},
},
events: {
Expand Down Expand Up @@ -150,6 +151,7 @@ const cons = {
NICKAVATAR_EVENTS_TOGGLED: 'NICKAVATAR_EVENTS_TOGGLED',
NOTIFICATIONS_TOGGLED: 'NOTIFICATIONS_TOGGLED',
NOTIFICATION_SOUNDS_TOGGLED: 'NOTIFICATION_SOUNDS_TOGGLED',
TIME12_TOGGLED: 'TIME12_TOGGLED',
},
},
};
Expand Down
15 changes: 15 additions & 0 deletions src/client/state/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class Settings extends EventEmitter {
this.hideNickAvatarEvents = this.getHideNickAvatarEvents();
this._showNotifications = this.getShowNotifications();
this.isNotificationSounds = this.getIsNotificationSounds();
this.isTime12 = this.getIsTime12();

this.darkModeQueryList = window.matchMedia('(prefers-color-scheme: dark)');

Expand Down Expand Up @@ -153,6 +154,15 @@ class Settings extends EventEmitter {
return settings.isNotificationSounds;
}

getIsTime12() {
if (typeof this.isTime12 === 'boolean') return this.isTime12;

const settings = getSettings();
if (settings === null) return false;
if (typeof settings.isTime12 === 'undefined') return false;
return settings.isTime12;
}

setter(action) {
const actions = {
[cons.actions.settings.TOGGLE_SYSTEM_THEME]: () => {
Expand Down Expand Up @@ -192,6 +202,11 @@ class Settings extends EventEmitter {
setSettings('isNotificationSounds', this.isNotificationSounds);
this.emit(cons.events.settings.NOTIFICATION_SOUNDS_TOGGLED, this.isNotificationSounds);
},
[cons.actions.settings.TOGGLE_TIME12]: () => {
this.isTime12 = !this.isTime12;
setSettings('isTime12', this.isTime12);
this.emit(cons.events.settings.TIME12_TOGGLED, this.isTime12);
},
};

actions[action.type]?.();
Expand Down

0 comments on commit 7866a83

Please sign in to comment.