Copilot with Kotlin: Create a list of months in 3 letter format
Video: Copilot with Kotlin: Create a list of months in 3 letter format by Taught by Celeste AI - AI Coding Coach
Kotlin: List of Months in 3-Letter Format
Month.values().map { it.getDisplayName(TextStyle.SHORT, Locale.ENGLISH).uppercase() }. Get all 12 months, format each as a 3-letter abbreviation, uppercase. The locale-aware way.
A small puzzle: produce ["JAN", "FEB", "MAR", ..., "DEC"]. The naive approach hardcodes the strings; the correct approach uses java.time.Month so it's locale-aware.
The Copilot prompt
import java.time.Month
import java.time.format.TextStyle
import java.util.Locale
// Generate a list of months in 3-letter uppercase format
fun main() {
Copilot generates:
fun main() {
val months = Month.values()
.map { it.getDisplayName(TextStyle.SHORT, Locale.ENGLISH).uppercase() }
println(months)
// [JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC]
}
Walkthrough
1. Month.values(). Returns Array<Month> — the 12 enum values in order (JANUARY=1, ..., DECEMBER=12). It's an array, but the standard collection operations work.
2. .map { ... }. Transform each Month to a String. Since Array's map returns List<T>, we get List<String>.
3. getDisplayName(TextStyle.SHORT, Locale.ENGLISH). Returns "Jan", "Feb", etc. for English. Locale.JAPANESE returns "1月", "2月", etc.
4. .uppercase(). Capitalize. "Jan".uppercase() → "JAN".
For locales where the short name is already uppercase (or is non-letter), uppercase() is a no-op.
Locales
val french = Month.JANUARY.getDisplayName(TextStyle.SHORT, Locale.FRENCH)
// "janv." (with period)
val spanish = Month.JANUARY.getDisplayName(TextStyle.SHORT, Locale.forLanguageTag("es"))
// "ene."
val japanese = Month.JANUARY.getDisplayName(TextStyle.SHORT, Locale.JAPANESE)
// "1月"
Different locales, different conventions. For "JAN, FEB, ..." specifically, you want English. For "show months in the user's language," use Locale.getDefault() or a Compose locale.
TextStyle options
TextStyle.FULL— "January"TextStyle.SHORT— "Jan"TextStyle.NARROW— "J" (single letter; not always unique — Jan/Jun/Jul all are "J" in some locales)
Plus FULL_STANDALONE, SHORT_STANDALONE, NARROW_STANDALONE for languages where the standalone form differs (Russian, Polish, etc.).
Hardcoded alternative
val months = listOf("JAN", "FEB", "MAR", "APR", "MAY", "JUN",
"JUL", "AUG", "SEP", "OCT", "NOV", "DEC")
Works. Same output. Brittle: - Wrong for non-English UIs. - Have to update if you change the locale. - One typo and you have a silent bug.
For "this is always uppercase English," the hardcoded version is fine. For anything user-facing, use the API.
Variations
// Lowercase
val lower = Month.values().map { it.getDisplayName(TextStyle.SHORT, Locale.ENGLISH).lowercase() }
// [jan, feb, mar, ...]
// Full names
val full = Month.values().map { it.getDisplayName(TextStyle.FULL, Locale.ENGLISH) }
// [January, February, March, ...]
// Single-letter
val narrow = Month.values().map { it.getDisplayName(TextStyle.NARROW, Locale.ENGLISH) }
// [J, F, M, A, M, J, J, A, S, O, N, D] — note J/M repeated
// As "01", "02", ...
val numbers = Month.values().map { it.value.toString().padStart(2, '0') }
// [01, 02, 03, ..., 12]
Month.value returns the 1-12 integer. padStart(2, '0') pads with leading zero.
Building a month picker
val months = Month.values().map { month ->
val short = month.getDisplayName(TextStyle.SHORT, Locale.ENGLISH).uppercase()
val full = month.getDisplayName(TextStyle.FULL, Locale.ENGLISH)
Pair(month.value, "$short ($full)")
}
months.forEach { (num, name) -> println("$num: $name") }
// 1: JAN (January)
// 2: FEB (February)
// ...
A pair of (number, label) for dropdown UIs. Adapt to whatever format your widget needs.
Edge case: case-insensitive locales
In Turkish (Locale.forLanguageTag("tr")), the lowercase of "I" is "ı" (without dot), and the uppercase of "i" is "İ" (with dot). For non-locale-sensitive uppercase, use Locale.ROOT:
month.getDisplayName(TextStyle.SHORT, Locale.ROOT).uppercase(Locale.ROOT)
Locale.ROOT is the locale-neutral default. Safer for "computer-readable" values like keys.
Common mistakes
Hardcoding for one locale. Breaks for international users.
Forgetting to call uppercase(). "Jan", "Feb" → getDisplayName returns title case. Add .uppercase() for "JAN", "FEB".
Forgetting Locale. getDisplayName(TextStyle.SHORT) doesn't compile — Locale is required. Pick Locale.ENGLISH, Locale.ROOT, or the user's locale.
Confusing Month with LocalDate. Month is just the enum (no year). LocalDate.of(2024, Month.JANUARY, 15).month would extract the Month from a date.
Using Locale.getDefault() for "computer" output. The user's locale might be Turkish; "I" might lowercase to "ı". For user-facing display, default is fine; for keys/identifiers, use Locale.ROOT or Locale.ENGLISH.
What's next
Episode 37: Calculate age from a birthday. Period.between(birthday, today).years — the modern way.
Recap
Month.values().map { it.getDisplayName(TextStyle.SHORT, Locale.ENGLISH).uppercase() } for ["JAN", "FEB", ..., "DEC"]. Locale changes language; TextStyle changes length (FULL, SHORT, NARROW). For locale-neutral output, Locale.ROOT. Hardcoded listOf("JAN", ...) works for English-only contexts but is brittle. Month.value for the 1-12 number; padStart(2, '0') for "01", "02", etc.
Next episode: age calculation.