1
\$\begingroup\$

Intro: I started working three month ago and i have never used JavaScript before, i don't know what is the best practice in JS and i feel like my code can be improved a lot, so i'm here searching for tips and tricks or other infos who can make my code better.

Task: Take in input a dictionary with all opening time of a shop and return a formatted string.

Input: A dictionary with seven pairs, the key is "openingMon" .. "openingSun".
Time separated with dash "-" it's the opening time, if there is a ";" in that time is closed.
Note that the input is always a dictionary and always have this keys.

openings = {
    "openingMon" : "08:00 - 12:00 ; 13:00 - 21:00",
    "openingTue" : "08:00 - 10:00 ; 16:00 - 20:00",
    "openingWed" : "10:00 - 10:00 ; 16:00 - 20:00",
    "openingThu" : "08:00 - 14:00 ",
    "openingFri" : "08:00 - 20:00",
    "openingSat" : "",
    "openingSun" : ""
}

Output: a formatted string with the following rule:

  • If all value is empty you must return "Missing opening time".
  • If the value corresponding to the current day of the week is not empty you must return if the shop is open or closed and the closing/opening time.
  • If the value corresponding to the current day of the week is empty but at least another value is not empty you must return that the shop is closed and the opening time of the next day of the week with not empty value.
  • If tomorrow's value is empty you must include the name of the next day with opening time.
  • If the shop is closed for the rest of the day you must return a string like if the current day's value it's empty.

Examples (for the given input):

  • If it's Sunday return "Closed today - Opening: Tomorrow 08:00".
  • If it's Saturday return "Closed today - Opening: Monday 08:00".
  • If it's Thursday and it's 09:00 return "Open now - Closing: 14:00".
  • If it's Tuesday and it's 11:00 return "Closed now - Opening: 16:00".
  • If it's Tuesday and it's 21:00 return "Closed today - Opening: Tomorrow 10:00".
  • If it's Friday and it's 21:00 return "Closed today - Opening: Monday 08:00".

Solution:

// Set the string with the opening information
function set_opening(opening_dict) {

    // Convert from a time string to an int: "08:36" -> 836
    let toInt = (x) => parseInt(x.replace(":", ""));
    // For using a string of opening time like a list: i = 2, o = "08:30 - 13:00 ; 15:00 - 20:00" -> "15:00"
    let toList = (i, o = opening) => o == "" ? o : (o.includes(";") ? (o.split(" ; ")[Math.floor(i / 2)]).split(" - ")[i % 2] : o.split(" - ")[i]);
    // Get opening time based on a day of the week: 2 -> "08:30 - 13:00 ; 15:00 - 20:00"
    let getOpening = (x) => opening_dict["opening" + week_days[x].slice(0, 3)];
    // Get last closing time from a string: "08:30 - 13:00 ; 15:00 - 20:00" -> 2000
    let getClose = (o = opening) => o == "" ? 0 : o.includes(";") ? toInt(toList(3, o)) : toInt(toList(1, o));
    // Get opening time from opening as an int: i = 2, o = "08:30 - 13:00 ; 15:00 - 20:00" -> 1500
    let getTime = (i, o = opening) => o == "" ? 0 : toInt(toList(i, o));

    // Check if all value is empty
    let is_empty = true;
    for (const value of Object.values(opening_dict)) {
        is_empty = is_empty && value == "";
    }
    // If all value is empty there is no openings
    if (is_empty) {
        return "Missing opening time";
    }

    let week_days = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
    let now = new Date(Date.now());
    // Save current time as an int
    let time_now = now.getHours() + (now.getMinutes() > 9 ? "" : "0") + now.getMinutes();
    // Save the opening time for today (getDay return 0 for sunday and 6 for saturday)
    let opening = getOpening(now.getDay());

    // If today is closed tell next opening day
    if (opening == "" || time_now >= getClose()) {
        let next_opening_day = now.getDay() + 1;
        // Save next opening day
        while (next_opening_day != now.getDay()) {
            if (getOpening(next_opening_day) != "") {
                break;
            }
            // If it's sunday go to monday
            next_opening_day = (next_opening_day + 1) % 7;
        }
        let next_opening = next_opening_day == now.getDay() + 1 ? "Tomorrow" : week_days[next_opening_day];
        return `Closed today - Opening: ${next_opening} ${toList(0, getOpening(next_opening_day))}`;
    }

    // Check current time and say if it's is open or closed, along with next opening/closing time
    if (time_now < getTime(0)) {
        return `Closed now - Opening: ${toList(0)}`;
    } else if (getTime(0) <= time_now && time_now < getTime(1)) {
        return `Open now - Closing: ${toList(1)}`;
    }
    // If current openings have four time
    if (time_now < getTime(2)) {
        return `Closed now - Opening: ${toList(2)}`;
    } else if (getTime(2) <= time_now && time_now < getTime(3)) {
        return `Open now - Closing: ${toList(3)}`;
    }
};
\$\endgroup\$
5
  • \$\begingroup\$ Welcome to the site!! I’m not sure what version of JavaScript you used but I’m getting some errors when running it in Chrome and Node.js TIO \$\endgroup\$
    – jdt
    Oct 12, 2021 at 13:42
  • \$\begingroup\$ @JohanduToit what error are you getting? i'm using JavaScript v1.7 and Node.js v12.22.3 \$\endgroup\$
    – Alberto S
    Oct 12, 2021 at 13:54
  • \$\begingroup\$ let getClose = (o = opening) => o == "" ? 0 : o.includes(";") ? toInt(toList(3, o)) : toInt(toList(1, o)); TypeError: Cannot read property 'includes' of undefined \$\endgroup\$
    – jdt
    Oct 12, 2021 at 14:21
  • \$\begingroup\$ Perhaps, I'm just doing something stupid, can you perhaps add how you call set_opening? \$\endgroup\$
    – jdt
    Oct 12, 2021 at 14:49
  • \$\begingroup\$ @JohanduToit i'm sorry, there was an error in getOpening because i translated the function from my language to english, it work now \$\endgroup\$
    – Alberto S
    Oct 12, 2021 at 15:12

1 Answer 1

0
\$\begingroup\$

I think you are overcomplicating things with all the inline lambda functions.

A Simple way to compare two times is to use the following formula:

time = hour * 60 + minute.

Based on this you can use the following function to create a time representation from a string, ie 08:30

timeToInt = function(text) {
    let hour = parseInt(text.substring(0, 2));
    let minute = parseInt(text.substring(3));
    return hour * 60 + minute;
}

And use the same formula to get an integer representation of the current time:

let date = new Date();
let currentTime = date.getHours() * 60 + date.getMinutes();

At this point everything starts to become much simpler:

set_opening = function (openings) {
    let date = new Date();
    let currentTime = date.getHours() * 60 + date.getMinutes();
    let startDay = date.getDay();
    let dayOfWeek = startDay;
    let weekDayLookup = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
    let nextTime = false;
    for (; ;) {
        let dayName = weekDayLookup[dayOfWeek % 7];
        let opening = openings["opening" + dayName.substring(0, 3)];
        let timeSpans = opening.split(';').map(item => item.trim());
        for (span of timeSpans) {
            let hours = span.split('-').map(item => item.trim())
            if (nextTime == false) {
                let openTime = timeToInt(hours[0]);
                let closeTime = timeToInt(hours[1]);
                if (currentTime >= openTime && currentTime <= closeTime)
                    return "Open now - Closing: " + hours[1];
                nextTime = true;
            }
            else {
                if (dayOfWeek == startDay)
                    return "Closed now - Opening: " + dayName + " " + hours[0];
                else 
                    return "Closed today - Opening: " + (dayOfWeek - startDay == 1 ? "Tomorrow" : dayName) + " " + hours[0];
            }
        }
        dayOfWeek++;
        if (dayOfWeek > 14)
            return "No opening time found";
    }
}
\$\endgroup\$
1
  • \$\begingroup\$ Thank you nice tips :) \$\endgroup\$
    – Alberto S
    Oct 14, 2021 at 7:55

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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