Streak that skips weekends
Dashy vault/Guides/Streak that skips weekends
Guides/Streak that skips weekends.md

A habit streak in Obsidian that skips weekends

Properties
blocks
statsheatmap
keys
days: weekdaysskip_field
needs dataview
checked on
Dashy 1.5.2

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

Three cards: workdays in a row, the same habit counted with weekends, and the best run of workdays; below them three months of days with the workdays in blue, weekends empty and a holiday week hatched
What you have at the end of step 3. The middle card is the same habit counted the plain way. From a demo vault.

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.

Diary/2026-09-14.md
---
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.

Diary/2026-08-03.md
---
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 Monday counts too.
  • WeekendsTick, untick or leave the box out. With days: weekdays Saturday 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.

Workdays.md
```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 sets vacation is skipped the same way. Works with days or 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.

Weekends only, not your own rest days

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.

Workdays.md
```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.

Workdays.md
```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.

With the Tracker plugin
```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() and currentStreak().
  • 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.
With Dataview, JavaScript queries turned on
```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.
DashyTrackerdataviewjs
Skip weekendsdays: weekdaysNot in the docsWrite it
Skip holidaysskip_fieldNot in the docsWrite it
Current streakcurrent_streak, from todaycurrentStreak(), from the newest noteThe loop above
Best streakstreak, same rulesmaxStreak(), weekends break itWrite it
What you installDashyTrackerDataview, 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
```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
```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
```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
```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:

  • days expects all or weekdays. Something else was written, weekday or workdays for example. The card falls back to all until you fix it.
  • at_least, at_most, days and skip_field only apply to agg: streak and agg: current_streak. The keys sit on a sum or count card, 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 vacation set.