NSCalendar set firstWeekDay to monday but results are different - ios

I am trying to get the beginning date of a month.
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"begining of month: %# from today", [self beginningOfMonth:[NSDate date]]);
}
- (NSDate *)beginningOfMonth:(NSDate *)date {
NSCalendar *calendar = [NSCalendar currentCalendar];
calendar.locale = [NSLocale currentLocale];
calendar.timeZone = [NSTimeZone defaultTimeZone];
calendar.firstWeekday = 2;
NSDateComponents *componentsCurrentDate = [calendar components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitWeekday|NSCalendarUnitWeekOfMonth fromDate:date];
NSDateComponents *componentsNewDate = [NSDateComponents new];
componentsNewDate.year = componentsCurrentDate.year;
componentsNewDate.month = componentsCurrentDate.month;
componentsNewDate.weekOfMonth = 1;
componentsNewDate.weekday = calendar.firstWeekday;
return [calendar dateFromComponents:componentsNewDate];
}
But the console outputs is 2015-06-05 10:41:54.544 Test[1119:25066] begining of month: 2015-05-31 16:00:00 +0000
I just looked the calendar, it should be 2015-06-01 but it shows 2015-05-31. And I did set firstWeekday to 2, so it's Monday.

It seems you are getting the right result. Depending on the time zone of your Xcode installation, the console will output a different date.
Try using a date formatter in NSLog.
NSDateFormatter *f = [[NSDateFormatter alloc] init];
NSDate *firstMonday = [self beginningOfMonth:[NSDate date];
NSLog(#"First Monday of month: %#", [f stringFromDate:firstMonday]);

Related

Getting date of week of year

I want to get start date of week from its number with following code:
+ (NSDate *)dateOfWeek:(NSInteger)weekOfYear year:(NSInteger)year {
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setFirstWeekday:2]; // monday
calendar.minimumDaysInFirstWeek = 4; // iso 8601
NSDateComponents *components = [[NSDateComponents alloc] init];
components.year = year;
components.weekOfYear = weekOfYear;
[components setWeekday:2]; // monday
NSDate *date = [calendar dateFromComponents:components];
return date;
}
If year = 2017 and weekOfYear = 52 (or other valid numbers) date is correct:
2017-12-24 21:00:00 +0000
if year = 2018 and weekOfYear = 2 date is correct too:
2018-01-07 21:00:00 +0000
but if year = 2018 and weekOfYear = 1 date is incorrect:
2018-12-30 21:00:00 +0000
it must be 2017-12-31 21:00:00 +0000.
There is a second way to get dates using NSDateFormatter:
NSString *dateString = [NSString stringWithFormat:#"%li %li", (long)year, (long)weekOfYear];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = #"yyyy ww";
NSDate *date = [dateFormatter dateFromString:dateString];
NSLog(#"%#", [date description]);
But it works with the same problems with year = 2018 and weekOfYear = 1!
What I`m doing wrong with getting week dates or this is Foundation bug?
It's not a Foundation bug.
You need the component yearForWeekOfYear to get the correct week of year:
components.yearForWeekOfYear = year;
The date formatter issue is actually the same, the yearForWeekOfYear specifier is Y
dateFormatter.dateFormat = #"YYYY ww";

Getting weekdays and dates for a week

I am working on an app where I need to create a weekly calendar. For this I will need days and dates of current week(Sun Sep30, Mon Oct 1, Tue Oct2 etc.). Can someone please guide me how to achieve this?
Regards
Pankaj
Here is a simple function which extracts date for all the days in this week, staring from Sunday this week to Saturday,
func formattedDaysInThisWeek() -> [String] {
// create calendar
let calendar = NSCalendar(identifier: NSCalendarIdentifierGregorian)!
// today's date
let today = NSDate()
let todayComponent = calendar.components([.Day, .Month, .Year], fromDate: today)
// range of dates in this week
let thisWeekDateRange = calendar.rangeOfUnit(.Day, inUnit:.WeekOfMonth, forDate:today)
// date interval from today to beginning of week
let dayInterval = thisWeekDateRange.location - todayComponent.day
// date for beginning day of this week, ie. this week's Sunday's date
let beginningOfWeek = calendar.dateByAddingUnit(.Day, value: dayInterval, toDate: today, options: .MatchNextTime)
var formattedDays: [String] = []
for i in 0 ..< thisWeekDateRange.length {
let date = calendar.dateByAddingUnit(.Day, value: i, toDate: beginningOfWeek!, options: .MatchNextTime)!
formattedDays.append(formatDate(date))
}
return formattedDays
}
func formatDate(date: NSDate) -> String {
let format = "EEE MMMdd"
let formatter = NSDateFormatter()
formatter.dateFormat = format
return formatter.stringFromDate(date)
}
If you call method formattedDaysInThisWeek(), the output is like this,
["Sun Oct11", "Mon Oct12", "Tue Oct13", "Wed Oct14", "Thu Oct15", "Fri Oct16", "Sat Oct17"]
Do you just need it for this week? If so, here's some code that you should be able to use:
- (NSString *)stringOfDatesOfThisWeek {
NSArray *datesOfThisWeek = [self dateOfTheWeek:[NSDate date]];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"EEE MMM d"];
NSMutableString *dateStringForThisWeek = [[NSMutableString alloc] initWithString:[formatter stringFromDate:[datesOfThisWeek firstObject]]];
for (int i = 1; i < datesOfThisWeek.count; i++) {
[dateString appendFormat:#", %#", [formatter stringFromDate:[datesOfThisWeek objectAtIndex:i]]];
}
}
- (NSArray *)datesOfTheWeek:(NSDate *)todaysDate {
NSCalendar *calendar = [NSCalendar currentCalendar];
NSInteger weekNumber = [[calendar components: NSWeekCalendarUnit fromDate:todaysDate] week];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *comp = [gregorian components:NSYearCalendarUnit fromDate:todaysDate];
[comp setWeek:weekNumber]; //Week number.
NSMutableArray *dates = [NSMutableArray new];
for (int i = 0; i < 7; i++) {
[comp setWeekday:1]; //First day of the week. Change it to 7 to get the last date of the week
NSDate *resultDate = [gregorian dateFromComponents:comp];
[dates addObject:resultDate];
}
return dates;
}
and after typing all of that without Xcode, I realized that this question was asked about Swift. I'm leaving it in case someone wants an Objective-C answer and stumbles across this.
If I understood it correctly, to get expected date format you can use NSDateFormatter with following formatter:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat:#"EEEE, MMM d";
NSLog(#"%#", [dateFormatter stringFromDate:[NSDate date]]);
You can also set locale for date formatter to get weekdays in specified language:
[dateFormatter setLocale:[NSLocale localeWithLocaleIdentifier:#"en_GB"]];
For more details please refer to Data Formatting Guide
Updated Objective - c Code of #fennelouski :
- (NSString *)stringOfDatesOfThisWeek {
NSArray *datesOfThisWeek = [self datesOfTheWeek:[NSDate date]];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"EEE MMM d"];
NSMutableString *dateStringForThisWeek = [[NSMutableString alloc] initWithString:[formatter stringFromDate:[datesOfThisWeek firstObject]]];
for (int i = 1; i < datesOfThisWeek.count; i++) {
[dateStringForThisWeek appendFormat:#", %#", [formatter stringFromDate:[datesOfThisWeek objectAtIndex:i]]];
}
return dateStringForThisWeek;
}
- (NSArray *) datesOfTheWeek:(NSDate *)todaysDate {
NSCalendar *calendar = [NSCalendar currentCalendar];
NSInteger weekNumber = [[calendar components: NSCalendarUnitWeekOfMonth fromDate:todaysDate] weekOfMonth];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSDateComponents *comp = [gregorian components:NSCalendarUnitYear fromDate:todaysDate];
[comp setWeekOfMonth:weekNumber]; //Week number.
NSMutableArray *dates = [NSMutableArray new];
for (int i = 0; i < 7; i++) {
[comp setWeekday:1]; //First day of the week. Change it to 7 to get the last date of the week
NSDate *resultDate = [gregorian dateFromComponents:comp];
[dates addObject:resultDate];
}
return dates;
}

Adding one month to NSDate

I am trying to set a start date and an end date in my app. The end date should be one month from the start date.
e.g.
start date = 1st January 2014
end date = 31st January 2014
Currently I am using the following method to add one month to the start date, but the end date becomes 1st February 2014.
dateByAddingComponents:toDate:options:
Is there a way to achieve the result I am looking for so that the end date will always be one month - 1 day from the start date?
I hope this made sense.
Thank you.
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *dateComp = [gregorian components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:[NSDate date]];
NSLog(#"Input Date: %#",[NSDate date]);
[dateComp setDay:dateComp.day - 1];
[dateComp setMonth:dateComp.month + 1];
NSDate *nextMonthMinusOneday = [gregorian dateFromComponents:dateComp];
NSLog(#"Output date %#",nextMonthMinusOneday);
Output:
Input Date: 2014-03-31 21:21:34 +0000
Output date 2014-04-30 05:00:00 +0000
Sure:
- (NSDate *)lastDayOfMonthDateForDate:(NSDate *)date {
NSDateComponents *comp = [NSDateComponents new];
comp.day = -1;
comp.month = 1;
return [[NSCalendar currentCalendar] dateByAddingComponents:comp toDate:date options:0];
}
- (NSDate *)dateForNextMonthMinusSingleDay:(NSDate *)date {
NSDateComponents *dayOffsetComponents = [[NSDateComponents alloc] init];
[dayOffsetComponents setMonth:1];
[dayOffsetComponents setDay:-1];
return [[NSCalendar currentCalendar] dateByAddingComponents:dayOffsetComponents
toDate:date
options:0];
}
- (NSDate *)dateFromMMDDYYYYString:(NSString *)string {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setLocale:[[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"]];
[formatter setDateFormat:#"MM/dd/yyyy"];
return [formatter dateFromString:string];
}
NSDate *date = [self dateForNextMonthMinusSingleDay:[self dateFromMMDDYYYYString:#"01/01/2014"]];
I have verified the above code and its working as expected.

Weekday of first day of month

I need to get the weekday of the first day of the month. For example, for the current month September 2013 the first day falls on Sunday.
At first, get the first day of current month (for example):
NSDate *today = [NSDate date];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *components = [gregorian components:(NSEraCalendarUnit | NSYearCalendarUnit | NSMonthCalendarUnit) fromDate:today];
components.day = 1;
NSDate *firstDayOfMonth = [gregorian dateFromComponents:components];
Then use NSDateFormatter to print it as a weekday:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"EEEE"];
NSLog(#"%#", [dateFormatter stringFromDate:firstDayOfMonth]);
P.S. also take a look at Date Format Patterns
Here is the solution to getting the weekday name of the first day in the current month
NSDateComponents *weekdayComps = [[NSDateComponents alloc] init];
weekdayComps = [calendar.currentCalendar components:calendar.unitFlags fromDate:calendar.today];
weekdayComps.day = 1;
NSDateFormatter *weekDayFormatter = [[NSDateFormatter alloc]init];
[weekDayFormatter setDateFormat:#"EEEE"];
NSString *firstweekday = [weekDayFormatter stringFromDate:[calendar.currentCalendar dateFromComponents:weekdayComps]];
NSLog(#"FIRST WEEKDAY: %#", firstweekday);
For the weekday index, use this
NSDate *weekDate = [calendar.currentCalendar dateFromComponents:weekdayComps];
NSDateComponents *components = [calendar.currentCalendar components: NSWeekdayCalendarUnit fromDate: weekDate];
NSUInteger weekdayIndex = [components weekday];
NSLog(#"WEEKDAY INDEX %i", weekdayIndex);
You can also increment or decrement the month if needed.
Depending on the output you need you may use NSDateFormatter (as it was already said) or you may use NSDateComponents class. NSDateFormatter will give you a string representation, NSDateComponents will give you integer values. Method weekday may do what you want.
NSDateComponents *components = ...;
NSInteger val = [components weekday];
For Swift 4.2
First:
extension Calendar {
func startOfMonth(_ date: Date) -> Date {
return self.date(from: self.dateComponents([.year, .month], from: date))!
}
}
Second:
self.firstWeekDay = calendar.component(.weekday, from: calendar.startOfMonth(Date()))

Display NSDates in terms of week

Scenario:
I have an expense tracking iOS Application and I am storing expenses from a expense detail view controller into a table view (with fetched results controller) that shows the list of expenses along with the category and amount and date. I do have a date attribute in my entity "Money" which is a parent entity for either an expense or an income.
Question:
What I want is to basically categorize my expenses for a given week, a month, or year and display it as the section header title for example : (Oct 1- Oct 7, 2012) and it shows expenses amount and related stuff according to that particular week. Two buttons are provided in that view, if I would press the right button, it will increment the week by a week (Oct 1- Oct 7, 2012 now shows Oct8 - Oct 15, 2012) and similarly the left button would decrement the week by a week.
How would I accomplish that? I am trying the following code - doesn't work.
- (void)weekCalculation
{
NSDate *today = [NSDate date]; // present date (current date)
NSCalendar* calendar = [NSCalendar currentCalendar];
NSDateComponents* comps = [calendar components:NSYearForWeekOfYearCalendarUnit |NSYearCalendarUnit|NSMonthCalendarUnit|NSWeekCalendarUnit|NSWeekdayCalendarUnit fromDate:today];
[comps setWeekday:1]; // 1: Sunday
firstDateOfTheWeek = [[calendar dateFromComponents:comps] retain];
[comps setWeekday:7]; // 7: Saturday
lastDateOfTheWeek = [[calendar dateFromComponents:comps] retain];
NSLog(#" first date of week =%#", firstDateOfTheWeek);
NSLog(#" last date of week =%#", lastDateOfTheWeek);
firstDateOfWeek = [dateFormatter stringFromDate:firstDateOfTheWeek];
lastDateOfWeek = [dateFormatter stringFromDate:lastDateOfTheWeek];
}
Code for incrementing date -
- (IBAction)showNextDates:(id)sender
{
int addDaysCount = 7;
NSDateComponents *dateComponents = [[[NSDateComponents alloc] init] autorelease];
[dateComponents setDay:addDaysCount];
NSDate *newDate1 = [[NSCalendar currentCalendar]
dateByAddingComponents:dateComponents
toDate:firstDateOfTheWeek options:0];
NSDate *newDate2 = [[NSCalendar currentCalendar]
dateByAddingComponents:dateComponents
toDate:lastDateOfTheWeek options:0];
NSLog(#" new dates =%# %#", newDate1, newDate2);
}
Suppose the week shows like this (Nov4, 2012 - Nov10, 2012) and I press the increment button, I see in the console, date changes to Nov11,2012 and Nov.17, 2012 which is right but if I press the increment button again, it shows the same date again (Nov 11, 2012 and Nov.17, 2012).
Please help me out here.
Declare currentDate as an #property in your class. And try this.
#property(nonatomic, retain) NSDate *currentDate;
Initially set
self.currentDate = [NSDate date];
before calling this method.
- (void)weekCalculation
{
NSCalendar* calendar = [NSCalendar currentCalendar];
NSDateComponents* comps = [calendar components:NSYearForWeekOfYearCalendarUnit |NSYearCalendarUnit|NSMonthCalendarUnit|NSWeekCalendarUnit|NSWeekdayCalendarUnit fromDate:self.currentDate];
[comps setWeekday:1]; // 1: Sunday
firstDateOfTheWeek = [[calendar dateFromComponents:comps] retain];
[comps setWeekday:7]; // 7: Saturday
lastDateOfTheWeek = [[calendar dateFromComponents:comps] retain];
NSLog(#" first date of week =%#", firstDateOfTheWeek);
NSLog(#" last date of week =%#", lastDateOfTheWeek);
firstDateOfWeek = [dateFormatter stringFromDate:firstDateOfTheWeek];
lastDateOfWeek = [dateFormatter stringFromDate:lastDateOfTheWeek];
}
Once the view is loaded self.currentDate value should be updated from showNextDates. Make sure it is not getting reset anywhere else.
- (IBAction)showNextDates:(id)sender
{
int addDaysCount = 7;
NSDateComponents *dateComponents = [[[NSDateComponents alloc] init] autorelease];
[dateComponents setDay:addDaysCount];
NSDate *newDate1 = [[NSCalendar currentCalendar]
dateByAddingComponents:dateComponents
toDate:firstDateOfTheWeek options:0];
NSDate *newDate2 = [[NSCalendar currentCalendar]
dateByAddingComponents:dateComponents
toDate:lastDateOfTheWeek options:0];
NSLog(#" new dates =%# %#", newDate1, newDate2);
self.currentDate = newDate1;
}
I had needed similar thing in one of my old projects and achieved it via the code below. It sets this weeks date to an NSDate variable and adds/removes 7 days from day component in each button click. Here is the code:
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"GMT"]];
NSDate *date = [NSDate date];
NSDateComponents *components = [calendar components:(NSYearCalendarUnit|NSWeekdayCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:date ];
//
[components setDay:([components day] - ([components weekday] )+2)];
self.currentDate = [calendar dateFromComponents:components];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = #"dd.MM.yyyy HH:mm:ss";
self.datelabel.text = [formatter stringFromDate:self.currentDate];
The code above calculates this week start and sets it to currentDate variable. I Have two UIButtons with UIActions named prevClick and nextClick which calls the method that sets the next or previous weekstart:
- (IBAction)prevClick:(id)sender {
[self addRemoveWeek:NO];
}
-(void)addRemoveWeek:(BOOL)add{
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar setTimeZone:[NSTimeZone timeZoneWithAbbreviation:#"GMT"]];
NSDateComponents *components = [calendar components:(NSYearCalendarUnit|NSWeekdayCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:self.currentDate ];
components.day = add?components.day+7:components.day-7;
self.currentDate = [calendar dateFromComponents:components];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
formatter.dateFormat = #"dd.MM.yyyy HH:mm:ss";
self.datelabel.text = [formatter stringFromDate:self.currentDate];
}
- (IBAction)nextClk:(id)sender {
[self addRemoveWeek: YES];
}

Resources