Java Date Formatting in Portuguese: From SimpleDateFormat to java.time
From a Stack Overflow question about formatting dates in Brazilian Portuguese with SimpleDateFormat to the modern java.time API and a comparison with JS Temporal.
Java Date Formatting in Portuguese: From SimpleDateFormat to java.time
I asked a question on Stack Overflow in Portuguese about formatting dates in Brazilian Portuguese using Java. The question scored 13 — localization was (and still is) a real stumbling block for developers who need their apps to display “segunda-feira, 15 de março de 2026” instead of “Monday, March 15, 2026.”
The core problem hasn’t changed: you need locale-aware date formatting. But the tools we use for it are fundamentally different now.
The 2015 Approach: SimpleDateFormat
Back then, SimpleDateFormat was the go-to class for date formatting in Java. To get Portuguese output, you passed a Locale:
SimpleDateFormat sdf = new SimpleDateFormat(
"EEEE, dd 'de' MMMM 'de' yyyy",
new Locale("pt", "BR")
);
String formatted = sdf.format(new Date());
// "segunda-feira, 15 de março de 2026"
This worked, but SimpleDateFormat was a minefield:
- Not thread-safe. Sharing an instance across threads caused silent data corruption. I’ve seen production bugs where dates from one request leaked into another because someone cached a
SimpleDateFormatin a static field. - Mutable
Dateobjects.java.util.Datewas mutable, so passing a date to a method meant that method could modify your date. Defensive copying was everywhere. - Calendar gymnastics. Doing arithmetic — adding days, finding the first day of the month — required
Calendar, which was verbose, confusing, and also mutable. - Timezone confusion.
Datestored a timestamp but printed in the JVM’s default timezone.SimpleDateFormathad its own timezone setting. Getting consistent timezone behavior required careful configuration.
For something as simple as “show today’s date in Portuguese,” you had to dodge a surprising number of traps.
What Changed: java.time
Java 8 (2014) introduced the java.time package, inspired by Joda-Time. By 2026, it’s the only date/time API you should be using in Java:
LocalDate today = LocalDate.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(
"EEEE, dd 'de' MMMM 'de' yyyy",
new Locale("pt", "BR")
);
String formatted = today.format(formatter);
// "segunda-feira, 15 de março de 2026"
The code looks similar, but the underlying design is completely different:
- Immutable.
LocalDate,LocalDateTime,ZonedDateTime— all immutable. No defensive copying. No thread-safety issues. - Thread-safe formatters.
DateTimeFormatteris immutable and thread-safe. Cache it in a static field without worry. - Clear type system.
LocalDatehas no time.LocalTimehas no date.ZonedDateTimehas both plus a timezone. The type tells you what information is present. - Fluent arithmetic.
today.plusDays(7),today.withDayOfMonth(1),today.minusMonths(3)— readable and returns a new instance.
Built-in Localized Styles
You don’t even need custom patterns for common formats:
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL)
.withLocale(new Locale("pt", "BR"));
LocalDate.now().format(formatter);
// "segunda-feira, 29 de março de 2026"
The JDK knows the correct date format for Brazilian Portuguese. Let it handle the pattern.
Cross-Language Comparison: JavaScript Temporal
JavaScript went through its own date evolution. Intl.DateTimeFormat has handled localized formatting for years:
const date = new Date();
const formatted = new Intl.DateTimeFormat('pt-BR', {
weekday: 'long',
day: 'numeric',
month: 'long',
year: 'numeric',
}).format(date);
// "segunda-feira, 29 de março de 2026"
And the Temporal API, now available in modern browsers and runtimes, brings Java-like immutable date types to JavaScript:
const today = Temporal.Now.plainDateISO();
const formatted = today.toLocaleString('pt-BR', {
weekday: 'long',
day: 'numeric',
month: 'long',
year: 'numeric',
});
The pattern is converging: immutable date objects, clear type distinctions (date vs. time vs. datetime vs. zoned), and built-in locale-aware formatting. Java got there first with java.time, JavaScript followed with Temporal.
The Lesson
The original question was about a formatting pattern — a syntax problem. But the real issue was that Java’s date/time API was badly designed. SimpleDateFormat worked for the happy path and broke in every other scenario. The java.time API didn’t just fix formatting — it fixed the entire mental model around dates, times, and timezones.
When a platform redesigns a fundamental API, pay attention. The migration cost is real, but the bugs you’ll never write are worth it.
Related Posts
Java Date Formatting in Portuguese: From SimpleDateFormat to java.time
From a Stack Overflow question about formatting dates in Brazilian Portuguese with SimpleDateFormat to the modern java.time API and a comparison with JS Temporal.
Calculating Age in PHP: DateTime::diff Then and Now
From a 2015 Stack Overflow answer on calculating age with PHP DateTime to 2026 — the same approach still works, but Carbon and timezone awareness changed the game.
PHP Date and Weekend Check: From date("w") to DateTimeImmutable
From a 2015 Stack Overflow answer about checking if a date falls on a weekend in PHP to the modern era of DateTimeImmutable, Carbon, and locale-aware calendars.