# 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 date
- `EventComponent` - 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 `calendarFormats` to 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:

1. Component prop values
2. Supply custom formatting function
3. Format date via i18n

### Override the component props defaults

All the mentioned components accept timestamp formatter props:

```ts
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;
};
```

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:

```json
{
  "lastDay": "[gestern um] LT",
  "lastWeek": "[letzten] dddd [um] LT",
  "nextDay": "[morgen um] LT",
  "nextWeek": "dddd [um] LT",
  "sameDay": "[heute um] LT",
  "sameElse": "L"
}
```

<admonition type="tip">

If any `calendarFormats` keys are missing, the underlying library falls back to hard-coded English equivalents.

</admonition>

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:

```tsx
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`:

```tsx
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:

```tsx
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):

```json
"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.
- `timestamp` is the variable whose value is inserted
- value separator `|` signals the separation between the interpolated value and the formatting function name
- `timestampFormatter` is the name of the formatting function that is used to convert the `timestamp` value into desired format
- `timestampFormatter` accepts the same parameters as the React components (`calendar`, `calendarFormats`, `format`). Values can be scalars or objects (for `calendarFormats`). Params are separated by `;`.

<admonition type="note">

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](https://www.i18next.com/translation-function/formatting#basic-usage).

</admonition>

#### Custom datetime formatter functions

Besides overriding the configuration parameters, we can override the default `timestampFormatter` function by providing custom `Streami18n` instance:

```tsx
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>;
};
```


---

This page was last updated at 2026-04-21T07:55:45.767Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react/v13/guides/date-time-formatting/](https://getstream.io/chat/docs/sdk/react/v13/guides/date-time-formatting/).