---
name: duration_stats
kind: function
lang: go
domain: datascience
version: "1.0.0"
purity: pure
signature: "func DurationStatsFrom(durations []int64) DurationStats"
description: "Calcula estadisticas descriptivas (N, media, P50/P90/P99) de un slice de duraciones en milisegundos. Ordena una copia local sin mutar el input. Retorna DurationStats{} para slice vacio."
tags: [statistics, duration, percentile, metrics, int64]
uses_functions:
  - percentile_int64_go_datascience
uses_types:
  - DurationStats_go_datascience
returns:
  - DurationStats_go_datascience
returns_optional: false
error_type: ""
imports:
  - sort
params:
  - name: durations
    desc: "Slice de duraciones en milisegundos. No necesita estar ordenado; se ordena internamente sobre una copia."
output: "DurationStats con N, AvgMs, P50Ms, P90Ms y P99Ms calculados. DurationStats{} si el slice esta vacio."
tested: true
tests:
  - "slice vacio retorna estadisticas cero"
  - "un solo elemento produce estadisticas identicas"
  - "cinco elementos calcula media y percentiles correctos"
  - "input original no se muta"
  - "diez elementos p90 usa idx truncado"
test_file_path: "functions/datascience/duration_stats_test.go"
file_path: "functions/datascience/duration_stats.go"
source_repo: "https://github.com/egutierrez/fn_registry/apps/kanban"
source_license: "private"
source_file: "apps/kanban/backend/metrics.go"
---

## Ejemplo

```go
durations := []int64{50, 10, 30, 40, 20}
stats := DurationStatsFrom(durations)
// stats.N     = 5
// stats.AvgMs = 30
// stats.P50Ms = 30
// stats.P90Ms = 50
// stats.P99Ms = 50
```

## Notas

Ordena una copia con `sort.Slice` para no mutar el slice original.
Compone `Percentile` (`percentile_int64_go_datascience`) para los calculos de P50/P90/P99.
Extraido y generalizado desde `apps/kanban/backend/metrics.go:113-130`.
