ðŸŽ‰ Exercism Research is now launched. Help Exercism, help science and have some fun at research.exercism.io ðŸŽ‰

# stevenhuey'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.m
//  Meetup
//
//  Created by Steve Huey on 6/21/17.
//

#import "Meetup.h"

@interface Meetup ()
@property (nonatomic, assign) NSInteger year;
@property (nonatomic, assign) NSInteger month;

- (NSDate*)dateWithYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day;
- (NSDate*)defaultDate;
- (NSDate*)defaultTeenthDate;

- (BOOL)isOrdinal:(MeetupOptions)options;
- (NSDate*)ordinalDayFor:(MeetupDayOfWeek)dayOfWeek andOptions:(MeetupOptions)options;

- (BOOL)isLast:(MeetupOptions)options;
- (NSDate*)lastDayFor:(MeetupDayOfWeek)dayOfWeek;

- (BOOL)isTeenth:(MeetupOptions)options;
- (NSDate*)teenthDayFor:(MeetupDayOfWeek)dayOfWeek;

- (NSDate*)dayBefore:(NSDate*)day;
- (NSDate*)dayAfter:(NSDate*)day;
- (NSDate*)nextMonth;

- (BOOL)isDate:(NSDate*)date onDayOfWeek:(MeetupDayOfWeek)dayOfWeek;
@end

@implementation Meetup
#pragma mark - Meetup
- (instancetype)initWithYear:(NSInteger)year andMonth:(NSInteger)month
{
self = [super init];

if (self)
{
_year = year;
_month = month;
}

return self;
}

- (NSDate*)dayForDayOfWeek:(MeetupDayOfWeek)dayOfWeek andOptions:(MeetupOptions)options
{
NSDate* day = nil;

if ([self isOrdinal:options])
{
day = [self ordinalDayFor:dayOfWeek andOptions:options];
}
else if ([self isLast:options])
{
day = [self lastDayFor:dayOfWeek];
}
else if ([self isTeenth:options])
{
day = [self teenthDayFor:dayOfWeek];
}

return day;
}

#pragma mark - Internal
- (NSDate*)dateWithYear:(NSInteger)year month:(NSInteger)month day:(NSInteger)day
{
NSDateComponents* components = [[NSDateComponents alloc] init];

components.year = year;
components.month = month;
components.day = day;;

return [[NSCalendar currentCalendar] dateFromComponents:components];
}

- (NSDate*)defaultDate
{
return [self dateWithYear:self.year month:self.month day:1];
}

- (NSDate*)defaultTeenthDate
{
return [self dateWithYear:self.year month:self.month day:13];
}

- (BOOL)isOrdinal:(MeetupOptions)options
{
return (MeetupOptionsFirst == options ||
MeetupOptionsSecond == options ||
MeetupOptionsThird == options ||
MeetupOptionsFourth == options);
}

- (NSDate*)ordinalDayFor:(MeetupDayOfWeek)dayOfWeek andOptions:(MeetupOptions)options
{
NSDateComponents* components = [[NSDateComponents alloc] init];

components.weekday = dayOfWeek;
components.weekdayOrdinal = options;

return [[NSCalendar currentCalendar] nextDateAfterDate:[self defaultDate]
matchingComponents:components
options:NSCalendarMatchNextTime];
}

- (BOOL)isLast:(MeetupOptions)options
{
return (MeetupOptionsLast == options);
}

- (NSDate*)lastDayFor:(MeetupDayOfWeek)dayOfWeek
{
NSDate* day = [self nextMonth];
do {
day = [self dayBefore:day];
} while (![self isDate:day onDayOfWeek:dayOfWeek]);

return day;
}

- (BOOL)isTeenth:(MeetupOptions)options
{
return (MeetupOptionsTeenth == options);
}

- (NSDate*)teenthDayFor:(MeetupDayOfWeek)dayOfWeek
{
NSDate* day = [self defaultTeenthDate];

while (![self isDate:day onDayOfWeek:dayOfWeek])
{
day = [self dayAfter:day];
}

return day;
}

- (NSDate*)dayBefore:(NSDate*)day
{
value:-1
toDate:day
options:NSCalendarSearchBackwards];
}

- (NSDate*)dayAfter:(NSDate*)day
{
value:1
toDate:day
options:NSCalendarMatchNextTime];
}

- (NSDate*)nextMonth
{
value:1
toDate:[self defaultDate]
options:NSCalendarMatchNextTime];
}

- (BOOL)isDate:(NSDate*)date onDayOfWeek:(MeetupDayOfWeek)dayOfWeek
{
NSDateComponents* components = [[NSCalendar currentCalendar] components:NSCalendarUnitWeekday
fromDate:date];

return (components.weekday == dayOfWeek);
}
@end``````