Internationalization API (`Intl`), sorting and aggregate functions
Internationalization API (`Intl`), sorting and aggregate functions
Internationalization API (Intl)
JavaScript provides the Internationalization API, usually called Intl.
Think of it as a translator—but not for words. Instead, it formats things like:
- Numbers
- Dates
- Times
- Currencies
One part of this API is Intl.DateTimeFormat.
What is Intl.DateTimeFormat?
Intl.DateTimeFormat is a JavaScript class that formats Date objects according to a user's:
- Language
- Country
- Regional preferences
It doesn't change the actual date. It only changes how the date is displayed.
Syntax
new Intl.DateTimeFormat(locales?, options?)
locales
The locales argument tells JavaScript to format the date according to a particular country or language.
Examples:
"en-US" // United States
"en-GB" // United Kingdom
"fr-FR" // France
If you don't care which locale is used, pass undefined.
new Intl.DateTimeFormat(undefined);
This tells JavaScript:
"Use the user's browser or operating system locale."
First, create a formatter
Before you can format dates, you need to create a formatter.
const formatter = new Intl.DateTimeFormat(undefined, {
dateStyle: "long",
timeStyle: "short",
});
You only create the formatter once, then you can reuse it for as many dates as you want.
Formatting a date
Suppose you have this date:
2026-07-27T13:30:45.123Z
First, convert it into a JavaScript Date object.
const date = new Date("2026-07-27T13:30:45.123Z");
Then use the formatter.
formatter.format(date);
The output depends on the user's locale, but it could look something like:
July 27, 2026 at 2:30 PM
Intl.NumberFormat
Background
Intl.NumberFormat formats numbers into locale-aware strings. It automatically applies the correct formatting rules for the selected locale, including thousands separators, decimal separators, currency symbols, percentages, measurement units, scientific notation, and compact number notation.
Syntax
const formatter = new Intl.NumberFormat(locales, options);
formatter.format(number);
Parameters
locales
Specifies the language or region whose formatting rules should be used.
"en-US"
"en-NG"
"fr-FR"
undefined // Uses the user's browser locale
options
Controls how the number should be formatted.
Common options include:
style : "decimal" (default), "currency", "percent", or "unit"
currency : Currency code such as "NGN", "USD", "EUR"
currencyDisplay: How the currency should appear: "symbol" (default), "narrowSymbol", "code", or "name"
notation: "standard" (default), "scientific", "engineering", or "compact"
compactDisplay :"short" (default, e.g. 2.5M) or "long" (e.g. 2.5 million)
minimumFractionDigits : Minimum number of decimal places to display maximumFractionDigits : Maximum number of decimal places to display roundingMode : Controls how values are rounded. Examples include "trunc", "ceil", "floor", "expand", "halfExpand", and "halfEven"
Common Uses
Currency Formatting
const formatter = new Intl.NumberFormat("en-NG", {
style: "currency",
currency: "NGN",
});
formatter.format(1250000);
Output:
₦1,250,000.00
Compact Number Formatting
Compact notation is commonly used in dashboards, analytics, and reporting applications.
const formatter = new Intl.NumberFormat("en-NG", {
notation: "compact",
});
formatter.format(2500000);
Output:
2.5M
Controlling Decimal Precision
const formatter = new Intl.NumberFormat("en-NG", {
maximumFractionDigits: 2,
});
Useful when displaying financial values or percentages that require consistent precision.
Summary
Intl.NumberFormat is commonly used for:
- Currency formatting (
₦1,250,000) - Percentages (
25%) - Measurement units (
120 km/h,50 MB) - Compact numbers (
2.5M,18K)
Intl.RelativeTimeFormat
Background
Intl.RelativeTimeFormat converts a time difference into a natural human-readable phrase. Instead of displaying an exact date or time, it displays relative values such as:
- Yesterday, 5 minutes ago, In 2 hours, Next week. This is commonly used in notifications, messaging applications, activity feeds, and dashboards.
Syntax
const rtf = new Intl.RelativeTimeFormat(locales, options);
rtf.format(value, unit);
value
A number representing the time difference. Negative values represent the past.Positive values represent the future.
unit
The unit of time.
"second","minute", "hour","day","week","month","quarter","year"
options
numeric: "always" displays exact values (e.g. "1 day ago"). "auto" uses natural phrases where possible (e.g. "yesterday").
style: "long" (default), "short", or "narrow"
Example
const rtf = new Intl.RelativeTimeFormat("en", {
numeric: "auto",
});
rtf.format(-1, "day");
Output:
yesterday
Another example:
rtf.format(5, "minute");
Output:
in 5 minutes
Summary
Intl.RelativeTimeFormat is commonly used for:
- Notifications, Chat applications, Activity feeds, Audit logs
- Social media timestamps
Using more detailed formatting options
Instead of using dateStyle and timeStyle, you can choose exactly which parts of the date you want to display.
const formatter = new Intl.DateTimeFormat("en-US", {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
});
This gives you more control over how the date is displayed.
Why create a formatter?
One advantage of Intl.DateTimeFormat is that you create the formatter once and reuse it whenever you need it.
formatter.format(new Date());
formatter.format(new Date("2026-10-01"));
formatter.format(new Date("2027-01-15"));
This is cleaner than creating a new formatter every time you want to format a date.
Using toLocaleString()
You can also use toLocaleString().
Instead of creating a formatter, you call it directly on a Date object.
First, create a Date.
const date = new Date("2026-07-27T13:30:45.123Z");
Then call:
date.toLocaleString(locales, options);
It accepts the same locales and options as Intl.DateTimeFormat.
Example:
date.toLocaleString("en-GB", {
dateStyle: "long",
timeStyle: "short",
});
Which one should you use?
Use Intl.DateTimeFormat if you're formatting many dates because you can reuse the formatter.
Use toLocaleString() if you're formatting just one date.
Sorting Arrays
The .sort() method sorts the elements of an array.
Syntax
array.sort(compareFunction?)
The compareFunction is optional.
If you don't provide one, JavaScript converts the values to strings and sorts them alphabetically.
Example:
["Orange", "Banana", "Apple"].sort();
Result:
["Apple", "Banana", "Orange"];
If you want JavaScript to sort differently, provide your own comparison function.
Sorting strings
When sorting strings, localeCompare() is preferred because it handles alphabetical ordering correctly across different languages and locales.
For an array of objects:
students.sort((a, b) => a.name.localeCompare(b.name));
For an array of strings:
array.sort((a, b) => a.localeCompare(b));
Sorting numbers
For numbers, always provide a comparison function.
Ascending
numbers.sort((a, b) => a - b);
Descending
numbers.sort((a, b) => b - a);
Without a comparison function, JavaScript compares numbers as strings.
For example:
[100, 20, 3].sort();
does not sort numerically because JavaScript compares:
"100"
"20"
"3"
instead of the actual numbers.
Prisma groupBy()
groupBy() groups rows that have the same value in one or more fields, then performs aggregate calculations for each group separately.
Syntax
await prisma.<model>.groupBy({
by: [],
where: {},
_sum: {},
_count: {},
_avg: {},
_min: {},
_max: {},
orderBy: {},
having: {},
take: 10,
skip: 0,
});
How groupBy() works
Let's look at a simple example.
await prisma.sale.groupBy({
by: ["itemName"],
});
This tells Prisma:
Group all rows that have the same
itemName.
Think of it as a two-step process.
Step 1
Group the rows using the fields inside by.
Step 2
Run the aggregate calculations (_sum, _count, _avg, _min, _max) for each group.
The by field decides how the rows are grouped, while the aggregate functions decide what information should be calculated for each group.
What does groupBy() return?
groupBy() returns an array of objects.
Why?
Because there can be many groups, and each group becomes one object in the returned array.
Example:
[
{
itemName: "Rice",
_sum: {
quantity: 12,
},
},
{
itemName: "Beans",
_sum: {
quantity: 8,
},
},
];
groupBy() vs aggregate()
Both perform calculations, but they answer different questions.
groupBy()
Returns an array because it summarizes each group separately.
aggregate()
Returns a single object because it summarizes all matching records together.
Example:
await prisma.sale.aggregate({
_sum: {
quantity: true,
},
});
Result:
{
_sum: {
quantity: 20,
},
}
Key takeaway
bydecides how the rows are grouped.- Aggregate functions (
_sum,_count,_avg,_min,_max) decide what calculations are performed for each group. groupBy()returns an array of grouped summaries.aggregate()returns one summary object for all matching records.
Comments (0)
No comments yet. Be the first to share your thoughts.