Write a program that keeps track of the number of consecutive days it has been run.

The day resets at midnight (the local time of the computer on which the program is run).

If there is a day that the program is not run, the counter is reset to zero.

Every time the program is run, the counter should go up by one day if it is the first time the program is run that day. This means that the first time the program is run, it should say, "You have a 1 day streak!"

The output of the program is in the form: You have a [streak_length] day streak!

You are allowed to store data externally or modify the source code––your choice.

This is , so shortest code in bytes wins!

  • \$\begingroup\$ Does it have to be local time? Or can it just be any time zone? \$\endgroup\$
    – Riker
    Feb 3, 2017 at 22:34
  • \$\begingroup\$ @EasterlyIrk, the day resets at midnight local time. \$\endgroup\$
    – Daniel
    Feb 3, 2017 at 22:35
  • \$\begingroup\$ So it has to be local from where the computer is? Or at least waht timezone the comptuer is on. It can't use UTC regardless? \$\endgroup\$
    – Riker
    Feb 3, 2017 at 22:39
  • \$\begingroup\$ @EasterlyIrk, it has to be the time zone of the computer \$\endgroup\$
    – Daniel
    Feb 3, 2017 at 22:40
  • \$\begingroup\$ Ah okay. Thanks for clarifying. \$\endgroup\$
    – Riker
    Feb 3, 2017 at 22:40

6 Answers 6


Bash, 92, 90, 82 bytes


grep `date -d-1day -I` h||>h
date -I>>h
echo You have a `uniq h|wc -l` day streak!


  • Truncate file, instead of removing it, -8 bytes;
  • Replaced -daystart with ! -newermt to save 2 bytes.

How It Works !

Each time you launch it will append a line with the current date to the file h, e.g:


It will then use uniq to filter out duplicates (i.e. multiple launches, within the same day), and count the lines to get the streak length.

uniq h|wc -l

To reset a streak, it will grep for 'yesterday' in h, and truncate it if not found.

grep `date -d-1day -I` h||>h

Bash, 102 bytes

find ! -newerat 0-1day -delete
touch -a a
echo You have a $((1+(`stat -c %X-%Y a`)/86400)) day streak!

Warning, do not run in any folder you care about. It deletes any file not accessed in the last day in the working directory.

Uses a file a to store data, using the accessed/modified timestamps.


Goruby, 85 Bytes

Run with the interpreter flag -rdate.

op t.ts,?w
dw{c+=1;t=t.p;Fil.f t.ts}
s"You have a #{c} day streak!"

It works by storing a new file for each day on which it's invoked, then counts the number of consecutive files backwards to obtain the length of the streak. It doesn't ever delete files, so it will, eventually, after a very, very, very, very, very long time, fill your hard drive, a handful of bytes at a time.

Here's an ungolfed version of it:

streak, current_date = 0, Date.today
open(current_date.to_s, 'w')
while File.file?(current_date.to_s)
    streak += 1
    current_date = current_date.prev_day;
puts "You have a #{streak} day streak!"

Python 3, 213 bytes

import time

Bash + coreutils, 120 97 bytes

read d n<f;c=`date -d0 +%s`;echo $c $[c>d?c>d+86399?n=1:++n:n]>f;echo You have a $n day streak!

The bash line above has 95 bytes in it.

There's a second file called f that just contains a single character:


(The program writes to f.)

So I think the total number of bytes should be scored as 97 (95 bytes for the contents of the bash file, 1 byte for the contents of the external file, and 1 byte because 1 file other than the program is used). This is based on Counting bytes for multi-file programs.

Note: Thanks to @orlp for pointing out that an earlier answer to this that I posted was nonsense; I had misread the problem completely. (It was posted as a different answer, which I've deleted.)


PowerShell, 95 bytes

(date -f 'd')>>z
gc z|gu|%{$c=(1,++$c)[($d=date $_)-eq$n]
"You have a $c day streak!"

Try it online!


I start by writing the current date (in short date format) out to a file (named z). >> works as usual; appends, but creates if it doesn't exist.

Next, I read the contents of the file line by line with Get-Content (gc), pipe through Get-Unique (gu) since there could be multiple entries from the same date, then pipe through ForEach-Object (%).

In the loop, I create a 2 element array with the value 0 in the first element, and the current value of $c (+1) in the second element. Using ++$c allows me to avoid wrapping something like $c+1 in parentheses.

Then I index into the two element array with a boolean comparison, which will get coalesced to 0 for $false or 1 for $true. Within the comparison, I'm assigning to $d a [datetime] object created from the date read from the current line in the file. That object gets compared to $n, which on the first run hasn't been assigned yet, so it will never match, and $c will be initialized to 1, since the value of the indexing is being assigned to $c.

Next, $n is populated with the next expected date, by adding 1 to the current datetime object. The key here is that 1D means it's a [decimal] literal. For some reason when you add integer numbers to a [datetime], it's interpreted as ticks, but when you add floating point numbers, they are interpreted as days. So this populates $n for the next iteration.

The effect is that the counter gets reset every time the current date doesn't match the "next" date (which is the previous date plus 1 day).

Finally the message is output.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.