Calculating Sleep Cycles

In the previous section, we put JavaScript directly in a <script> tag inside our HTML. This works, but for larger applications it is better to keep JavaScript in a separate file. Let’s do that, then build our sleep cycle calculation.

Moving to an External JavaScript File

Create a new file called index.js in your project folder. Move the JavaScript code from the <script> tag into this file:

const calcBtn = document.getElementById("calc-btn");
calcBtn.onclick = handleClick;

function handleClick() {
  console.log("Bam!");
  window.alert("Boo!");
}

Now update index.html. Replace the entire <script>...</script> block with a link to the external file:

<script src="index.js"></script>

Keep this line right before the closing </body> tag. Refresh the browser and click the button. It should still work the same way.

Now we can test our JavaScript with Node too. Try:

node index.js

You will get an error about document not being defined. That is expected. document only exists in the browser. But we can still use Node to test pure JavaScript logic before integrating with the DOM.

Getting the Current Time

Let’s write the calculation logic. For now, replace the contents of index.js with just this:

const now = new Date();
console.log(now);

Run it with Node:

node index.js

You will see something like 2024-06-15T02:30:00.000Z. This is the full date and time in UTC. This format is not easy for users to read.

Formatting for Local Timezone

The Z at the end means UTC (Coordinated Universal Time). Let’s convert to your local timezone:

const now = new Date();
console.log(now.toLocaleString());

Run it again. Now you see something like 6/15/2024, 10:30:00 PM. This is the date and time in your local timezone. This is better, but we only need the time.

Showing Just the Time

Use toLocaleTimeString to show only the time portion:

const now = new Date();
console.log(now.toLocaleTimeString("en-US", { timeStyle: "short" }));

The options object { timeStyle: "short" } controls the format. Now you should see something like 10:30 PM.

Calculating Fall Asleep Time

It takes about 14 minutes to fall asleep. Let’s calculate when that would be:

const fallAsleepTime = new Date();
fallAsleepTime.setMinutes(fallAsleepTime.getMinutes() + 14);

console.log(
  "You will fall asleep at",
  fallAsleepTime.toLocaleTimeString("en-US", { timeStyle: "short" })
);

We create a Date, then use setMinutes to add 14 minutes to the current minutes. Run it. You should see a time 14 minutes from now.

Notice the pattern: we get the current value, modify it, then set it back. This “get-modify-set” pattern is common when working with objects that have getter and setter methods.

Calculating One Sleep Cycle

Each sleep cycle is 90 minutes. Let’s calculate when the first cycle ends:

const fallAsleepTime = new Date();
fallAsleepTime.setMinutes(fallAsleepTime.getMinutes() + 14);

const wakeUpTime = new Date(fallAsleepTime);
wakeUpTime.setMinutes(wakeUpTime.getMinutes() + 90);

console.log(
  "First cycle ends at",
  wakeUpTime.toLocaleTimeString("en-US", { timeStyle: "short" })
);

Notice we create a new Date from fallAsleepTime. If we just did const wakeUpTime = fallAsleepTime, both variables would point to the same Date object, and modifying one would modify the other.

Calculating All Six Cycles

Now let’s loop to calculate all 6 cycles:

const fallAsleepTime = new Date();
fallAsleepTime.setMinutes(fallAsleepTime.getMinutes() + 14);

const wakeUpTime = new Date(fallAsleepTime);

for (let i = 1; i <= 6; i++) {
  wakeUpTime.setMinutes(wakeUpTime.getMinutes() + 90);
  const timeString = wakeUpTime.toLocaleTimeString("en-US", {
    timeStyle: "short",
  });
  console.log(`Cycle ${i}: ${timeString}`);
}

Each iteration adds another 90 minutes. Run it. You should see 6 wake-up times, each 90 minutes apart.

Wrapping in a Function

Let’s wrap this in a function and store the results in an array:

function calcWakeUpTimes() {
  const fallAsleepTime = new Date();
  fallAsleepTime.setMinutes(fallAsleepTime.getMinutes() + 14);

  const wakeUpTime = new Date(fallAsleepTime);
  const wakeUpTimes = [];

  for (let i = 1; i <= 6; i++) {
    wakeUpTime.setMinutes(wakeUpTime.getMinutes() + 90);
    const timeString = wakeUpTime.toLocaleTimeString("en-US", {
      timeStyle: "short",
    });
    wakeUpTimes.push(timeString);
  }

  console.log("Wake-up times:", wakeUpTimes.join(", "));
}

calcWakeUpTimes();

Test it one more time with node index.js. You should see all 6 times printed on one line.

Connecting to the Button

Now let’s make the button trigger our calculation. Replace the last line with code to hook up the button:

- calcWakeUpTimes();
+ const calcBtn = document.getElementById("calc-btn");
+ calcBtn.onclick = calcWakeUpTimes;

Open index.html in your browser, open the developer console (right-click → Inspect → Console), and click the Calculate button. You should see the wake-up times logged.

The output is still just in the console. In the next section, we will display these times on the page itself.

Checkpoint: Commit your progress.

git add .
git commit -m "wakeup-02: Add sleep cycle calculation"
git push