v33.8.1

select option

useFormattedDate hook

Format dates as strings for display

Overview

The useFormattedDate hook provides a way for frontend developers to format dates and times as strings, rather than JSX elements. This is useful when you need an ink formatted date to use in places where react elements are not accepted.

While the FormattedDate component renders as a React element, useFormattedDate returns a formatting function that outputs a string. Both use the same underlying logic and support the same formats, but serve different use cases.

useFormattedDate is intended for internal Carta developers who want to format dates into user-friendly strings, with support for time zones and locale-aware formatting. Internally, useFormattedDate works exactly like FormattedDate, ensuring consistency across the product.

Best Practices

  • Prefer ISO-8601 strings: Always use ISO-8601 date strings for input. This format is unambiguous, widely supported, and ensures consistent parsing and formatting across all Carta applications.
  • Specify displayTimezone when consistency matters: If you need all users to see the same date and time regardless of their local settings, always provide a displayTimezone (e.g., 'America/New_York' or 'UTC').
  • Avoid legacy and ambiguous formats: While legacy formats like MM/DD/YYYY are supported for backward compatibility, avoid using them in new code to prevent confusion and parsing errors.
  • Use the right tool for the job: Use useFormattedDate for string output (logging, tooltips, etc.) and FormattedDate for rendering dates in the UI.

If you have additional questions or encounter issues, please reach out on the #ink channel.

Supported Input Types

The useFormattedDate hook supports multiple ISO 8601 formats as well as Date instances, moment objects, and a few legacy formats. If an unsupported value is provided, the hook will simply return an empty string.

Input ValueInput FormatSupportedOutput (format: condensedWithTime, displayTimezone: UTC)
2025-12-31T12:00:00.000+02:00ISO 8601YesDec 31, 2025, 02:00 PM UTC
2025-12-31T12:00:00.000ZISO 8601YesDec 31, 2025, 12:00 PM UTC
2025-12-31T12:00:00ZISO 8601YesDec 31, 2025, 12:00 PM UTC
2025-12-31T12:00ZISO 8601YesDec 31, 2025, 12:00 PM UTC
2025-12-31ISO 8601YesDec 31, 2025, 12:00 AM UTC
2025-12ISO 8601YesDec 1, 2025, 12:00 AM UTC
2025ISO 8601YesJan 1, 2025, 12:00 AM UTC
01/31/2025MM/DD/YYYYYesJan 31, 2025, 12:00 AM UTC
01/2025MM/YYYYYesJan 1, 2025, 12:00 AM UTC
January 1, 2023MMMM DD, YYYYNo"" (empty string)

When no date or time is provided, the hook defaults to first day of the month and the start of the day in UTC (i.e., 12:00 AM). The same happens when only a year is provided, defaulting to January 1st of that year.

Best Practice: Always prefer ISO-8601 strings for input to avoid ambiguity and ensure consistency.

Fractional Seconds Handling

useFormattedDate accepts up to 9 digits of fractional seconds in ISO-8601 input strings (e.g., 2025-12-31T12:00:00.123456789Z), in line with the full ISO 8601 specification.

However, it is important to note the following:

  • Inputs are truncated to the first 3 digits (milliseconds) for parsing. Precision beyond milliseconds (i.e., microseconds and nanoseconds) is discarded.
  • Output is always rounded to the nearest minute. Seconds and fractional seconds are not shown in the formatted string, regardless of input precision.

Formatting, Time Zones, and Locale Handling

At present, you cannot override the default locale or input timezone settings. All configuration is handled internally to promote consistency with FormattedDate.

By default, all dates provided are parsed as UTC and the output is formatted in the user's local timezone unless you provide a displayTimezone;

The user's local timezone is determined by their browser or system settings and based on the Intl.DateTimeFormat().resolvedOptions().timeZone method, which is widely supported in modern browsers.

You can update displayTimezone (and other options) per invocation of formatDate, but there is no way to configure persistent defaults at the hook level. Each call to formatDate requires all relevant options to be specified.

Future enhancements will allow setting user preferences or defaults when initializing the hook, reducing the need to pass options every time.

For now, all dates are formatted using the en-US locale, except for the i18n formats, which use en-GB. In the future the component will be expanded to allow developers to customize the locale and timezone settings.

Using useFormattedDate

useFormattedDate will return an object containing the formatDate function that can be used to format dates.

formatDate requires a config object as argument to work, the parameters it needs are:

  • value: the date value to format which needs to be in a supported format (see Supported Input Types).
  • format: the desired output format. The available formats are the same as those supported by the FormattedDate component, such as condensedWithTime, long, short, etc.
  • displayTimezone (optional): an IANA timezone string (e.g., America/New_York, UTC) to specify the timezone for formatting. If not provided, the user's local timezone is used.
  • enableDebug (optional): boolean to enable debugging mode, which returns additional metadata about the parsing and formatting process.

formatDate will return an object containing the formatted date string and an optional __meta field for debugging purposes.

Example Usage

With inferred timezone

import { useFormattedDate } from "@carta/ink";
const { formatDate } = useFormattedDate();
const result = formatDate({
value: "2025-12-31T12:00:00Z",
format: "condensedWithTime",
});
console.log(result.value);
// Dec 31, 2025, 7:00 AM EST (if user is in New York)
// Dec 31, 2025, 12:00 PM UTC (if user is in London)

With explicit timezone

import { useFormattedDate } from "@carta/ink";
const { formatDate } = useFormattedDate();
const result = formatDate({
value: "2025-12-31T12:00:00Z",
format: "condensedWithTime",
displayTimezone: "America/New_York",
});
console.log(result.value); // Dec 31, 2025, 7:00 AM EST

Types

formatDate config object

interface UseFormattedDateOptionsType {
value: Date | Moment | string;
format?: FormatOptions; // e.g. 'condensedWithTime', 'long', 'short', etc.
displayTimezone?: string; // IANA timezone, e.g. 'America/New_York'
enableDebug?: boolean; // If true, returns extra metadata
}

formatDate return value

interface UseFormattedDateResultType {
value: string; // The formatted date string
__meta?: any; // Optional metadata for debugging
isoDate?: string; // ISO representation of the parsed date
}

Debugging mode

If you encounter unexpected results or need to troubleshoot date parsing and formatting, you can enable debugging by passing enableDebug: true to formatDate. This will include a __meta field in the result object, containing detailed information about the parsing process, detected errors, and the type of input.

Example Usage

import { useFormattedDate } from "@carta/ink";
const { formatDate } = useFormattedDate();
const result = formatDate({
value: "2024-99-99", // Invalid date
format: "condensedWithTime",
enableDebug: true,
});
console.log(result.__meta);
// {
// dateTime: {
// errors: { month: 'Invalid month', day: 'Invalid day' },
// parsingType: 'ISO Date'
// }
// }

What You Can Debug

  • Parsing errors: Invalid month, day, hour, minute, or second values.
  • Formatting errors: Invalid or malformed dates or invalid output timezone names.
  • Parsing types: Whether the input was parsed as ISO, custom, or localized format.

Example of metadata errors

  • Invalid ISO date format:
    result.__meta.dateTime.errors.month; // 'Invalid month'
    result.__meta.dateTime.errors.day; // 'Invalid day'
    result.__meta.dateTime.parsingType; // 'ISO Date'
  • Invalid time in ISO string:
    result.__meta.dateTime.errors.hours; // 'Invalid hour'
    result.__meta.dateTime.errors.minutes; // 'Invalid minute'
    result.__meta.dateTime.errors.seconds; // 'Invalid second'
  • Invalid timezone:
    result.__meta.errors.invalidInstant; // 'Invalid input timezone'
    result.__meta.errors.invalidFormattedDate; // 'Invalid output timezone'

FAQ / Known Issues

Why does my date return an empty string?

If your input is not in a supported format (see Core Concepts), useFormattedDate will return an empty string. Only ISO-8601, Date objects, moment objects, and select legacy formats are supported.

Why does the formatted date look different for different users?

If you do not specify a displayTimezone, the date is formatted in the user's local timezone, which may vary based on their browser or system settings.

Can I set a default timezone or locale for all calls?

Not yet. All options must be provided per invocation of formatDate. Future releases may allow persistent defaults at the hook level.

Is there a way to format dates as JSX elements?

Yes, use the FormattedDate component for UI rendering.

Is this page helpful?