export type TimestampFormatterOptions = {
/* If true, call the `Day.js` calendar function to get the date string to display (e.g. "Yesterday at 3:58 PM"). */
calendar?: boolean;
/* Object specifying date display formats for dates formatted with calendar extension. Active only if calendar prop enabled. */
calendarFormats?: Record<string, string>;
/* Overrides the default timestamp format if calendar is disabled. */
format?: string;
};Date and time formatting
This guide shows how to customize date/time formatting across SDK components.
SDK components displaying date & time
The following SDK components display date/time:
DateSeparator- separates message groups by dateEventComponent- component that renders system messages (message.type === 'system')Timestamp- component to display non-system message timestamp
Best Practices
- Prefer i18n-based formatting for app-wide consistency.
- Avoid mixing calendar and fixed formats within the same UI surface.
- Provide complete
calendarFormatsto avoid English fallbacks. - Keep custom formatters deterministic for predictable UI.
- Test formatting across locales and daylight-saving changes.
Format customization
The datetime format customization can be done on multiple levels:
- Component prop values
- Supply custom formatting function
- Format date via i18n
Override the component props defaults
All the mentioned components accept timestamp formatter props:
If calendar formatting is enabled, the dates are formatted with time-relative words ("yesterday at ...", "last ..."). The calendar strings can be further customized with calendarFormats object. The calendarFormats object has to cover all the formatting cases as shows the example below:
{
"lastDay": "[gestern um] LT",
"lastWeek": "[letzten] dddd [um] LT",
"nextDay": "[morgen um] LT",
"nextWeek": "dddd [um] LT",
"sameDay": "[heute um] LT",
"sameElse": "L"
}If any calendarFormats keys are missing, the underlying library falls back to hard-coded English equivalents.
If calendar formatting is enabled, the format prop would be ignored. So to apply the format string, the calendar has to be disabled (applies to DateSeparator and MessageTimestamp).
All the components can be overridden through Channel component context:
import {
Channel,
DateSeparatorProps,
DateSeparator,
EventComponentProps,
EventComponent,
MessageTimestampProps,
MessageTimestamp,
} from "stream-chat-react";
const CustomDateSeparator = (props: DateSeparatorProps) => (
<DateSeparator {...props} calendar={false} format={"YYYY"} /> // calendar is enabled by default
);
const CustomSystemMessage = (props: EventComponentProps) => (
<EventComponent {...props} format={"YYYY"} /> // calendar is disabled by default
);
const CustomMessageTimestamp = (props: MessageTimestampProps) => (
<MessageTimestamp
{...props}
calendar={false}
format={"YYYY-MM-DDTHH:mm:ss"}
/> // calendar is enabled by default
);
<Channel
DateSeparator={CustomDateSeparator}
MessageSystem={SystemMessage}
MessageTimestamp={CustomMessageTimestamp}
>
...
</Channel>;Custom formatting function
You can pass a custom formatting function to MessageList or VirtualizedMessageList via formatDate ((date: Date) => string). The Message component passes it to children via MessageComponentContext:
import { useMessageContext } from "stream-chat-react";
const CustomComponent = () => {
const { formatDate } = useMessageContext();
};By default, MessageTimestamp consumes it. That means formatDate only affects message timestamps; DateSeparator and EventComponent ignore it.
Date & time formatting with i18n service
Until now, datetime values could only be customized at the Channel level. Formatting via i18n enables SDK-wide configuration stored in translation JSON files. Advantages include:
- it is centralized
- it takes into consideration the locale out of the box
- allows per-string formatting (instead of per-component props)
- allows for high re-usability - apply the same configuration in multiple places via the same translation key
- allows for custom formatting logic
Change the default configuration
The default datetime formatting configuration is stored in the JSON translation files. The default translation keys are namespaced with prefix timestamp/ followed by the component name. For example, the message date formatting can be targeted via timestamp/MessageTimestamp, because the underlying component is called MessageTimestamp.
You can change the default configuration by passing an object to translationsForLanguage Streami18n option with all or some of the relevant translation keys:
import { Chat, Streami18n } from "stream-chat-react";
const i18n = new Streami18n({
language: "de",
translationsForLanguage: {
"timestamp/DateSeparator":
"{{ timestamp | timestampFormatter(calendar: false) }}",
"timestamp/MessageTimestamp":
'{{ timestamp | timestampFormatter(calendar: true; calendarFormats: {"lastDay": "[gestern um] LT", "lastWeek": "[letzten] dddd [um] LT", "nextDay": "[morgen um] LT", "nextWeek": "dddd [um] LT", "sameDay": "[heute um] LT", "sameElse": "L"}) }}',
},
});
const ChatApp = ({ chatClient, children }) => {
return (
<Chat client={chatClient} i18nInstance={i18n}>
{children}
</Chat>
);
};Understanding the formatting syntax
Once default prop values are nullified, you can override the formatting rules. Here’s an example for SystemMessage in German (JSON with escaped quotes):
"timestamp/SystemMessage": "{{ timestamp | timestampFormatter(calendar: true; calendarFormats: {\"lastDay\": \"[gestern um] LT\", \"lastWeek\": \"[letzten] dddd [um] LT\", \"nextDay\": \"[morgen um] LT\", \"nextWeek\": \"dddd [um] LT\", \"sameDay\": \"[heute um] LT\", \"sameElse\": \"L\"}) }}",Let's dissect the example:
- The curly brackets (
{{,}}) indicate the place where a value will be interpolated (inserted) into the string. timestampis the variable whose value is inserted- value separator
|signals the separation between the interpolated value and the formatting function name timestampFormatteris the name of the formatting function that is used to convert thetimestampvalue into desired formattimestampFormatteraccepts the same parameters as the React components (calendar,calendarFormats,format). Values can be scalars or objects (forcalendarFormats). Params are separated by;.
The described rules follow the formatting rules required by the i18n library used under the hood - i18next. You can learn more about the rules in the formatting section of the i18next documentation.
Custom datetime formatter functions
Besides overriding the configuration parameters, we can override the default timestampFormatter function by providing custom Streami18n instance:
import { Chat, Streami18n, useCreateChatClient } from "stream-chat-react";
const i18n = new Streami18n({
formatters: {
timestampFormatter: () => (val: string | Date) => {
return new Date(val).getTime() + "";
},
},
});
export const ChatApp = ({ apiKey, userId, userToken }) => {
const chatClient = useCreateChatClient({
apiKey,
tokenOrProvider: userToken,
userData: { id: userId },
});
return <Chat client={chatClient} i18nInstance={i18n}></Chat>;
};