🎉 Exercism Research is now launched. Help Exercism, help science and have some fun at research.exercism.io 🎉
Avatar of KiligWY

KiligWY's solution

to Meetup in the Objective-C Track

Published at Jul 13 2018 · 0 comments
Instructions
Test suite
Solution

Calculate the date of meetups.

Typically meetups happen on the same day of the week. In this exercise, you will take a description of a meetup date, and return the actual meetup date.

Examples of general descriptions are:

  • The first Monday of January 2017
  • The third Tuesday of January 2017
  • The wednesteenth of January 2017
  • The last Thursday of January 2017

The descriptors you are expected to parse are: first, second, third, fourth, fifth, last, monteenth, tuesteenth, wednesteenth, thursteenth, friteenth, saturteenth, sunteenth

Note that "monteenth", "tuesteenth", etc are all made up words. There was a meetup whose members realized that there are exactly 7 numbered days in a month that end in '-teenth'. Therefore, one is guaranteed that each day of the week (Monday, Tuesday, ...) will have exactly one date that is named with '-teenth' in every month.

Given examples of a meetup dates, each containing a month, day, year, and descriptor calculate the date of the actual meetup. For example, if given "The first Monday of January 2017", the correct meetup date is 2017/1/2.

Setup

There are two different methods of getting set up to run the tests with Objective-C:

  • Create an Xcode project with a test target which will run the tests.
  • Use the ruby gem objc as a test runner utility.

Both are described in more detail here: http://exercism.io/languages/objective-c

Submitting Exercises

When submitting an exercise, make sure your solution file is in the same directory as the test code.

The submit command will look something like:

exercism submit <path-to-exercism-workspace>/objective-c/meetup/Meetup.m

You can find the Exercism workspace by running exercism debug and looking for the line beginning with Workspace.

Source

Jeremy Hinegardner mentioned a Boulder meetup that happens on the Wednesteenth of every month https://twitter.com/copiousfreetime

Submitting Incomplete Solutions

It's possible to submit an incomplete solution so you can see how others have completed the exercise.

MeetupTest.m

#import <XCTest/XCTest.h>

#if __has_include("MeetupExample.h")
# import "MeetupExample.h"
# else
# import "Meetup.h"
#endif

@interface MeetupTest : XCTestCase

@end

@implementation MeetupTest

- (void)testMonteenthOfMay2013 {
    NSDate *date = [[[Meetup alloc] initWithYear:2013 andMonth:5]
                    dayForDayOfWeek:MeetupDayOfWeekMonday andOptions:MeetupOptionsTeenth];
    XCTAssertEqualObjects(date, [self dateForMonth:5 day:13 year:2013]);
}

- (void)testSaturteenthOfFebruary2013 {
    NSDate *date = [[[Meetup alloc] initWithYear:2013 andMonth:2]
                    dayForDayOfWeek:MeetupDayOfWeekSaturday andOptions:MeetupOptionsTeenth];
    XCTAssertEqualObjects(date, [self dateForMonth:2 day:16 year:2013]);
}

- (void)testFirstTuesdayOfMay2013 {
    NSDate *date = [[[Meetup alloc] initWithYear:2013 andMonth:5]
                    dayForDayOfWeek:MeetupDayOfWeekTuesday andOptions:MeetupOptionsFirst];
    XCTAssertEqualObjects(date, [self dateForMonth:5 day:7 year:2013]);
}

- (void)testSecondMondayOfApril2013 {
    NSDate *date = [[[Meetup alloc] initWithYear:2013 andMonth:4]
                    dayForDayOfWeek:MeetupDayOfWeekMonday andOptions:MeetupOptionsSecond];
    XCTAssertEqualObjects(date, [self dateForMonth:4 day:8 year:2013]);
}

- (void)testThirdThursdayOfSeptember2013 {
    NSDate *date = [[[Meetup alloc] initWithYear:2013 andMonth:9]
                    dayForDayOfWeek:MeetupDayOfWeekThursday andOptions:MeetupOptionsThird];
    XCTAssertEqualObjects(date, [self dateForMonth:9 day:19 year:2013]);
}

- (void)testFourthSundayOfMarch2013 {
    NSDate *date = [[[Meetup alloc] initWithYear:2013 andMonth:3]
                    dayForDayOfWeek:MeetupDayOfWeekSunday andOptions:MeetupOptionsFourth];
    XCTAssertEqualObjects(date, [self dateForMonth:3 day:24 year:2013]);
}

- (void)testLastThursdayOfOctober2013 {
    NSDate *date = [[[Meetup alloc] initWithYear:2013 andMonth:10]
                    dayForDayOfWeek:MeetupDayOfWeekThursday andOptions:MeetupOptionsLast];
    XCTAssertEqualObjects(date, [self dateForMonth:10 day:31 year:2013]);
}

- (void)testLastWednesdayOfFebruary2012 {
    NSDate *date = [[[Meetup alloc] initWithYear:2012 andMonth:2]
                    dayForDayOfWeek:MeetupDayOfWeekWednesday andOptions:MeetupOptionsLast];
    XCTAssertEqualObjects(date, [self dateForMonth:2 day:29 year:2012]);
}

- (void)testFirstFridayOfDecember2012 {
    NSDate *date = [[[Meetup alloc] initWithYear:2012 andMonth:12]
                    dayForDayOfWeek:MeetupDayOfWeekFriday andOptions:MeetupOptionsFirst];
    XCTAssertEqualObjects(date, [self dateForMonth:12 day:7 year:2012]);
}

#pragma mark - Helper method

- (NSDate *)dateForMonth:(int)month day:(int)day year:(int)year {
    NSDateComponents *components = [[NSDateComponents alloc] init];
    components.month = month;
    components.day = day;
    components.year = year;
    
    return [[NSCalendar currentCalendar] dateFromComponents:components];
}

@end

Meetup.h

#import <Foundation/Foundation.h>


typedef NS_ENUM(NSUInteger, MeetupDay) {
    MeetupDayOfWeekSunday = 1,
    MeetupDayOfWeekMonday,
    MeetupDayOfWeekTuesday,
    MeetupDayOfWeekWednesday,
    MeetupDayOfWeekThursday,
    MeetupDayOfWeekFriday,
    MeetupDayOfWeekSaturday,
};

typedef NS_ENUM(NSUInteger, MeetupOption) {
    MeetupOptionsFirst = 0,
    MeetupOptionsSecond = 7,
    MeetupOptionsThird = 14,
    MeetupOptionsFourth = 21,
    MeetupOptionsLast,
    MeetupOptionsTeenth,
};

@interface Meetup : NSObject

- (instancetype)initWithYear:(NSInteger)year andMonth:(NSInteger)month;
- (NSDate *)dayForDayOfWeek:(MeetupDay)dayOfWeek andOptions:(MeetupOption)option;

@end

Meetup.m

#import "Meetup.h"

@interface Meetup ()

@property (nonatomic, assign) NSInteger year;
@property (nonatomic, assign) NSInteger month;
@property (nonatomic, assign) NSInteger day;

@end

@implementation Meetup

- (instancetype)initWithYear:(NSInteger)year andMonth:(NSInteger)month {
    if (self = [super init]) {
        self.year = year;
        self.month = month;
    }
    return self;
}

- (NSDate *)dayForDayOfWeek:(MeetupDay)dayOfWeek andOptions:(MeetupOption)option {
    NSDateComponents *components = [[NSDateComponents alloc] init];
    components.year = self.year;
    components.month = self.month;
    components.day = 1;
    
    NSCalendar *calendar = [NSCalendar currentCalendar];
    NSDateComponents *dateComponents = [calendar components:NSCalendarUnitWeekday fromDate:[calendar dateFromComponents:components]];
    NSInteger day = 1;
    // first dayOfWeek
    if (dayOfWeek >= dateComponents.weekday) {
        day += (dayOfWeek - dateComponents.weekday);
    } else {
        day += (dayOfWeek + 7 - dateComponents.weekday);
    }
    
    if (option == MeetupOptionsLast) {
        NSInteger days = [calendar rangeOfUnit:NSCalendarUnitDay inUnit:NSCalendarUnitMonth forDate:[calendar dateFromComponents:components]].length; // days in month
        if (day + 28 > days) {
            day += 21;
        } else {
            day += 28;
        }
    } else if (option == MeetupOptionsTeenth) {
        if (dayOfWeek >= dateComponents.weekday && dateComponents.weekday != 1) {
            day += 14;
        } else {
            day += 7;
        }
    } else {
        day += option;
    }
    
    components.day = day;
    return [calendar dateFromComponents:components];
}

@end

Community comments

Find this solution interesting? Ask the author a question to learn more.

What can you learn from this solution?

A huge amount can be learned from reading other people’s code. This is why we wanted to give exercism users the option of making their solutions public.

Here are some questions to help you reflect on this solution and learn the most from it.

  • What compromises have been made?
  • Are there new concepts here that you could read more about to improve your understanding?