Description
Actually, Hugo (the SSG) is not capable to get a week number!
It’s ‘under consideration’!
However, Go language provides the IsoWeek() method.
Find the week number serves a purpose, whilst uncommon, is certainly useful.
As instance, a weekly newsletter :)
I’m going to show you two differents functions:
- by
getIsoWeek - or with
getWeekNumber
getisoweek
First, create a partial template: /func/getIsoWeek:
{{- $date := time.AsTime . -}}
{{- $weekday := $date.Weekday }}
{{/* 1. Normalize Weekday (Mon=1 ... Sun=7) */}}
{{- $isoDay := cond (eq $weekday 0) 7 (int $weekday) -}}
{{/* 2. Find Thursday (ISO Week belongs to the year of its Thursday) */}}
{{- $offset := sub 4 $isoDay -}}
{{- $thursday := $date.AddDate 0 0 $offset -}}
{{/* 3. Calculate Week Number */}}
{{- $isoYear := $thursday.Year -}}
{{- $isoWeek := add (div (sub $thursday.YearDay 1) 7) 1 -}}
{{/* 4. Return the data */}}
{{- $str := dict "week" (printf "%02d" $isoWeek) "year" (printf "%04d" $isoYear) -}}
{{- $data := dict "week" $isoWeek "year" $isoYear "str" $str -}}
{{- return $data -}}
The call:
{{- partial "func/getisoweek" .Date -}}
Or any other varible using Time, such as now.
⇒ Remark about getIsoWeek :
- if I want values as
int, I call$data.weekand$data.year - if I want values as
str, I call$data.str.weekand$data.str.year
Personnaly, I’ve too created another partial template, called utils/formatIsoDate.
The code as follows:
{{- $data := partial "func/getIsoWeek" . -}}
{{- $s := printf "w%s-y%s" $data.str.week $data.str.year -}}
{{- return $s -}}
I can call it either from the default archetypes, or anywhere into the templates or shortcodes, as I wish, such as:
{{ partial "utils/formatIsoDate" .Date }} ou {{ partial "utils/formatIsoDate" now }}.
getweeknumber
This second method for finding the week number is a little trickier!
This time, I have two main files.
⇒ The first function, func/splitNameYMO, is designed to “break down” a standardized date (YYYY-MM-DD) into the corresponding day, month, and year, and return a dictionary.
{{- $str := split . "-" -}}
{{- $d = (int (index $str 2)) -}}
{{- $m = (int (index $str 1)) -}}
{{- $y = (int (index $str 0)) -}}
{{- return (dict "day" $d "month" $m "year" $y) -}}
I created this file because I use it frequently throughout my code…
⇒ The second file is the main function, named func/getWeekNumber
{{- $date := "" -}}
{{- $tz := site.Params.timeZone -}}
{{- $week := 0 -}}
{{ $type := printf "%T" . }}
{{ if eq $type "string" }}
{{- $data := partial "func/splitNameYMO" . }}
{{- $date = time (printf "%04d-%02d-%02d" $data.year $data.month $data.day) $tz -}}
{{ else }}
{{- $date = time . $tz -}}
{{- end -}}
{{/* Calcul 'doy: day of the year', 'dow: day of the week' */}}
{{- $doy := $date.YearDay -}}
{{- $dow := int $date.Weekday -}}
{{- $year := $date.Year -}}
{{/* calcul week number */}}
{{- $week = div (add (sub $doy $dow) 10) 7 -}}
{{- if eq $dow 0 -}}
{{- $week = sub $week 1 -}}
{{- end -}}
{{- $str := dict "week" (printf "%02d" $week) "year" (printf "%04d" $year) -}}
{{- $data := dict "week" $week "year" $year "str" $str -}}
{{- return $data -}}
Explanations:
-
First, I need to determine the type of the value I’m injecting into the file call — whether it’s a
stringor something else, in this case a timestamp — keep in mind that Hugo doesn’t know how to declare a value type for a timestamp, but in the repository, it is defined asTime.time. -
Next, I determine which day of the year the date (
$doy) corresponds to, which day of the week it falls on ($dow), and finally the year, of course. -
Calcul of the week number is known:
- subtract the day of the week from the day of the year
- add
10 - and divide the result by
7 - and finally, if the day of the week is a Sunday, I subtract
1from the week number found — this applies to Hugo, where weeks start on Sunday
Voila!