+ (NSCalendar*)getGregorianCalendarInstance {
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
return calendar;
}
+ (NSInteger)currentGregorianWeekOfYear:(NSDate*) date {
NSCalendar *gregorianCalendar = [self getGregorianCalendarInstance];
gregorianCalendar.firstWeekday = 2; // Monday = 2
NSDateComponents *components = [gregorianCalendar components:NSCalendarUnitWeekOfYear fromDate:date];
NSUInteger weekOfYear = [components weekOfYear];
return weekOfYear;
}
+ (NSInteger)currentGregorianYear:(NSDate*) date {
NSCalendar *gregorianCalendar = [self getGregorianCalendarInstance];
gregorianCalendar.firstWeekday = 2;
[gregorianCalendar setTimeZone:[NSTimeZone defaultTimeZone]];
gregorianCalendar.locale = [NSLocale localeWithLocaleIdentifier:#"en_US_POSIX"];
NSDateComponents *comps = [gregorianCalendar components: NSCalendarUnitYear fromDate:date];
NSInteger year = [comps year];
return year;
}
week number returns 52 instead of 1 in currentGregorianWeekOfYear function and year returns 2019 instead of 2020 in currentGregorianYear function for date = 2019-12-30 15:00:00 +0000
Specific reason to use the Gregorian calendar is to display 1st January in the 1st week of the year. With the ISO calendar, 1st January will be indicated as the 52nd or 53rd week of the year.
I already checked multiple references but it does not solve my problem:
WeekOfYear overflowing to 1 in 53rd week in gregorian calendar?
NSDateComponents weekOfYear returns wrong value
Swift: Gregorian Calendar and weeks/weekdays - inconsistent behavior
Related
I'm trying to write a method that takes an NSDate as input and returns the first day of the week that the date falls in. I've been using NSDateComponents to try and set the year, week of year, and day of week; but I get unexpected behavior. For example :
NSDateComponents* comps = [[NSDateComponents alloc]init];
[comps setYear:2015];
[comps setWeekday:1];
[comps setWeekOfYear:1];
NSLog(#"%#\n%#\n\n", comps, [formatter stringFromDate:[calendar dateFromComponents:comps]]);
Results in:
<NSDateComponents: 0x7fbc24cc9870>
Calendar Year: 2015
Week of Year: 1
Weekday: 1
Dec 27 2016
All strangeness aside, here is my method that's supposed to return the first day of the week from an NSDate:
- (NSDate *)dateAtBeginningOfDayForDate:(NSDate *)inputDate
{
// Use the user's current calendar and time zone
NSCalendar *calendar = [NSCalendar currentCalendar];
NSTimeZone *timeZone = [NSTimeZone systemTimeZone];
[calendar setTimeZone:timeZone];
NSDateComponents *dateComps = [calendar components:NSCalendarUnitYear | NSCalendarUnitWeekOfYear | NSCalendarUnitWeekday fromDate:inputDate];
NSDateComponents* startOfWeek = [[NSDateComponents alloc]init];
// Set the time components manually
[startOfWeek setWeekOfYear:dateComps.weekOfYear];
[startOfWeek setYear:dateComps.year];
[startOfWeek setWeekday:0];
// Convert to date
NSDate *beginningOfDay = [calendar dateFromComponents:startOfWeek];
return beginningOfDay;
}
Follow this Ry’s Objective-C Tutorial...
http://rypress.com/tutorials/objective-c/data-types/dates
How to set the minimum date of an UIDatePicker to today + 5days with no Sunday included in the 5 days?
The code below first checks for the current weekday (Gregorian calendar => Sunday=1). If today is a day after Tuesday, then there will be a Sunday in today+5 days (see calculation of the offset).
After calculating the offset, it will be added to the current date.
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *currentDate = [NSDate date];
NSDateComponents *components = [gregorian components:NSWeekdayCalendarUnit fromDate:currentDate];
int offset = (components.weekday >= 3) ? 6 : 5;
NSDate *minDate = [gregorian dateByAddingUnit:NSDayCalendarUnit value:offset toDate:currentDate options:0];
//datePicker.minimumDate = minDate;
I'm trying to get the ordinal number of a week using NSCalendar so that I can calculate the number of weeks between two dates, however the method I'm using is demonstrating some weird behaviour.
I'm expecting a new week to begin every Sunday at 00:00:00, but instead it seems to happen at 23:58:45. I've tried changing the firstWeekday property of the calendar but that doesn't have any effect.
Example Code (note: 2014-03-09 is a Sunday)
- (void)testTimeWeeksBegins
{
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
// Make NSDates
NSDateComponents *comps = [[NSDateComponents alloc] init];
comps.year = 2014;
comps.month = 3;
comps.day = 9;
comps.hour = 23;
comps.minute = 58;
comps.second = 44;
NSDateComponents *compsToAdd = [[NSDateComponents alloc] init];
compsToAdd.second = 1;
NSDate *date23_58_44 = [calendar dateFromComponents:comps];
NSDate *date23_58_45 = [calendar dateByAddingComponents:compsToAdd toDate:date23_58_44 options:0];
// Calculate ordinality of week on both dates
NSUInteger ord23_58_44 = [calendar ordinalityOfUnit:NSWeekOfYearCalendarUnit inUnit:NSEraCalendarUnit forDate:date23_58_44];
NSUInteger ord23_58_45 = [calendar ordinalityOfUnit:NSWeekOfYearCalendarUnit inUnit:NSEraCalendarUnit forDate:date23_58_45];
// Output
NSLog(#"Date is %# and week number is %d", date23_58_44, ord23_58_44);
NSLog(#"Date is %# and week number is %d", date23_58_45, ord23_58_45);
}
Output
Date is 2014-03-09 23:58:44 +0000 and week number is 105043
Date is 2014-03-09 23:58:45 +0000 and week number is 105044
Am I being stupid and missing something obvious or is this a bug? I suppose my workaround would be to use a date with a time after 23:58:45, to ensure no problems in future?
I've been looking for a way to format the following NSDate object:
19 Feb 2013
Like that
18-25 Feb 2013
The 19 occurs within the week between the 18th and the 25th of Feb.
I couldn't an easy method to do so, is there build in functionality in to the NSDateFormater? should I implement it myself?
I don't think there is built in functionality in NSDateFormatter to do this. However, Apple has an example of how to get the NSDate values for the first and last days of a the week given a date. Here's their example on getting the Sunday of the current week:
NSDate *today = [[NSDate alloc] init];
NSCalendar *gregorian = [[NSCalendar alloc]
initWithCalendarIdentifier:NSGregorianCalendar];
// Get the weekday component of the current date
NSDateComponents *weekdayComponents = [gregorian components:NSWeekdayCalendarUnit
fromDate:today];
/*
Create a date components to represent the number of days to subtract from the current date.
The weekday value for Sunday in the Gregorian calendar is 1, so subtract 1 from the number of days to subtract from the date in question. (If today is Sunday, subtract 0 days.)
*/
NSDateComponents *componentsToSubtract = [[NSDateComponents alloc] init];
[componentsToSubtract setDay: 0 - ([weekdayComponents weekday] - 1)];
NSDate *beginningOfWeek = [gregorian dateByAddingComponents:componentsToSubtract
toDate:today options:0];
/*
Optional step:
beginningOfWeek now has the same hour, minute, and second as the original date (today).
To normalize to midnight, extract the year, month, and day components and create a new date from those components.
*/
NSDateComponents *components =
[gregorian components:(NSYearCalendarUnit | NSMonthCalendarUnit |
NSDayCalendarUnit) fromDate: beginningOfWeek];
beginningOfWeek = [gregorian dateFromComponents:components];
Since Sunday is not the beginning of the week in all locales, they also show how to get the beginning of the week as defined by the calendar's locale:
NSDate *today = [[NSDate alloc] init];
NSDate *beginningOfWeek = nil;
BOOL ok = [gregorian rangeOfUnit:NSWeekCalendarUnit startDate:&beginningOfWeek
interval:NULL forDate: today];
e.g. 01.10.2010 is friday => 27.09.2010 is monday.
I have no idea how to manage this one. btw: how can I calculate with dates?
For time/date calculations use NSDateComponents.
Listing 2 Getting the Sunday in the current week
NSDate *today = [[NSDate alloc] init];
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
// Get the weekday component of the current date
NSDateComponents *weekdayComponents = [gregorian components:NSWeekdayCalendarUnit fromDate:today];
/*
Create a date components to represent the number of days to subtract from the current date.
The weekday value for Sunday in the Gregorian calendar is 1, so subtract 1 from the number of days to subtract from the date in question. (If today's Sunday, subtract 0 days.)
*/
NSDateComponents *componentsToSubtract = [[NSDateComponents alloc] init];
[componentsToSubtract setDay: 0 - ([weekdayComponents weekday] - 1)];
NSDate *beginningOfWeek = [gregorian dateByAddingComponents:componentsToSubtract toDate:today options:0];
/*
Optional step:
beginningOfWeek now has the same hour, minute, and second as the original date (today).
To normalize to midnight, extract the year, month, and day components and create a new date from those components.
*/
NSDateComponents *components =
[gregorian components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit)
fromDate: beginningOfWeek];
beginningOfWeek = [gregorian dateFromComponents:components];
In later versions, there is a smarter way:
NSCalendar *cal = [NSCalendar currentCalendar];
[cal setFirstWeekday:2]; //2 is monday. 1:Sunday .. 7:Saturday don't set it, if user's locale should determine the start of a week
NSDate *now = [NSDate date];
NSDate *monday;
[cal rangeOfUnit:NSWeekCalendarUnit // we want to have the start of the week
startDate:&monday // we will write the date object to monday
interval:NULL // we don't care for the seconds a week has
forDate:now]; // we want the monday of today's week
If you actually change the weekday that represents the start of the week (Sunday vs. Monday), you should change it back after this snippet.