Originally created to shift the sleep times of my 28-hour days to find the right schedule that worked for me. But you can adjust the numbers to display any regular sleep schedule that fits evenly in a week.

It's also got an hourly world clock. And, if you host it from a web server, it'll show sunrise and sunset.1

picture of the sleepshift calendar

To use it

  1. Throw these files on a web server: sleepshift.js, sleepshift.css

  2. Slap this code in your web page:

    In the header:

    <link rel="stylesheet" type="text/css" href="sleepshift.css">
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js"></script>
    <script type="text/javascript" src="sleepshift.js"></script>

    In the body, where you want it displayed:

    <div id="sleepshift"></div>

    In the body, at the very bottom:

    <script type="text/javascript">

With that, your table will show the same sleep times as the xkcd 28-hour day comic, with no extras.

xkcd comic 320 about 28-hour days

Tweaking the sleep hours

You can add values to drawMyCal() to change the length and shift the times of your days.

SleepShift.drawMyCal(totalhours, wakehours, offset)
The total hours in your day. Not necessarily 24. Reasonable day lengths that fit evenly in a normal 168 hour week are: 12, 14, 21, 24, and 28.
Number of hours in your day that you want to be awake.
The week starts at 00:00 Monday (cell 0). Adjust the offset to the hour on -Sun or +Mon when you first wake up during the week. Examples:
  • To start your week at midnight Sunday, use 0.
  • To start your week at 8 a.m. on Monday, use 8.
  • To start your week at 7 p.m. on Sunday, use -5.

A normal person's week ;-)

SleepShift.drawMyCal(24, 16, 7);

The default with no values is the same as:

SleepShift.drawMyCal(28, 20, -6);

Showing more stuff

To customize it further, you can use the init() function before running drawMyCal().


  title: "My crazy week",
  sleepcolor: "777",
  mytimezonename: "Eastern",
  tzhash: {
    "Central":     -7,
    "Kristina":     1,
    "+00:30 Ravi":  5
  cellstyles: {
    "workout": ["6af",[37,91,149]],
    "my-work": ["6fd",[0,164,165,166,167]]


Property Format Default value
title string "My 28-hour days (with world clock)"
mytimezonename string ""
sleepcolor string - "0x[0x]0x[0x]0x[0x]" "87a"
tzhash object - { "time zone name": signed-integer offset, ... } {}
cellstyles object - { "name": ["color", [list of cells]], ... } {}
debug boolean false
Whatever you wanna call the table.
Give your own time zone a name. Adds this sentence below the table: "The table's times are in the <mytimezonename> time zone."
So, you don't like slate purple? Change it here, maybe something like gray "777" or "8a8a8a".
The cell with the current GMT (black border) and the cell with the viewer's LOCAL time (blue border) are displayed automatically. To have other time zones listed at their current hour (say, if you work with a global team), list each zone with a name of your choice and its hour offset.

And, sorry, there's no daylight savings feature yet. When the time comes, you gotta change affected values (along with all the clocks in your house). :O)

Use this property to add other events (work hours, etc.). For each event you want to add to the table, provide its name, separating multi-word names with hyphens. (In the color key that's displayed below the table, hyphens become spaces and the words are init-capped.) With each name, provide an HTML "#" color value (either 3 or 6 hex digits) and the cell numbers to apply the event to.
"But wait, how do I know what the cell numbers are?" Great question. To see the cell numbers, set debug to true.

For a more complete example, the values in the index.html file were used to display the picture above.

So, there ya go. Have fun!

1Sunrise and sunset are determined by your geolocation. And browser geolocation is not always available unless the web page is hosted on a web server. Yeah, don't holler at me, that's just the way it works. You can, of course, install a web server on your local machine and host it from there.