---
name: format_iso8601
kind: function
lang: py
domain: core
version: "1.0.0"
purity: pure
signature: "format_iso8601(dt: datetime) -> str"
description: "Formatea un datetime a ISO 8601 UTC con milisegundos. Formato: yyyy-MM-ddTHH:mm:ss.SSSZ. Si naive asume UTC, si aware convierte a UTC."
tags: [datetime, iso8601, format, time, utc]
uses_functions: []
uses_types: []
returns: []
returns_optional: false
error_type: ""
imports: ["datetime"]
params:
  - name: dt
    desc: "datetime object (puede ser naive o aware)"
output: "string ISO 8601 UTC con milisegundos formato yyyy-MM-ddTHH:mm:ss.SSSZ"
tested: true
tests:
  - "datetime naive formateado como UTC"
  - "datetime con timezone convertido a UTC"
  - "datetime UTC sin conversion"
test_file_path: "python/functions/core/format_iso8601_test.py"
file_path: "python/functions/core/format_iso8601.py"
---

## Ejemplo

```python
from datetime import datetime, timezone, timedelta
from format_iso8601 import format_iso8601

# Naive (asume UTC)
s = format_iso8601(datetime(2026, 2, 21, 13, 20, 23, 147000))
# "2026-02-21T13:20:23.147Z"

# Con timezone +8
tz8 = timezone(timedelta(hours=8))
s = format_iso8601(datetime(2026, 2, 21, 21, 20, 23, 147000, tzinfo=tz8))
# "2026-02-21T13:20:23.147Z"
```

## Notas

Algoritmo:
1. Si naive: `dt.replace(tzinfo=timezone.utc)`.
2. Si aware: `dt.astimezone(timezone.utc)`.
3. `dt.isoformat(timespec="milliseconds").replace("+00:00", "Z")`.

Funcion pura. No hace I/O ni tiene efectos secundarios.
