# freeCodeCamp Algorithm Challenge Guide: Friendly Date Ranges

freeCodeCamp Algorithm Challenge Guide: Friendly Date Ranges
0

Remember to use `Read-Search-Ask` if you get stuck. Try to pair program and write your own code

### Problem Explanation:

Create a program that will take two dates and convert them into a more easy to understand date such as `January 1st, 2017`. It will also check the difference between them, and handles cases with no difference, more than a day, more than a month, more than a year, and more than a month and less than a year respectively.

## Hint: 1

Split the string into an array where you get “YYYY”, “MM”, “DD”.

try to solve the problem now

## Hint: 2

You need to handle the case for “st”, “nd”, and “th”. Note that 13 is “th” not “rd”.

try to solve the problem now

## Hint: 3

If you are using `Date()` to create instances of dates to work with, then use UTC time to avoid errors due to time zone difference between servers.

try to solve the problem now

## Basic Code Solution:

``````function makeFriendlyDates(str) {

var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];

// Convert a YYYY-MM-DD string into a date object.
function convertDate(str) {
// Split the dates to work independently.
var dateStr = str.split('-');

// Force the dates into Universal time to avoid issues due to timezones.
return (new Date(Date.UTC(dateStr[0], dateStr[1] - 1, dateStr[2])));

}

// Handles the case of the day's endings.
function dateEnding(val) {
switch (val) {
case 1:
case 21:
case 31:
return val + 'st';
case 2:
case 22:
return val + 'nd';
case 3:
case 23:
return val + 'rd';
default:
return val + 'th';
}
}

// Checks for the real difference in months to avoid errors
function monthDiff(date1, date2) {
var month2 = date2.getUTCFullYear() * 12 + date2.getUTCMonth();
var month1 = date1.getUTCFullYear() * 12 + date1.getUTCMonth();
return month2 - month1;
}

//day diff
function dayDiff(date1, date2) {
if(date2.getUTCMonth() === date1.getUTCMonth()){
return date1.getUTCDate()-date2.getUTCDate();
}
return 0;
}

// Get's the right month string.
function getMonth(date) {
return months[date.getUTCMonth()];
}

function displayDate() {

// Handles same day
if (date2.getTime() - date1.getTime() === 0) {
return [getMonth(date1) + ' ' + dateEnding(date1.getUTCDate()) + ', ' + date1.getUTCFullYear()];
}

// Handles same month
if (date1.getUTCMonth() === date2.getUTCMonth() && date1.getUTCFullYear() === date2.getUTCFullYear()) {
return [getMonth(date1) + ' ' + dateEnding(date1.getUTCDate()), dateEnding(date2.getUTCDate())];
}

// Handles more than a month of difference, but less than 12 months and different year
if (monthDiff(date1, date2) < 12 && date1.getUTCFullYear() !== date2.getUTCFullYear() ) {
return [getMonth(date1) + ' ' + dateEnding(date1.getUTCDate()), getMonth(date2) + ' ' + dateEnding(date2.getUTCDate())];
}

// Handles same month but different year
if (monthDiff(date1, date2) <= 12 && dayDiff(date1, date2)>0) {
return [getMonth(date1) + ' ' + dateEnding(date1.getUTCDate())+', '+date1.getUTCFullYear(), getMonth(date2) + ' ' + dateEnding(date2.getUTCDate())];
}

// Handles more than a month of difference, but less than 12 months and same year
if (monthDiff(date1, date2) < 12) {
return [getMonth(date1) + ' ' + dateEnding(date1.getUTCDate())+', '+date1.getUTCFullYear(), getMonth(date2) + ' ' + dateEnding(date2.getUTCDate())];
}

// Handles cases with more than 12 months apart.
return [getMonth(date1) + ' ' + dateEnding(date1.getUTCDate()) + ', ' + date1.getUTCFullYear(), getMonth(date2) + ' ' + dateEnding(date2.getUTCDate()) + ', ' + date2.getUTCFullYear()];
}

var date1 = convertDate(str[0]);
var date2 = convertDate(str[1]);

return displayDate();

}

// test here
makeFriendlyDates(['2016-07-01', '2016-07-04']);
``````

### Code Explanation:

• The function `convertDate()` converts a string in the format YYYY-MM-DD to a date object.
• `split()` the dates on - to work independently.
• Force the dates into universal time to avoid timezone issues.
• The function `dateEnding()` handles day’s ending i.e., appending st, nd, rd or th.
• The function `monthDiff()` checks the real difference in month to avoid errors.
• The function `dayDiff()` checks the real difference in day to avoid errors.
• The function `getMonth()` returns month string for particular date.
• The function `displayDate()` displays the date correctly. Following provisions are made:
• Handles same day.
• Handles same month.
• Handles more than a month of difference, but less than 12 months and different year.
• Handles same month but different year.
• Handles more than a month of difference, but less than 12 months and same year.
• Handles cases with more than 12 months apart.

## NOTES FOR CONTRIBUTIONS:

• DO NOT add solutions that are similar to any existing solutions. If you think it is similar but better, then try to merge (or replace) the existing similar solution.
• Categorize the solution in one of the following categories — Basic, Intermediate and Advanced.

See `Wiki Challenge Solution Template` for reference.

You did not check for currentYear case.

1 Like

```function makeFriendlyDates(arr) {
// Split date strings into Array
var first = arr[0].split("-"),
second = arr[1].split("-"),
// Convert string values into integer numbers
firstYear = parseInt(first[0]),
firstMonth = parseInt(first[1]),
firstDay = parseInt(first[2]),
secondYear = parseInt(second[0]),
secondMonth = parseInt(second[1]),
secondDay = parseInt(second[2]);
// Set Month Names
var months = {1:"January",2:"February",3:"March",4:"April",5:"May",6:"June",7:"July",8:"August",
9:"September",10:"October",11:"November",12:"December"};

// Check ordinal Dates
function ordinalDates(day){
switch (day){
case 1:
case 21:
case 31:
return day + "st";
case 2:
case 22:
return day + "nd";
case 3:
case 23:
return day + "rd";
default:
return day + "th";
}
}
var friendlyFirst = "" + months[firstMonth] + " " + ordinalDates(firstDay);
var friendlySecond = "" + months[secondMonth] + " " + ordinalDates(secondDay);

switch (true) {
//Check same Dates
case (arr[0] === arr[1]):
return [friendlyFirst + ", " + firstYear];
//Check If the range ends in the same month that it begins, do not display the ending year or month.
case ((firstYear === secondYear) && (firstMonth === secondMonth)):
return [friendlyFirst,"" + ordinalDates(secondDay)];
//Check if the date range ends in less than a year from when it begins, do not display the ending year.
case ((firstYear === secondYear) && (firstMonth != secondMonth)):
return [friendlyFirst + ", " + firstYear, friendlySecond];
/*Check if the date range ends in less than a year from when it begins and
check if the range ends in the same month that it begins.*/
case ((secondYear - firstYear == 1) && (firstMonth === secondMonth) && (firstDay > secondDay)):
return [friendlyFirst + ", " + firstYear, friendlySecond];
//Check if the date range ends within one year, the year should not be displayed at the beginning of the friendly range.
case ((secondYear - firstYear == 1) && (firstMonth > secondMonth)):
return [friendlyFirst, friendlySecond];
default:
return [friendlyFirst + ", " + firstYear, friendlySecond + ", " + secondYear];
};
}
```

I’m gonna leave this here for others running the current challenges (not the beta push), cause I’m still pissed off that this NFP has refused to fix the bugs in these challenges, having known since JULY 2016 of these issues. Hours of trying to debug YOUR issue. blah…

``````// To Err is code, to Arr is pirate. So work like a captain, but code like a pirate!
// walk-through with Stephen Mayeux
//DON'T EVER DO THIS FOR REALSY, USE A LIBRARY - http://momentjs.com/
// THIS CHALLENGE IS BUGGY AS ALL GET OUT, AND YOU'VE KNOWN OF THE ISSUES SINCE JULY 2016

// start the helper functions to avoid a ton of copypasta throughout this challenge
// our months array

var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];

//convert integer to ordinal number

function makeOrdinals(num) {
switch (num) {
case 1:
case 21:
case 31:
return num.toString() + 'st';
case 2:
case 22:
return num.toString() + 'nd';
case 3:
case 23:
return num.toString() + 'rd';
default:
return num.toString() + 'th';
}
}

// access months numerical number array (*January = [0]) and create ordinal number
function monthAndDay(d) {
return months[d.getMonth()] + ' ' + makeOrdinals(d.getDate());
}

function fullDate(d) {
return monthAndDay(d) + ', ' + d.getFullYear();
}

function makeFriendlyDates(arr) {
//midnight, Jan 1, 1970 - https://www.quora.com/What-is-the-significance-of-January-1-1970
//return Date.parse(arr[0]); = 1467331200000 miliseconds

// Change all date vars to UTC, and use (-1) on the currentYear var, because FCC hasn't fixed the bugs in this challenge. thanks
var currentYear = new Date().getUTCFullYear() - 1;
var start = new Date(Date.parse(arr[0]));
start = new Date(start.getUTCFullYear(), start.getUTCMonth(), start.getUTCDate());
var end = new Date(Date.parse(arr[1]));
end = new Date(end.getUTCFullYear(), end.getUTCMonth(), end.getUTCDate());
var yearInMS = 31536000000; // 1 year in miliseconds

//test variables by uncommenting one line below
//return currentYear;
//return start;
//return end;
//return yearInMS;

// if our start and end dates are the same, in miliseconds
if (end - start === 0) {
return [fullDate(start)];
}

// if we are in the current year and same month
if (start.getFullYear() === currentYear && start.getMonth() === end.getMonth()) {
return [monthAndDay(start), makeOrdinals(end.getDate())];
}

// if we are in the current year and dates are less than one year apart
if (start.getFullYear() === currentYear && end - start < yearInMS) {
return [monthAndDay(start), monthAndDay(end)];
}

// if we are NOT in the current year, but less than a year apart
if (end - start < yearInMS) {
return [fullDate(start), monthAndDay(end)];
}

// if our dates are more than a year apart
if (end - start >= yearInMS) {
return [fullDate(start), fullDate(end)];
}
}

makeFriendlyDates(['2017-07-01', '2017-07-04']);
``````

Not beautiful, but hey it works. Can’t expect more from such a nasty challenge.

``````function makeFriendlyDates(arr) {
var f=['',''];
var diff=arr.map(e=>(e.replace(/-/g,''))).reduce((a,v)=>v-a);
var diffMoreThanYear=diff>9999;
var dates=arr.map(e=>e.split('-').map(v=>parseInt(v)));

//month
f[0]=f[0].concat(month(dates[0][1])+' ');
if(dates[0][0]!=dates[1][0]||dates[0][1]!=dates[1][1]){
f[1]=f[1].concat(month(dates[1][1])+' ');
}
//day
f=f.map((v,i)=>v.concat(day(dates[i][2])));
//year
if(dates[0][0]!=2016||diffMoreThanYear){
f[0]=f[0].concat(', '+dates[0][0]);
}
if(diffMoreThanYear){
f[1]=f[1].concat(', '+dates[1][0]);
}
if(diff==0){
f.pop();
return f;
}
else return f;
}

function month(str){
switch(str){
case 1: return 'January';
case 2: return 'February';
case 3: return 'March';
case 4: return 'April';
case 5: return 'May';
case 6: return 'June';
case 7: return 'July';
case 8: return 'August';
case 9: return 'September';
case 10: return 'October';
case 11: return 'November';
case 12: return 'December';
}
}

function day(n){
switch(n){
case 1: return '1st';
case 2: return '2nd';
case 3: return '3rd';
}
return n+'th';
}
``````

Did this problem get pulled from the course? I can’t find it anywhere.

Nonetheless, I’m glad I stumbled upon this thread as I have just completed the challenge (all I have to do is submit it now) but the code is very ugly when compared to some really elegant solutions presented here.