DEV Community is a community of 879,630 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

dev.to staff

Posted on

Daily Challenge #252 - Everybody hates Mondays

Nobody likes Mondays! You spent the weekend partying and hanging out with friends, and then Monday comes, and you have to get up early, put on some business clothes and go to work. So how many of these horrible days does someone have to endure? Well, let's find out.

Create a method to find the number of Mondays given a person's birthday and the current date. Do not worry about holidays/vacation, sick leave etc. Assume a person has a job and goes to work throughout a year if they are of working age. To keep things simple, assume someone starts working when they are 22 years old and retires when he/she is 78. That's right, Mondays don't count as bad days if you are at school/university or a pensioner! And although not having to work on the weekends is a rather recent fad (look it up!) assume that Mondays where and will always be bad days at any era.

Examples

`Mondays.count(LocalDate.of(1995, 4, 3), LocalDate.of(2017, 4, 3))`
=> 1 Monday

`Mondays.count(LocalDate.of(1995, 4, 2), LocalDate.of(2018, 4, 2))`
=> 53 Mondays

Tests

`Mondays.count(LocalDate.of(1700, 9, 20), LocalDate.of(1762, 9, 26))`
`Mondays.count(LocalDate.of(-300, 12, 20), LocalDate.of(-258, 12, 22))`
`Mondays.count(LocalDate.of(1000000, 2, 25), LocalDate.of(1000022, 12, 28))`

This challenge comes from shadowmanos on CodeWars. Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

Want to propose a challenge idea for a future post? Email yo+challenge@dev.to with your suggestions!

Discussion (3)

Andrea Stagi • Edited on

Python implementation

``````from datetime import datetime, timedelta

class Mondays():

@staticmethod
def count(birth: datetime, current_date: datetime):
# For a more accurate deltatime in years use dateutil library with relativedelta instead, it supports leap years
end_working = birth + timedelta(days=78 * 365)
start_working = birth + timedelta(days=22 * 365)
if current_date > end_working:
current_date = birth + end_working
first_monday = start_working + timedelta(days=(7 - start_working.weekday()) % 7)
last_monday = current_date - timedelta(days=current_date.weekday())
days_between_mondays = (last_monday - first_monday).days
if days_between_mondays >= 7:
return int(days_between_mondays / 7)
return 1 if not current_date.weekday() or not start_working.weekday() else 0

try:
mondays = Mondays.count(datetime(1995, 4, 3), datetime(2017, 4, 3))
print (mondays)
except ValueError as ex:
print (ex)

try:
mondays = Mondays.count(datetime(1995, 4, 2), datetime(2018, 4, 2))
print (mondays)
except ValueError as ex:
print (ex)

try:
mondays = Mondays.count(datetime(1700, 9, 20), datetime(1762, 9, 26))
print (mondays)
except ValueError as ex:
print (ex)

try:
mondays = Mondays.count(datetime(-300, 12, 20), datetime(-258, 12, 22))
print (mondays)
except ValueError as ex:
print (ex)

try:
mondays = Mondays.count(datetime(1000000, 2, 25), datetime(1000022, 12, 28))
print (mondays)
except ValueError as ex:
print (ex)
``````
Peter Lau

JavaScript version without outside packages. It takes me such a long time. Still doubt if it can pass all the tests, while CodeWar ask for a Java version.

``````const oneWeek = 7 * 24 * 3600 * 1000
const oneDay = 24 * 3600 * 1000
const getWorkDate =  ([year, month, day]) => [year+22, month, day]
const getRetireDate = ([year, month, day]) => [year+78, month, day]
const getDate = ([year, month, day]) => new Date(year, month-1, day)
const formatMonday = number => `\${number} Monday\${number == 0 || number == 1 ? '' : 's'}`

const cmpDate = (date1, date2) => {
for (let i=0;i<3;i++) {
if(date1[i]>date2[i]) return 'large'
if(date1[i]<date2[i]) return 'less'
}
return 'equal'
}

const countMonday = (birthDate, currentDate) => {
let count = 0
const workDate =  getWorkDate(birthDate)
const retireDate = getRetireDate(birthDate)
if(cmpDate(currentDate, workDate) == 'less') return formatMonday(count)
const endDate = cmpDate(currentDate, retireDate) != 'less' ? retireDate : currentDate

const workWeekDay = getDate(workDate).getDay()
const endWeekDay = getDate(endDate).getDay()
console.log(workWeekDay, endWeekDay)

const duration = getDate(endDate).getTime() - getDate(workDate).getTime() + oneDay
const weekCount = parseInt(duration/oneWeek)
console.log(duration, oneWeek, duration % oneWeek)
if (duration % oneWeek != 0 && (
endWeekDay < workWeekDay || endWeekDay == 1
)) {
count = weekCount + 1
} else {
count = weekCount
}
return formatMonday(count)
}

birth = [1995, 4, 3]
current = [2017, 4, 3]
console.log(countMonday(birth, current))

birth = [1995, 4, 2]
current = [2018, 4, 2]
console.log(countMonday(birth, current))

``````
Peter

Rust, likely a better way to do this.

``````use std::convert::TryInto;
use chrono::prelude::*; // 0.4.11

pub struct Mondays {}

impl Mondays {
pub fn count(birth: chrono::NaiveDate, curr_date: chrono::NaiveDate) -> i64 {
// start work at age 22
let start_work = birth + chrono::Duration::days(22 * 365);
// retire at age 78
let retire = birth + chrono::Duration::days(78 * 365);
// check if they have retired or not
let end_work = if curr_date > retire { retire } else { curr_date };
// check days from monday, if 0 set to 7
let start_from_monday = match start_work.weekday().num_days_from_monday() {
0 => 7,
x => x,
};
// get first monday
let first_monday = start_work + chrono::Duration::days((7 - start_from_monday).try_into().unwrap());
// get last monday
let last_monday = end_work - chrono::Duration::days((end_work.weekday().num_days_from_monday()).try_into().unwrap());
// count days between mondays
let between_mondays = last_monday.signed_duration_since(first_monday).num_days();
// if more than 7 days, div by 7
if between_mondays > 7 {
between_mondays / 7
} else if between_mondays >= 0 {
1
} else {
0
}
}
}

#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_1() {
assert_eq!(Mondays::count(chrono::NaiveDate::from_ymd(1995, 4, 3), chrono::NaiveDate::from_ymd(2017, 4, 3)), 1);
}
#[test]
fn test_2() {
assert_eq!(Mondays::count(chrono::NaiveDate::from_ymd(1995, 4, 2), chrono::NaiveDate::from_ymd(2018, 4, 2)), 53);
}
#[test]
fn test_3() {
assert_eq!(Mondays::count(chrono::NaiveDate::from_ymd(1995, 4, 2), chrono::NaiveDate::from_ymd(2017, 3, 2)), 0);
}
}
``````