Miksi Excel, SQL, Python ja JavaScript antavat eri viikkonumeron samalle päivälle

Lasket viikkonumeron Pythonissa, avaat saman päivän Excelissä, ja numerot eivät täsmää. Ajet SQL-kyselyn ja saat kolmannen tuloksen. Haet netistä ja löydät neljännen.

Tämä ei ole bugi. Se on suunnitteluvalinta, jonka jokainen työkalu tekee eri tavalla — ja useimmat eivät dokumentoi sitä tarpeeksi näkyvästi.

Käytössä on vähintään kaksi suurta viikkonumerointijärjestelmää, useita variaatioita kummankin sisällä, eikä ole mitään universaalia oletusta. Kun ymmärrät erot, ristiriitojen selvittäminen vie sekunteja. Ennen sitä ne ovat raivostuttavia.

Kaksi pääjärjestelmää

ISO 8601 (käytössä suurimmassa osassa Eurooppaa, kansainvälisessä liiketoiminnassa ja tieteellisissä yhteyksissä)

  • Viikot alkavat maanantaina ja päättyvät sunnuntaina
  • Viikko 1 on viikko, joka sisältää vuoden ensimmäisen torstain
  • Vuodessa on 52 tai 53 viikkoa
  • Viikkovuosi voi poiketa kalenterivuodesta rajapäivinä

USA-/”yksinkertainen” järjestelmä (käytössä Pohjois-Amerikassa ja monien taulukkotyökalujen oletuksena)

  • Viikot alkavat sunnuntaina ja päättyvät lauantaina (tai joskus maanantaista sunnuntaihin, riippuen lokalisaatiosta)
  • Viikko 1 on viikko, joka sisältää tammikuun 1. päivän
  • Tammikuun 1. päivä on aina viikolla 1 riippumatta viikonpäivästä
  • Vuoden lopun osittaiset viikot saavat korkeat numerot (52 tai 53), eikä niitä siirretä seuraavan vuoden viikoksi 1

Käytännön ero näkyy selvimmin joulukuun lopussa ja tammikuun alussa.

PäiväISO-viikkoUS-viikko (sunnuntai alku)
December 28, 2025Week 52, 2025Week 53, 2025
December 29, 2025Week 1, 2026Week 53, 2025
December 30, 2025Week 1, 2026Week 53, 2025
December 31, 2025Week 1, 2026Week 53, 2025
January 1, 2026Week 1, 2026Week 1, 2026
January 2, 2026Week 1, 2026Week 1, 2026
January 3, 2026Week 1, 2026Week 1, 2026
January 4, 2026Week 1, 2026Week 2, 2026

29.–31.12.2025 ovat ISO-järjestelmässä viikolla 1 vuonna 2026 — koska kyseisen viikon torstai (1.1.) on vuonna 2026. US-järjestelmä pitää ne viikkona 53 vuonna 2025.

Excel: WEEKNUM vs ISOWEEKNUM

Excelissä on kaksi erillistä funktiota, mikä on selkeämpää kuin useimmissa työkaluissa.

WEEKNUM(date, [return_type]) — US-tyylinen, viikonalun voi määrittää

return_type-argumentti määrittää, mikä viikonpäivä aloittaa viikon:

return_typeViikko alkaa
1 (oletus)sunnuntai
2maanantai
11maanantai
12tiistai
13keskiviikko
14torstai
15perjantai
16lauantai
17sunnuntai
21maanantai (ISO 8601)

return_type = 21 saa WEEKNUM-funktion käyttäytymään ISO-tyylisesti — mutta tämä on heikosti dokumentoitu ja monilta käyttäjiltä jää huomaamatta.

ISOWEEKNUM(date) — ISO 8601, aina maanantai alku, torstaisääntö

Tämä lisättiin Excel 2013:ssa. Se palauttaa oikean ISO-viikkonumeron ja on yksiselitteinen.

=ISOWEEKNUM("2025-12-31")   → 1    (viikko 1 vuonna 2026)
=WEEKNUM("2025-12-31", 1)   → 53   (viikko 53 vuonna 2025, sunnuntai alku)
=WEEKNUM("2025-12-31", 2)   → 53   (viikko 53 vuonna 2025, maanantai alku)
=WEEKNUM("2025-12-31", 21)  → 1    (ISO-yhteensopiva, sama kuin ISOWEEKNUM)

Yleinen virhe: WEEKNUM-funktion käyttäminen oletusasetuksilla, kun vertaillaan ISO-järjestelmään. Numerot täsmäävät suurimman osan vuodesta, mutta eroavat hiljaa vuoden vaihteessa.

Google Sheets: samat funktiot, samat sudenkuopat

Google Sheetsissä on sekä WEEKNUM että ISOWEEKNUM, ja niiden käyttäytyminen on sama kuin Excelissä. Oletus-WEEKNUM on US-tyylinen, viikko alkaa sunnuntaina. ISOWEEKNUM on ISO 8601.

Yksi ero: Google Sheets on johdonmukaisempi ISO-viikkovuoden kanssa, kun käytät ISOWEEKNUM-funktion rinnalla YEAR-funktiota. Jos kirjoitat =YEAR("2025-12-31"), saat 2025, mutta ISO-viikko kuuluu vuoteen 2026. Ei ole yhtä sisäänrakennettua funktiota, joka palauttaisi ISO-viikkovuoden — se pitää laskea:

=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)))

Tämä on pitkä. Jos teet Sheetsissä paljon viikkovuosi-logiikkaa, on usein siistimpää viedä data Pythoniin tai SQL:ään.

Python: isocalendar() on ISO, mutta strftime('%W') ei ole

Pythonin datetime-moduuli tarjoaa kaksi eri lähestymistapaa.

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

from datetime import date

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

Huomaa, että palautettu vuosi on ISO-viikkovuosi (2026), ei kalenterivuosi (2025). Tämä on oikein ja tärkeää — jos tarvitset viikon “vuoden” raportointiin, käytä iso_year-arvoa, ei d.year-arvoa.

strftime('%W') ja strftime('%U') — US-tyylinen, eri viikonalut

d.strftime('%W')   # Viikkonumero, maanantai viikon ensimmäinen päivä → '52'
d.strftime('%U')   # Viikkonumero, sunnuntai viikon ensimmäinen päivä → '52'
d.strftime('%V')   # ISO-viikkonumero → '01'
d.strftime('%G')   # ISO-viikkovuosi → '2026'

Yhdistelmä %V / %G on ISO-oikea. %W / %U ovat US-tyylisiä ja eroavat ISO:sta vuoden vaihteessa.

Yleinen virhe: d.strftime('%W')-funktion käyttäminen viikkonumeroon, kun muut järjestelmät käyttävät ISO:ta. Se toimii 48+ viikkoa vuodesta ja alkaa sitten hiljaa poiketa joulukuussa ja tammikuussa.

# Väärin ISO-vertailuun — vuoden raja antaa ristiriidan
week = int(d.strftime('%W'))

# Oikein ISO:lle
iso_year, iso_week, _ = d.isocalendar()

JavaScript: ei sisäänrakennettua — laske itse

JavaScriptin Date-oliolla ei ole sisäänrakennettua viikkonumerometodia. Date.getDay() palauttaa 0 (sunnuntai) – 6 (lauantai). Viikkonumero pitää laskea itse tai käyttää kirjastoa kuten date-fns tai dayjs.

ISO-viikon manuaalinen laskenta:

function isoWeek(date) {
  const d = new Date(date)
  d.setHours(0, 0, 0, 0)
  // Thursday in current week decides the year
  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

date-fns:n käyttö:

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

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

Yleinen virhe: Kirjoittaa yksinkertainen Math.ceil(dayOfYear / 7) ja kutsua sitä viikkonumeroksi. Se ei vastaa ISO- eikä US-standardia — se on täysin eri (ja väärä) järjestelmä.

SQL: riippuu tietokannasta

Jokainen iso tietokanta käsittelee viikkonumerot hieman eri tavalla.

PostgreSQL — ISO oletuksena

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

PostgreSQL:n EXTRACT(week ...) noudattaa ISO 8601:ä. Viikkovuoden saa isoyear-kentästä.

MySQL / MariaDB — useita tiloja

-- 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

MySQL:n mode-argumentti on kriittinen ja siinä on 8 vaihtoehtoa (0–7). Mode 3 on ISO. Oletus (mode 0) on US-tyylinen. Tämä on yleinen bugien lähde, kun vaihdetaan tietokantamoottoria.

SQL Server — ei ISO oletuksena

-- 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)

SQL Serverin oletus DATEPART(week, ...) on US-tyylinen. isowk on ISO-versio. Jos teet raportteja, joita verrataan eurooppalaisiin järjestelmiin, käytä aina isowk.

SQLite — ei natiivia viikkofunktiota

SQLite:ssa ei ole WEEKNUM- tai EXTRACT(week ...)-funktiota. Käytetään strftime:a:

-- '%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

ISO-kiertotie etsii viikon torstain ja laskee sen perusteella. Se on oikein, mutta ei ilmeinen.

Pika-taulukko

TyökaluISO-viikkoUS-viikkoHuomiot
ExcelISOWEEKNUM() tai WEEKNUM(d, 21)WEEKNUM() oletusISOWEEKNUM lisättiin 2013
Google SheetsISOWEEKNUM()WEEKNUM() oletusSama kuin Excel
Pythondate.isocalendar()[1] tai %V%W (ma) / %U (su)Käytä %G ISO-viikkovuodelle
JavaScriptManuaalisesti tai date-fns getISOWeek()ManuaalisestiEi natiivia viikkonumeroa
PostgreSQLEXTRACT(week ...)Ei sisäänrakennettuaISO oletuksena
MySQLWEEK(d, 3)WEEK(d) tai WEEK(d, 0)Mode 3 = ISO
SQL ServerDATEPART(isowk, d)DATEPART(week, d)Oletus on US
SQLiteKiertotie vaaditaanstrftime('%W', d)Ei natiivia tukea

Näin vältät ristiriidat käytännössä

Valitse yksi järjestelmä ja pakota se kaikkialle. ISO on yleensä parempi oletus uusille järjestelmille — se on kansainvälisesti standardoitu ja se, mitä useimmat modernit kirjastot toteuttavat.

Tallenna aina ISO-viikkovuosi viikkonumeron rinnalle. Viikko 1 vuonna 2026 ja viikko 1 vuonna 2025 ovat eri viikkoja. Sarake, jossa on pelkkä 1, on epäselvä ilman vuotta.

Tarkista vuoden vaihteen tapaukset erikseen. Päivät 28.–31.12. ja 1.–3.1. ovat ne, joissa erot syntyvät. Testaa putkesi päivillä tältä väliltä ennen käyttöönottoa.

Jos epäröit, tallenna ja vertaa kokonaisia päivämääriä. Viikkonumerot ovat näyttöä ja raportointia varten, eivät ensisijaisia avaimia tai liitoksia varten. Jos liität dataa järjestelmien välillä viikkonumerolla, muunna ensin kanoniseen päivään (viikon maanantai).

Käytä ISO-viikkonumerolaskuria tarkistaaksesi oikean ISO-viikkonumeron mille tahansa päivälle, mukaan lukien koko vuoden kalenterinäkymä.