๐ 12 vs 24 hour clock
Learning Objectives
We usually write the time in one of two ways: the analogue 12 hour clock or the digital 24 hour clock. The 12 hour clock counts up to 12: it resets at midday. The 24 hour clock counts up to 24: it resets at midnight.
2๏ธโฃ4๏ธโฃ hour time | ๐ 12 hour time |
---|---|
09:00 | 09:00 am |
10:00 | 10:00 am |
11:30 | 11:30 am |
12:00 | 12:00 pm |
13:43 | 1:43 pm |
14:00 | 2:00 pm |
We use the notation “HH:MM”. HH is our stand-in for the hours value. MM is our stand-in for the minutes value.
๐งฉ Stating the problem
Let’s pose a problem: given any time in 24 hour clock, we want to format it as a 12 hour clock time. To achieve this goal, we’re going to implement a function formatAs12HourClock
.
Given a time in 24 hour clock
When we call formatAs12HourClock
Then we get back a string representing the same time in 12 hour clock
๐งช Our tests:
I expect formatAs12HourClock("09:00")
to be "09:00 am"
I expect formatAs12HourClock("14:19")
to be "2:19 pm"
โ๏ธ Comparing current and target output
Learning Objectives
Let’s start with a function declaration of formatAs12HourClock
:
|
|
Whenever we call formatAs12HourClock
we expect it to return a particular value, which we call the ๐ฏ target output. For example, we expect formatAs12HourClock("08:00")
to return "08:00 am"
. "08:00 am"
is the ๐ฏ target output.
However, the current output is what the function actually returns right now.
๐๐ผ Work through the exercises
Let’s start with formatAs12HourClock
defined like this:
|
|
Suppose we now call the function like this:
formatAs12HourClock("05:30");
For the call above, what is the
a) the current output? b) the ๐ฏ target output?
๐๐ผ Keep going
Let’s continue with formatAs12HourClock
defined like this:
|
|
Suppose we call the function like this:
formatAs12HourClock("20:10");
For the call above, what is the
a) the current output? b) the ๐ฏ target output?
๐งฉ Comparing values
We have learned how to log values to the console. We can also compare two values. We check that a function produces some target output with a comparison.
We compare the current output of formatAs12HourClock("08:00")
with the target output of "08:00 am"
and ask: are these two values the same?. We use a comparison operator to compare two expressions and check if they evaluate to the same value. We use the strict equality operator ===
to check if two values are the same.
Left equals Right
formatAs12HourClock("08:00") === "8:00 am";
===
checks if the values on the left and right of the operator are the same. We can think of formatAs12HourClock("08:00") === "8:00 am"
as the question: “Is the return value of formatAs12HourClock("08:00")
equal to "8:00 am"
?” This leads to the question:
What will the expression
formatAs12HourClock("08:00") === "8:00 am"
evaluate to?
โ โ Boolean values
Does 1 equal 0? Yes or No? True or False?
Some values are best represented as strings: any piece of text, a name, address, etc will most likely be stored using the string data type. The number data type can store numbers we use in calculations.
If we’re comparing two things, there are only two different states: true or false. This leads us to the boolean datatype, which only has true or false values. Whenever we compare two values with a comparison operator, we end up with a boolean value: true
or false
. It’s one or the other. It’s boolean.
// using the strict equality comparison expression
console.log(42 === 10 + 32);
// logs true
console.log(10 * 5 === 60);
// logs false
๐๐พ Now work through the exercises
Look at the code below and then try predicting how the computer will interpret each line. Remember to think about each line and work out if it is a declaration or a statement. You may want to use the Node REPL to help you check your answers.
Look at the code below and predict what each expression will evaluate to. Write your prediction down. Use the Node REPL to check your answers. Check out some relevant documentation if you’ve not seen a particular operator before.
|
|
๐๐ฟ Keep Going
Look at the code below and predict what each expression will evaluate to. Write your prediction down. Use the Node REPL to check your answers. Check out some relevant documentation if you’ve not seen a particular operator before
|
|
๐๐ฟ Keep Going
Checking misconceptions ๐ค
Look at the code below and then predict what the expression will evaluate to. Be sure to explain your answer too. Use the Node Repl to check your answer. Does the REPL output make sense?
Try using the Node Repl to check your answer. Does the REPL output make sense?
|
|
โ๏ธ Writing an assertion
Learning Objectives
We now have 2 new concepts: booleans and comparisons. From these concepts, we can now write an assertion about the function formatAs12HourClock
.
๐ An assertion is a check that our code behaves in a particular way: this check can either succeed or fail.
So far we’ve used the log function console.log
. We can write assertions using another function: console.assert
. The documentation says that console.assert
writes an error message to the console if the assertion is false. If the assertion is true, nothing happens. As finalCharacter === "?"
evaluates to true, no message will be written to the console.
const calculation = 10 + 32;
const result = 42;
console.assert(calculation === result);
Experiment with assertions
const calculation = 10 + 32;
const result = 42;
console.assert(calculation === result);
Update the final character in the sentence
variable string to make the assertion fail. Check the output you get in the console.
exercise</span>
exercise</span>
Let’s look at an example using formatAs12HourClock
:
function formatAs12HourClock() {}
console.assert(formatAs12HourClock("08:00") === "08:00 am");
Predict and explain if the assertion will succeed or fail. Pay particular attention to the return value of formatAs12HourClock
.
Clarity with arguments
It would be useful to have more information as to why this assertion failed. We can pass an additional argument to console.assert
:
function formatAs12HourClock() {}
console.assert(
formatAs12HourClock("08:00") === "08:00 am",
`current output: ${formatAs12HourClock("08:00")}, target output: 08:00 am`
);
Let’s break down these arguments to make sense of what’s going on:
- first argument -
formatAs12HourClock("08:00") === "08:00 am"
- the condition we’re checking - second argument -
current output: ${formatAs12HourClock("08:00")}, target output: 08:00 am
- a message string that will be logged to the console if the condition is false.
๐งน Refactor
We can tidy up the assertion even further. As weโre reusing the same expressions, we can store their result in variables with meaningful names so we can reuse them:
|
|
Execute this code; we now get a log in the console:
Assertion failed: current output: undefined, target output: 08:00 am
๐งฐ Implementing the functionality
On line 4, the function is being passed a single argument "08:00"
. But our function ignores it - it doesn’t declare any parameters. We can parameterise the function and label the input as time
:
function formatAs12HourClock(time) {}
According to our assertion, when we call our function with an input of "08:00"
we need to create an output of "08:00 am"
. We can add "am"
to the time
to get the target output. We can update our function with a template literal, set the return value and then re-run our code including our assertion to check the function is returning the correct value.
๐ We can and should continually check our assertions to see if our functionโs current output meets our target output.
|
|
โ Nothing is printed to the console, so this assertion is passing ๐
activity
๐ผ Checking different cases
So far weโve only created assertions that check the functionโs behaviour for times after midnight and before midday. In these cases, there is a pattern: take the current time and add "am"
to the end.
Now we need to assert that the function behaves correctly when the time is later than midday. Letโs create an assertion for our function when passed an input of "23:00"
:
|
|
๐ Reusing variable names
When we run the file with Node, we get an error in the console:
SyntaxError: Identifier 'currentOutput' has already been declared
In this case, identifier means name of a variable, so in a variable declaration like
const currentOutput = formatAs12HourClock("08:23");
currentOutput
is the identifier.
When an error is thrown, it means the execution of the program stops at this point and an error report is sent to the user. However, we want to do multiple assertions.
function formatAs12HourClock(time) {
return `${time} am`;
}
const currentOutput = formatAs12HourClock("08:00");
const targetOutput = "08:00 am";
console.assert(
currentOutput === targetOutput,
`current output: ${currentOutput}, target output: ${targetOutput}`
);
// โ this assertion now fails
const currentOutput2 = formatAs12HourClock("23:00");
const targetOutput2 = "11:00 pm";
console.assert(
currentOutput2 === targetOutput2,
`current output: ${currentOutput2}, target output: ${targetOutput2}`
);
Now the second assertion fails with the following message:
Assertion failed: current output: 23:00 am, target output: 11:00 pm
exercise
formatAs12HourClock
returns the target output when passed another time input in the afternoon.โ๏ธ โ๏ธ Making a choice
Learning Objectives
Our function works for morning inputs like "08:00"
. In this case, the function returns the target output of "08:00 am"
as required. However, at the moment, the output of formatAs12HourClock("23:00")
is "23:00 am"
.
๐ก We need to execute some different logic when the time is beyond midday
We can interpret this behaviour as a question:
We need to work out what to do in the case when the time input is later than midday.
๐งญ Describing the strategy
Let’s describe the strategy for dealing with an input that is after midday.
Earlier we observed that when the time goes beyond midday then we can subtract 12 from the hours time to get the new hours for the 12 hour clock time.
Before writing code, we can define our approach in steps using a flowchart:
Starting with an input like "23:00"
:
This approach involves running some code conditionally. In this case, we’re only going to continue doing Steps 4-6 if the condition hours are greater than 12 is true
.
โ Conditionally executing code
Learning Objectives
Recall: JavaScript programs are built up from sequences of declarations and statements.
In programming, we can use an if
statement to execute some code when a given condition is true
. In JavaScript, we can write an if
statement as follows:
if (condition) {
// do some code in here
}
The if
statement consists of:
if
keyword: this is the start of theif
statement(condition)
: condition is an expression that evaluates to true or false{}
: a block statement: any code we want to execute if the condition is true goes inside the curly braces here
We can represent this with a diagram too:
๐น๏ธ Playing computer
function checkDivisibility(a, b) {
if (a % b === 0) {
return `${a} is divisible by ${b}`;
}
return `${a} is not divisible by ${b}`;
}
console.log(checkDivisibility(10, 2));
console.log(checkDivisibility(50, 3));
Play computer with the example above, step through each line in the code and work out happens each time the function is called.
- What is the return value each time the function is called?
- What value is assigned to the
phoneNumber
parameter each time the function is called?
If you’ve not encountered any syntax before, remember to look it up in some documentation.
๐น๏ธ Playing computer
function getCountryCode(phoneNumber) {
if (phoneNumber.startsWith("+44")) {
return "UK";
}
}
getCountryCode("+447831620328");
getCountryCode("+989871783972");
Play computer with the example above, step through each line in the code and work out happens each time the function is called.
- What is the return value each time the function is called?
- What value is assigned to the
phoneNumber
parameter each time the function is called? - Try describing the purpose of this function - what should it do?
๐ง Forming sub-goals
Learning Objectives
For formatAs12HourClock
our strategy for inputs like "23:00"
involves checking if the hours
value is less than 12. For this purpose, we can use the greater than comparison operator >
.
>
will check if the value on the operator’s left side is less than the value on the operator’s right side.
So 3 > 12
evaluates to false
, as 3
is not greater than 12
.
So provided we have an expression for hours, we can write an if
statement as follows:
if (/* here goes an expression here that evaluates to the hours */ < 12) {
// do code to format the 12 hours
}
To complete the logic, we can form a
Any time we’re solving a problem, we can define a goal - a thing we need to achieve to consider the problem solved. We can break a problem into smaller problems, each with its own sub-goal. The problem-solving process involves continually breaking down problems into smaller manageable problems, each with its own sub-goal.
For the implementation of formatAs12HourClock
, we can form a sub-goal as follows:
๐ฏ Sub-goal: Find the hours value from the
time
input
๐งถ Accessing strings
Learning Objectives
Given a time
string we need to access the first 2 characters of the string which represent the hours.
Strings are zero-indexed.
Index means position, so zero-indexed means we start counting character positions from 0
onwards.
Here are the positions/indexes for "23:00"
index | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
character | "2" | "3" | ":" | "0" | "0" |
In JavaScript, we can use square bracket notation to access specific characters in the string using the index.
time[0]; // evaluates to "2"
time[1]; // evaluates to "3"
time[2]; // evaluates to ":"
// etc
Square bracket access will only give a single character. We must use another method to extract multiple characters from the given string.
โ๏ธ Extracting a slice
To extract 1 or more characters from a string, we can use a function called
slice
is a function that can take 2 arguments: a start index and an end index. slice
will return a section of the string from the start index up to but not including the end index.
time; // holds the value "23:00"
time.slice(0, 2); // will access the characters below
index | 0 | 1 |
---|---|---|
character | "2" | "3" |
So time.slice(0,2)
will evaluate to "23"
when the time
is "23:00"
. Finally we must convert "23"
to the number 23
, otherwise we can’t compare this value properly. We can use the Number
function to convert the string into a number.
Number(time.slice(0, 2)); // evaluates to 23
๐๏ธ Assembling the parts
Learning Objectives
Earlier we defined a sub-goal to find a value for the hours from the time
input. We’ve found that Number(time.slice(0,2))
is an expression that evaluates to the hours from time
. So we can write an if
statement using this expression:
if (Number(time.slice(0, 2)) > 12) {
}
If the time is "23:00"
then the expression Number(time.slice(0, 2)) > 12
will evaluate to true
and the body of the if
statement will be executed.
This if
statement is implementing the following part of the diagram from earlier:
Now we can format the string using our approach from earlier:
weโll need to append "pm"
to the string expression and subtract 12 from the hours. So we get the following:
if (Number(time.slice(0, 2)) > 12) {
return `${time.slice(0, 2) - 12}:00 pm`;
}
The return
statement above implements the following steps we set out earlier:
Now we can re-run our assertions from earlier to check our function behaves as target.