Getting date from weekday - ios

I'm doing this app where the user inputs some days (Using UITableView, monday - sunday).
I then need the app to figure out which dates this matches with. Say it's the user sits on sunday the 15th and chooses monday and tuesday. The app will figure out the dates are monday 16th and tuesday 17th.
How would one go about that using NSDate and such? I know how to find a weekday using the date, but I want the opposite.
Of course it has to be the closest days, like not finding monday the 23rd, but finding 16th.
Hope that makes sense. :-)

A direct method, without using a loop:
NSUInteger targetWeekday = ...; // 1 = Sunday, 2 = Monday, ...
// Date components for today:
NSCalendar *cal = [NSCalendar currentCalendar];
NSDate *now = [NSDate date];
NSDateComponents *comp = [cal components:NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit|NSWeekdayCalendarUnit
fromDate:now];
// Adjust components for target weekday:
if (targetWeekday >= comp.weekday) {
comp.day += (targetWeekday - comp.weekday);
} else {
comp.day += (targetWeekday + 7 - comp.weekday); // Assuming 7 days per week.
}
comp.weekday = targetWeekday;
// And back to NSDate:
NSDate *targetDate = [cal dateFromComponents:comp];
Remark:
if (targetWeekday >= comp.weekday) {
comp.day += (targetWeekday - comp.weekday);
} else {
comp.day += (targetWeekday + 7 - comp.weekday); // Assuming 7 days per week.
}
can be replaced by the shorter, equivalent code
comp.day += (targetWeekday + 7 - comp.weekday) % 7;

You can do it by following a simple procedure:
Start with an NSDate that represents today
Get the day of the week from it (here is how it is done)
If the day of the week matches what's in the selected UITableViewCell, you are done.
Otherwise, add one day to NSDate (here is how it is done), and go back to step 2.

Related

How to offset NSDate with UTC timezone offset without hardcoded manual calculation

Imagine the current local time being 15:11 UTC. I retrieve a data set from the server showing the opening closing time of a business displayed like so:
{
close = {
day = 3;
time = 0200;
};
open = {
day = 2;
time = 1700;
};
I also receive a utc-offset property exposed like so: "utc_offset" = "-420”; which I imagine is a minute offset giving an hour offset of 7 hours which seems right considering the timezone I'm in is UTC and the business location's opening hours information I'm receiving is for a business in Los Angeles who are 7 hours behind.
How do I use this property to then be able to do any time calculations on it
I want to determine whether the current local time falls between the open and close time that bit I have figured out but the calculations come out wrong considering the time comparison is done in the local timezone when it needs to be offset before calculating against that time range.
I'm trying to avoid doing things like
Psuedocode:
NSDate.date hour componenent + (UTC_offset / 60 = -7 hours)
Update:
Here's how I'm currently checking if the business is open right now
if currentArmyTime.compare(String(openInfo.time)) != .OrderedAscending && currentArmyTime.compare(String(closeInfo.time)) != .OrderedDescending {
//The business is open right now, though this will not take into consideration the business's time zone offset.
}
Is it easier to offset the current time?
Before you can use the 'open' and 'close' times in date operations you need to create an NSDate from a calendar that has been set to the time zone for those times. Here's an example:
// Create calendar for the time zone
NSInteger timeOffsetInSeconds = -420 * 60;
NSTimeZone *tz = [NSTimeZone timeZoneForSecondsFromGMT:timeOffsetInSeconds];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
calendar.timeZone = tz;
// Create an NSDate from your source data
NSDateComponents *comps = [[NSDateComponents alloc] init];
comps.day = 1;
comps.month = 1;
comps.year = 2016;
comps.hour = 8;
comps.minute = 0;
NSDate *openTime = [calendar dateFromComponents:comps];
// 'openTime' can now be to compared with local time.
NSLog(#"openTime = %#", openTime); // Result is openTime = 2016-01-01 15:00:00 +0000
You should put the above code into a method that takes in the raw time and the time offset to apply.

Calculate duration between two dates(finding upcoming/old birthdays) in ios [duplicate]

This question already has answers here:
Number of days between two NSDates [duplicate]
(16 answers)
Closed 6 years ago.
How can i calculate duration between two dates. like
I am getting contacts birthday list from contacts framework. Now i want to compare Today date with user DOB value and i should display the "remaining days count"(birthday).
For Example:
In contacts i added one user like: DOB: dd/MM/yyyy -->12/04/1960
now today date is: 25/04/2016
I want to get the upcoming birthday date(duration between two dates)
o/p: 18 days
How can i get this
Try below line of code. you will get the solution.
NSDateComponents *components;
NSInteger days;
components = [[NSCalendar currentCalendar] components: NSDayCalendarUnit
fromDate: startDate toDate: endDate options: 0];
days = [components day];
Use the following
unsigned int unitFlags = NSHourCalendarUnit | NSMinuteCalendarUnit | NSDayCalendarUnit | NSMonthCalendarUnit;
NSDateComponents *conversionInfo = [currCalendar components:unitFlags fromDate:fistDate toDate:secondDate options:0];
int months = [conversionInfo month]; // to get number of months
int days = [conversionInfo day]; // to get number of days
int hours = [conversionInfo hour]; // to get hour difference
int minutes = [conversionInfo minute]; // to get hour difference
copied from Difference between two NSDates

Get NSDate from start of 7 days ago

I'm trying to do some simple 7 day history plotting. Given the current NSDate.date, I want to get the NSDate that corresponds to the start of day, 7 days ago. So basically 7 days prior to 0.00 this morning.
What I've tried, is the following:
// decompose the current date, do I need more component fields?
NSDateComponents *comps = [NSCalendar.currentCalendar components: NSDayCalendarUnit fromDate: NSDate.date];
NSLog(#"components: %#", comps);
// Back day up 7 days. Will this wrap appropriate across month/year boundaries?
comps.day -= 7;
NSDate *origin = comps.date;
NSLog(#"new date: %#", origin);
What I assumed was that by just specifying NSDayCalendarUnit, the other things would be defaults (like start of day, etc). Unfortunately, origin ends up as (null). What is the correct way to do this?
To construct a new date you should know not only a day but also a month and a year. So you should add NSYearCalendarUnit | NSMonthCalendarUnit. Also you should setup calendar and probably timezone properties of NSDateComponents's instance:
NSDateComponents *comps = [NSCalendar.currentCalendar components: NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit fromDate: NSDate.date];
comps.calendar = NSCalendar.currentCalendar;
comps.timeZone = [NSTimeZone timeZoneWithName:#"UTC"];
NSLog(#"components: %#", comps);
// Back day up 7 days. Will this wrap appropriate across month/year boundaries?
comps.day -= 7;
NSDate *origin = comps.date;
NSLog(#"new date: %#", origin);

Is there a way to detect which millennium a NSDate is in?

I have an NSDate from a string of 01/01/14. Unfortunately the strings are saved with two digits so I have no idea if the year is from 1900's or 2000's. But I want create some intelligent code to guess what millennium and century the full year is. I know for a fact (based on the application I'm creating) that the year can't be below 1900 in 99% of cases.
I have converted the date to now show four digits on but it's now being displayed as 01/01/0014.
Is there a way to detect the millennium of the NSDate as 0 and make my changes accordingly?
What I really want to do is something like this (pseudo code):
if (millennium == 0 && decade < 15 && decade > 99)
{
millennium = 2;
century = 0;
// change the date to 2000's here
}
else if (millennium == 00)
{
millennium = 1;
century = 9;
// change the date to 1900's here
}
For starters your pseudocode isn't quite right (the first if statement is an impossible condition as decade can't be less than 15 and more than 99 at the same time).
I have created a basic solution using NSDateComponents and made up my own conditions for when to change the year which you can easily change.
NSDate *date; // this is your date
NSDateComponents* components = [[NSCalendar currentCalendar] components: NSMonthCalendarUnit | NSDateCalendarUnit | NSYearCalendarUnit fromDate:date];
if([components year] < 15) // 2000 to 2015
{
[components setYear:[components year] + 2000];
}
else if([components year] < 100) // 1915 to 1999
{
[components setYear:[components year] + 1900];
}
date = [NSCalendar currentCalendar] dateFromComponents:components];
there is an oldschool stuff (from the 80s) here to convert a year in 2 digits to year in 4 digits.
int finalYear = (19 + (yearIn2Digits < 50)) * 100 + yearIn2Digits;
then you can use that finalYear value to build up the proper NSDate object.
the covered interval is always 100 years and it is up you where you'd like to draw the line. the original idea worked between 1950 and 2049 – as you see in the formula, – but you can refine it for covering better your actual bounds of years.
I wouldn't recommend hardcoding this logic.
what if you want to convert a date which is 1908 , or 2015.
A smarter way to do this is as follows :
-(BOOL)isInCurrentDecade:(NSDate*)date{
// I don't recollect the api to extract year from NSDate
NSInteger tmpYear = [date year];
NSInteger currentYear = [[NSDate date] year];
return tmpYear > currentYear%100
}
What I am doing here is that I compare 87 , 04 , 99 with current year digit's 14. and if it's between 00 and now then its current decade. This code is more robust than your's because it's relative comparison with current date
o/p of the code is as follow as of year 2014 :
87 - > NO // in 90's
99 -> NO
04 - > YES // in 2000's
12 - > YES
Edge case occurs when your date includes 1/1/14 if you want it to be filtered in current decade replace the '>' with ' >=" .
Use NSDateFormatter and its property "twoDigitStartDate". You set this to the earliest date that you want to be able to enter with a two digit year. No complicated logic needed, and easy to update. Now data entry is one thing, but storing a date "with a two digit year", that's criminal.
And it handles things like "I want to be able to store anything starting with the start of the tax year 1985 in two digits, that is April 1st 1985". Then April 1st 85 will be in 1985, while March 31st 85 will be in 2085. With no effort.

Getting number of days where a range of NSDates intersects another range of NSDates

I have a problem on getting the number of days where a range of NSDates intersects another range of NSDates.
Scenario1:
Main Range: March8 - June8
Range to check: April8 - May8
Then the number of days that intersects is the number of days from April8 - May8
Scenario2:
Main Range: March8 - June8
Range to check: Feb8 - March15
Then the number of days that intersects is the number of days from March8 - March15
Scenario3:
Main Range: March8 - June8
Range to check: May19 - June15
Then the number of days that intersects is the number of days from May19 - June8
Scenario4:
Main Range: March8 - June8
Range to check: March1 - June9
Then the number of days that intersects is the number of days from March8 - June8
I tried to use below code by first using startdate1(Range to check) and startdate2(Main Range). If positive I'll include, otherwise I won't.
Then use enddate1(Range to check) and enddate2(Main Range). If positive I'll include, otherwise I won't.
Then sum up all positive values.
This solution I read from one of the post but it doesn't look correct.
+ (NSInteger)daysBetweenTwoDates:(NSDate *)fromDateTime andDate:(NSDate*)toDateTime
{
NSDate *fromDate;
NSDate *toDate;
NSCalendar *calendar = [NSCalendar currentCalendar];
[calendar rangeOfUnit:NSDayCalendarUnit startDate:&fromDate interval:NULL forDate:fromDateTime];
[calendar rangeOfUnit:NSDayCalendarUnit startDate:&toDate interval:NULL forDate:toDateTime];
NSDateComponents *difference = [calendar components:NSDayCalendarUnit fromDate:fromDate toDate:toDate options:0];
return [difference day] + 1;
}
Your method only takes two dates, so you need to get the proper two dates to supply to that method.
Assuming they intersect at all:
To do that all you need to do is take the two start dates and compare them, then take the two end dates and compare them. The last start date and the earliest end date will govern your range of intersection.
NSDate* correctStartDate;
NSComparisonResult result = [startdate1 compare:startdate2];
if(result == NSOrderedDescending)
correctStartDate = startdate1;
else
correctStartDate = startdate2;
NSDate* correctEndDate;
NSComparisonResult result = [enddate1 compare:enddate2];
if(result == NSOrderedAscending)
correctEndDate = enddate1;
else
correctEndDate = enddate2;
Then get the number of days between those using your method.
To check if they intersect just compare the start date and the end date. If the start is after the end then they do not intersect.

Resources