A habit streak in Obsidian that skips weekends
days: weekdaysskip_fieldSome habits are for workdays only. A plain streak then resets every Monday, because Saturday and Sunday were empty. One key fixes that: Friday joins up with Monday. A second one keeps a holiday week from ending the run.
1Tick the habit on workdays
One checkbox property for the habit, ticked in the daily note on the days you did it. Here it is deep_work.
---
deep_work: true
---
## 2026-09-14
For a day off, add a second property to that day's note. Any value counts except false, 0 or an empty one.
---
deep_work: false
vacation: true
---
## 2026-08-03
2026-09-14The note's name is its date. Anything after the date is fine:2026-09-14 Mondaycounts too.- WeekendsTick, untick or leave the box out. With
days: weekdaysSaturday and Sunday do not count either way. vacation: trueThe day needs a note to carry it. A workday with no note at all still ends the run.
2Count workdays in a row
Make a note for the tracker, say Workdays.md, and paste this block. It is the top row of the picture above.
```stats
columns: 3
items:
- { label: Workdays in a row, source: Diary, field: deep_work, agg: current_streak, days: weekdays, skip_field: vacation, unit: days, icon: 💻 }
- { label: With weekends, source: Diary, field: deep_work, agg: current_streak, unit: days }
- { label: Best run of workdays, source: Diary, field: deep_work, agg: streak, days: weekdays, skip_field: vacation, unit: days }
```
days: weekdaysSaturday and Sunday neither break the run nor add to it. Friday and Monday count as two days in a row.skip_field: vacationA day whose note setsvacationis skipped the same way. Works withdaysor on its own.current_streakThe run you are on now, counted back from today. Today never breaks it: until you tick today, it counts up to yesterday.streakThe longest run on record, by the same rules.
The middle card has neither key. It is there to show the difference: here, on a Monday it reads 1 at most, because Sunday was empty. Keep it next to the first card, or drop it.
days knows two values, all and weekdays. For a Monday, Wednesday and Friday plan, mark the other days with a property and name it in skip_field, as in the variations below.
3See the weeks
Paste this under the cards. Ticked days are blue, weekends stay empty, and a holiday is hatched.
```heatmap
source: Diary
field: deep_work
skip_field: vacation
color: blue
range: 91d
title: Deep work
```
range: 91d is the last thirteen weeks, ending today. Leave it out for a grid per calendar year. Hover a hatched cell and its tooltip says "day off".
The whole note
Both blocks in one piece, ready to paste into an empty note.
```stats
columns: 3
items:
- { label: Workdays in a row, source: Diary, field: deep_work, agg: current_streak, days: weekdays, skip_field: vacation, unit: days, icon: 💻 }
- { label: With weekends, source: Diary, field: deep_work, agg: current_streak, unit: days }
- { label: Best run of workdays, source: Diary, field: deep_work, agg: streak, days: weekdays, skip_field: vacation, unit: days }
```
```heatmap
source: Diary
field: deep_work
skip_field: vacation
color: blue
range: 91d
title: Deep work
```
The same streak with Tracker or dataviewjs
Both read the same deep_work: true notes.
```tracker
searchType: frontmatter
searchTarget: deep_work
folder: Diary
summary:
template: "Longest streak: {{maxStreak()}} days\nCurrent streak: {{currentStreak()}} days"
```
- Tracker counts every calendar day. A Saturday with no tick, or no note, breaks
maxStreak()andcurrentStreak(). - Tracker's docs list no setting to skip weekends or holidays.
- The current streak counts back from the newest note Tracker finds, not from today, unless you set
endDate.
```dataviewjs
const done = new Set(dv.pages('"Diary"')
.where(p => p.file.day && p.deep_work === true)
.map(p => p.file.day.toISODate())
.array());
let day = dv.luxon.DateTime.now().startOf("day");
if (!done.has(day.toISODate())) day = day.minus({ days: 1 });
let run = 0;
for (;;) {
if (day.weekday >= 6) { day = day.minus({ days: 1 }); continue; }
if (!done.has(day.toISODate())) break;
run++;
day = day.minus({ days: 1 });
}
dv.paragraph(`Workdays in a row: ${run}`);
```
- Needs Enable JavaScript queries in Dataview's settings. It is off by default.
- This is the current run only. Holidays, the best run and the grid are more code.
| Dashy | Tracker | dataviewjs | |
|---|---|---|---|
| Skip weekends | days: weekdays | Not in the docs | Write it |
| Skip holidays | skip_field | Not in the docs | Write it |
| Current streak | current_streak, from today | currentStreak(), from the newest note | The loop above |
| Best streak | streak, same rules | maxStreak(), weekends break it | Write it |
| What you install | Dashy | Tracker | Dataview, JavaScript queries on |
Variations
Holidays and sick days
skip_field takes one property. Give it a value per reason: day_off: vacation, day_off: sick.
```stats
items:
- label: Workdays in a row
source: Diary
field: deep_work
agg: current_streak
days: weekdays
skip_field: day_off
```
Your own rest days
Gym on Monday, Wednesday and Friday: mark the other days rest: true and leave days out.
```stats
items:
- label: Gym days in a row
source: Diary
field: gym
agg: current_streak
skip_field: rest
```
A number, on workdays
A workday counts once it reaches the bar. Weekends still do not count.
```stats
items:
- label: 8000+ steps, workdays in a row
source: Diary
field: steps
agg: current_streak
at_least: 8000
days: weekdays
```
A goal for the run
The same keys work on a progress bar: twenty workdays in a row, and how far along you are.
```progress
items:
- label: Twenty workdays in a row
source: Diary
field: deep_work
agg: current_streak
days: weekdays
goal: 20
```
If a block shows an error
A block that cannot do what you asked says so, inside the note. The ones you are likely to see here:
daysexpectsallorweekdays. Something else was written,weekdayorworkdaysfor example. The card falls back toalluntil you fix it.at_least,at_most,daysandskip_fieldonly apply toagg: streakandagg: current_streak. The keys sit on asumorcountcard, where they mean nothing.- The run is shorter than you expected. A workday with no note, or with the box unticked, ends it. Holidays need a note with
vacationset.
Related guides

Counts, streaks and a year of days from daily note checkboxes.

Each in its own colour, on one year of days.

A number summed by week, with a goal line.
Dashy is in Obsidian's community plugins. Search for Dashy, install, enable, then paste the note above.