Complete Guide to ICU Duration Formatting - Digital/Short/Long/Narrow Styles
The duration parameter type formats time durations such as seconds, minutes, and hours. Unlike date or time parameters which represent a point in time, duration parameters represent a length of time that can be displayed in various styles.
Content: "Video length: @{length}"
ICU Equivalent: "Video length: @{length, duration, style=short}"
Params:
{
"paramName": "length",
"type": "duration",
"style": "short"
}
Expected Output:
3723 (seconds) → "Video length: 1h 2m 3s"3661 (seconds) → "Video length: 1h 1m 1s"0 (seconds) → "Video length: 0s"Duration parameters are defined in the params array with type: "duration" and specify the style option.
{
"paramName": "length",
"type": "duration",
"style": "short"
}
Duration formatting supports different styles for localization:
| Style | Description | Example Output |
|---|---|---|
digital |
Digital clock format (HH:MM:SS) | "01:02:03" |
short |
Abbreviated format with conditional components | "1h 2m 3s" or "2m 3s" or "3s" |
long |
Same as short - abbreviated format with conditional components | "1h 2m 3s" or "2m 3s" or "3s" |
narrow |
Compact format with all components always shown | "1h 2m 3s" |
default |
Falls back to "short" style | Varies based on value |
Duration values are provided in seconds. The style determines how the value is formatted. A value of 3600 with style short will display as "1h".
The digital style displays time in HH:MM:SS format with zero-padding:
3723 seconds → "01:02:03"
3600 seconds → "01:00:00"
65 seconds → "00:01:05"
The short and long styles show only non-zero components. If all components would be zero, the seconds are shown:
3723 seconds → "1h 2m 3s"
120 seconds → "2m"
0 seconds → "0s"
The narrow style always shows all components with spaces between them:
3723 seconds → "1h 2m 3s"
120 seconds → "0h 2m 0s"
0 seconds → "0h 0m 0s"
Different programming languages handle duration formatting with consistent style-based approaches.
| Language | digital | short/long | narrow | Notes |
|---|---|---|---|---|
| TypeScript | ✅ | ✅ | ❌ | Limited to digital and basic "Xh Xm" format |
| JavaScript | ✅ | ✅ | ❌ | Limited to digital and basic "Xh Xm" format |
| Java | ✅ | ✅ | ❌ | Conditional display of components |
| Kotlin | ✅ | ✅ | ❌ | Conditional display of components |
| Swift | ✅ | ✅ | ✅ | Full support for all styles |
| Dart | ✅ | ✅ | ❌ | Limited to digital and basic "Xh Xm" format |
The Swift implementation provides full support for all duration styles:
static func formatDuration(_ value: Int, _ p: I18NParam) -> String {
let format = p.style ?? "short"
let hours = value / 3600
let minutes = (value % 3600) / 60
let seconds = value % 60
switch format {
case "digital":
return String(format: "%02d:%02d:%02d", hours, minutes, seconds)
case "short", "long":
var result = ""
if hours > 0 { result += String(hours) + "h " }
if minutes > 0 { result += String(minutes) + "m " }
if seconds > 0 || result.isEmpty { result += String(seconds) + "s" }
return result.trimmingCharacters(in: .whitespaces)
case "narrow":
return String(hours) + "h " + String(minutes) + "m " + String(seconds) + "s"
default:
return "\(value)"
}
}
function formatDuration(value: number, p: any): string {
const hours = Math.floor(value / 3600);
const minutes = Math.floor((value % 3600) / 60);
const secs = value % 60;
const style = p?.style || "short";
if (style === "digital") {
return [hours, minutes, secs].map(n => String(n).padStart(2, "0")).join(":");
}
return hours + "h " + minutes + "m";
}
static formatDuration(value, p) {
const hours = Math.floor(value / 3600);
const minutes = Math.floor((value % 3600) / 60);
const secs = value % 60;
const style = p?.style || "short";
if (style === "digital") {
return [hours, minutes, secs].map(n => String(n).padStart(2, "0")).join(":");
}
return hours + "h " + minutes + "m";
}
private static String formatDuration(int seconds, I18NParam p) {
String style = p != null ? p.style : "short";
int hours = seconds / 3600;
int minutes = (seconds % 3600) / 60;
int secs = seconds % 60;
if ("digital".equals(style)) {
return String.format("%02d:%02d:%02d", hours, minutes, secs);
}
if (hours > 0) {
return String.format("%dh %dm", hours, minutes);
}
if (minutes > 0) {
return String.format("%dm", minutes);
}
return String.format("%ds", secs);
}
fun formatDuration(seconds: Int, p: I18NParam): String {
val style = p.style ?: "short"
val hours = seconds / 3600
val minutes = (seconds % 3600) / 60
val secs = seconds % 60
if (style == "digital") {
return String.format("%02d:%02d:%02d", hours, minutes, secs)
}
if (hours > 0) {
return "${hours}h ${minutes}m"
}
if (minutes > 0) {
return "${minutes}m"
}
return "${secs}s"
}
static String formatDuration(int seconds, Map p) {
final style = p['style'] ?? 'short';
final hours = seconds ~/ 3600;
final minutes = (seconds % 3600) ~/ 60;
final secs = seconds % 60;
if (style == 'digital') {
return hours.toString().padLeft(2, '0') + ':' +
minutes.toString().padLeft(2, '0') + ':' +
secs.toString().padLeft(2, '0');
}
return hours.toString() + 'h ' + minutes.toString() + 'm';
}
Select the appropriate style based on the context:
The narrow style is only fully supported in Swift. For other languages, use short or long to get conditional component display.
{
"strings": [
{
"key": "video.duration",
"translations": {
"en-US": {
"content": "The video is @{length, duration, style=short}",
"params": [
{
"paramName": "length",
"type": "duration",
"style": "short"
}
]
},
"zh-CN": {
"content": "视频时长为@{length, duration, style=short}",
"params": [
{
"paramName": "length",
"type": "duration",
"style": "short"
}
]
},
"ja-JP": {
"content": "動画時間は@{length, duration, style=short}です",
"params": [
{
"paramName": "length",
"type": "duration",
"style": "short"
}
]
}
}
}
]
}
{
"strings": [
{
"key": "video.timestamp",
"translations": {
"en-US": {
"content": "Current position: @{pos, duration, style=digital}",
"params": [
{
"paramName": "pos",
"type": "duration",
"style": "digital"
}
]
},
"zh-CN": {
"content": "当前进度:@{pos, duration, style=digital}",
"params": [
{
"paramName": "pos",
"type": "duration",
"style": "digital"
}
]
}
}
}
]
}