Per què Excel, SQL, Python i JavaScript donen números de setmana diferents per a la mateixa data

Calcules el número de setmana a Python, després obres la mateixa data a Excel i no coincideix. Fas una consulta SQL i obtens un tercer resultat. Busques per internet i en trobes un quart.

Això no és un error. És una decisió de disseny que cada eina implementa d’una manera diferent — i moltes no ho documenten amb prou visibilitat.

Hi ha com a mínim dos sistemes principals de numeració de setmanes d’ús habitual, diverses variants dins de cada sistema i cap “per defecte” universal. Un cop entens les diferències, depurar discrepàncies és qüestió de segons. Fins aleshores, desespera.

Els dos sistemes principals

ISO 8601 (utilitzat a la major part d’Europa, en negocis internacionals i en contextos científics)

  • Les setmanes van de dilluns a diumenge
  • La setmana 1 és la setmana que conté el primer dijous de l’any
  • Un any té 52 o 53 setmanes
  • L’any de la setmana (week year) pot diferir de l’any del calendari als límits

Sistema US / simple (utilitzat a l’Amèrica del Nord i com a valor per defecte de molts fulls de càlcul)

  • Les setmanes van de diumenge a dissabte (o de vegades de dilluns a diumenge, segons la configuració regional)
  • La setmana 1 és la setmana que conté l’1 de gener
  • L’1 de gener sempre és a la setmana 1, independentment del dia de la setmana
  • Les setmanes parcials de final d’any reben números alts (52 o 53), no es reassignen a l’any següent

La diferència pràctica es nota sobretot a finals de desembre i principis de gener.

DataSetmana ISOSetmana US (comença diumenge)
28 de desembre de 2025Setmana 52, 2025Setmana 53, 2025
29 de desembre de 2025Setmana 1, 2026Setmana 53, 2025
30 de desembre de 2025Setmana 1, 2026Setmana 53, 2025
31 de desembre de 2025Setmana 1, 2026Setmana 53, 2025
1 de gener de 2026Setmana 1, 2026Setmana 1, 2026
2 de gener de 2026Setmana 1, 2026Setmana 1, 2026
3 de gener de 2026Setmana 1, 2026Setmana 1, 2026
4 de gener de 2026Setmana 1, 2026Setmana 2, 2026

El 29–31 de desembre de 2025 cauen a la setmana 1 ISO de 2026 — perquè el dijous d’aquella setmana (1 de gener) és a 2026. El sistema US els manté a la setmana 53 de 2025.

Excel: WEEKNUM vs ISOWEEKNUM

Excel té dues funcions diferents, cosa que és més clara que en moltes altres eines.

WEEKNUM(date, [return_type]) — estil US, amb dia d’inici configurable

L’argument return_type controla quin dia comença la setmana:

return_typeLa setmana comença
1 (per defecte)Diumenge
2Dilluns
11Dilluns
12Dimarts
13Dimecres
14Dijous
15Divendres
16Dissabte
17Diumenge
21Dilluns (ISO 8601)

return_type = 21 fa que WEEKNUM es comporti com ISO — però està mal documentat i la majoria d’usuaris ni saben que existeix.

ISOWEEKNUM(date) — ISO 8601, sempre dilluns com a inici, regla del dijous

Es va afegir a Excel 2013. Retorna el número de setmana ISO correcte i és inequívoc.

=ISOWEEKNUM("2025-12-31")   → 1    (setmana 1 de 2026)
=WEEKNUM("2025-12-31", 1)   → 53   (setmana 53 de 2025, comença diumenge)
=WEEKNUM("2025-12-31", 2)   → 53   (setmana 53 de 2025, comença dilluns)
=WEEKNUM("2025-12-31", 21)  → 1    (compatible amb ISO, igual que ISOWEEKNUM)

Error habitual: utilitzar WEEKNUM amb els arguments per defecte quan compares amb un sistema basat en ISO. Coincidiran la major part de l’any, però divergiran silenciosament prop del final d’any.

Google Sheets: mateixes funcions, mateixes advertències

Google Sheets té WEEKNUM i ISOWEEKNUM amb el mateix comportament que Excel. WEEKNUM per defecte és estil US (comença diumenge). ISOWEEKNUM és ISO 8601.

Una diferència: Google Sheets és més consistent quan retornes l’any ISO amb ISOWEEKNUM al costat de YEAR. Si escrius =YEAR("2025-12-31") obtens 2025, però la setmana ISO pertany a 2026. No hi ha una funció integrada única que retorni l’any de setmana ISO — l’has de calcular:

=IF(ISOWEEKNUM(A1) > 50, IF(MONTH(A1) = 1, YEAR(A1) - 1, YEAR(A1)),
   IF(ISOWEEKNUM(A1) < 3, IF(MONTH(A1) = 12, YEAR(A1) + 1, YEAR(A1)),
   YEAR(A1)))

Això és llarg. Si treballes seriosament amb setmana-any a Sheets, sovint és més net exportar a Python o SQL.

Python: isocalendar() és ISO, però strftime('%W') no

El mòdul datetime de Python t’ofereix dues vies diferents.

date.isocalendar() — ISO 8601, retorna (year, week, weekday)

from datetime import date

d = date(2025, 12, 31)
d.isocalendar()
# IsoCalendarDate(year=2026, week=1, weekday=3)

Fixa’t que l’any retornat és l’any ISO de la setmana (2026), no l’any del calendari (2025). És correcte i important: si has d’etiquetar la setmana, utilitza iso_year i no d.year.

strftime('%W') i strftime('%U') — estil US, amb diferents inicis de setmana

d.strftime('%W')   # Número de setmana, dilluns com a primer dia → '52'
d.strftime('%U')   # Número de setmana, diumenge com a primer dia → '52'
d.strftime('%V')   # Número de setmana ISO → '01'
d.strftime('%G')   # Any de setmana ISO → '2026'

La combinació %V / %G és correcta per a ISO. Les directives %W / %U són estil US i no coincidiran amb ISO als límits d’any.

Error habitual: fer servir d.strftime('%W') per obtenir números de setmana quan altres sistemes usen ISO. Coincidiran 48+ setmanes de l’any, i després divergiran a desembre i gener.

# Incorrecte per comparar amb ISO — fallarà al límit d’any
week = int(d.strftime('%W'))

# Correcte per ISO
iso_year, iso_week, _ = d.isocalendar()

JavaScript: no hi ha funció integrada, t’ho has de calcular

L’objecte Date de JavaScript no té cap mètode nadiu per a número de setmana. Date.getDay() retorna 0 (diumenge) fins a 6 (dissabte). Has de calcular-ho manualment o usar una llibreria com date-fns o dayjs.

Càlcul manual de setmana ISO:

function isoWeek(date) {
  const d = new Date(date)
  d.setHours(0, 0, 0, 0)
  // El dijous de la setmana actual decideix l’any
  d.setDate(d.getDate() + 3 - (d.getDay() + 6) % 7)
  const jan4 = new Date(d.getFullYear(), 0, 4)
  return 1 + Math.round(((d - jan4) / 86400000 - 3 + (jan4.getDay() + 6) % 7) / 7)
}

function isoWeekYear(date) {
  const d = new Date(date)
  d.setDate(d.getDate() + 3 - (d.getDay() + 6) % 7)
  return d.getFullYear()
}

isoWeek(new Date('2025-12-31'))      // 1
isoWeekYear(new Date('2025-12-31'))  // 2026

Amb date-fns:

import { getISOWeek, getISOWeekYear } from 'date-fns'

getISOWeek(new Date('2025-12-31'))      // 1
getISOWeekYear(new Date('2025-12-31'))  // 2026

Error habitual: fer un càlcul simple tipus Math.ceil(dayOfYear / 7) i dir-ne “número de setmana”. Això no dona resultats ni ISO ni US — és un altre sistema diferent (i equivocat).

SQL: depèn de la base de dades

Cada base de dades important gestiona els números de setmana d’una manera diferent.

PostgreSQL — ISO per defecte

SELECT EXTRACT(week FROM DATE '2025-12-31');
-- Returns 1 (ISO week)

SELECT DATE_PART('week', DATE '2025-12-31');
-- Returns 1 (same, ISO)

-- Get ISO week year
SELECT EXTRACT(isoyear FROM DATE '2025-12-31');
-- Returns 2026

EXTRACT(week ...) a PostgreSQL segueix ISO 8601. L’any de setmana està disponible amb isoyear.

MySQL / MariaDB — múltiples modes

-- Mode 3 is ISO 8601 (Monday start, week 1 has Thursday)
SELECT WEEK('2025-12-31', 3);   -- 1

-- Mode 0 (default) is US-style, Sunday start
SELECT WEEK('2025-12-31', 0);   -- 53
SELECT WEEK('2025-12-31');      -- 53 (default mode 0)

-- YEARWEEK returns combined year+week
SELECT YEARWEEK('2025-12-31', 3);  -- 202601

L’argument de mode a MySQL és crític i té 8 opcions (0–7). El mode 3 és ISO. El valor per defecte (mode 0) és estil US. Això és una font típica d’errors quan canvies de motor de base de dades.

SQL Server — no és ISO per defecte

-- Default DATEPART(week, ...) is not ISO
SELECT DATEPART(week, '2025-12-31');   -- 53

-- ISO week: use isowk or iso_week
SELECT DATEPART(isowk, '2025-12-31');  -- 1
SELECT DATEPART(iso_week, '2025-12-31');  -- 1 (same)

El DATEPART(week, ...) per defecte a SQL Server és estil US. L’alias isowk és la versió ISO. Si fas informes que han de quadrar amb sistemes europeus, utilitza sempre isowk.

SQLite — sense funció nativa de setmanes

SQLite no té WEEKNUM ni EXTRACT(week ...). Es fa servir strftime:

-- '%W' is Monday-start, US-style
SELECT strftime('%W', '2025-12-31');   -- 52

-- ISO week requires a workaround
SELECT (strftime('%j', date('2025-12-31', '-3 days', 'weekday 4')) - 1) / 7 + 1;
-- 1

El “workaround” ISO busca el dijous de la setmana i compta des d’allà. És correcte, però no és obvi.

Una chuleta ràpida

EinaSetmana ISOSetmana USNotes
ExcelISOWEEKNUM() o WEEKNUM(d, 21)WEEKNUM() per defecteISOWEEKNUM afegit el 2013
Google SheetsISOWEEKNUM()WEEKNUM() per defecteIgual que Excel
Pythondate.isocalendar()[1] o %V%W (dl) / %U (dg)Usa %G per a l’any ISO
JavaScriptManual o date-fns getISOWeek()ManualNo hi ha número de setmana nadiu
PostgreSQLEXTRACT(week ...)No integratISO per defecte
MySQLWEEK(d, 3)WEEK(d) o WEEK(d, 0)Mode 3 = ISO
SQL ServerDATEPART(isowk, d)DATEPART(week, d)Per defecte és US
SQLiteCal workaroundstrftime('%W', d)Sense suport nadiu

Com evitar discrepàncies a la pràctica

Tria un sistema i imposa’l arreu. Per a sistemes nous, ISO sol ser el millor per defecte: és estàndard internacional i és el que implementen moltes llibreries modernes.

Emmagatzema sempre l’any ISO de la setmana junt amb el número de setmana. La setmana 1 de 2026 i la setmana 1 de 2025 no són la mateixa setmana. Un camp que només guarda 1 és ambigu si no hi ha any.

Comprova explícitament els casos de límit d’any. Els dies 28–31 de desembre i 1–3 de gener és on apareixen les discrepàncies. Prova el teu pipeline amb dates d’aquest rang abans de desplegar.

Si tens dubtes, guarda i compara dates completes. Els números de setmana serveixen per a visualització i informes, no per a claus primàries o joins. Si estàs fent joins entre sistemes per número de setmana, converteix abans a una data canònica (el dilluns de la setmana).

Utilitza el calculador de número de setmana ISO per verificar el número de setmana ISO correcte de qualsevol data, inclosa la vista de calendari de tot l’any.