Subtract 7 days from current date - objective-c

It seems that I can't subtract 7 days from the current date. This is how i am doing it:
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *offsetComponents = [[NSDateComponents alloc] init];
[offsetComponents setDay:-7];
NSDate *sevenDaysAgo = [gregorian dateByAddingComponents:offsetComponents toDate:[NSDate date] options:0];
SevenDaysAgo gets the same value as the current date.
Please help.
EDIT: In my code I forgot to replace the variable which gets the current date with the right one. So above code is functional.

code:
NSDate *currentDate = [NSDate date];
NSDateComponents *dateComponents = [[NSDateComponents alloc] init];
[dateComponents setDay:-7];
NSDate *sevenDaysAgo = [[NSCalendar currentCalendar] dateByAddingComponents:dateComponents toDate:currentDate options:0];
NSLog(#"\ncurrentDate: %#\nseven days ago: %#", currentDate, sevenDaysAgo);
[dateComponents release];
output:
currentDate: 2012-04-22 12:53:45 +0000
seven days ago: 2012-04-15 12:53:45 +0000
And I'm fully agree with JeremyP.
BR.
Eugene

If you're running at least iOS 8 or OS X 10.9, there's an even cleaner way:
NSDate *sevenDaysAgo = [[NSCalendar currentCalendar] dateByAddingUnit:NSCalendarUnitDay
value:-7
toDate:[NSDate date]
options:0];
Or, with Swift 2:
let sevenDaysAgo = NSCalendar.currentCalendar().dateByAddingUnit(.Day, value: -7,
toDate: NSDate(), options: NSCalendarOptions(rawValue: 0))
And with Swift 3 and up it gets even more compact:
let sevenDaysAgo = Calendar.current.date(byAdding: .day, value: -7, to: Date())

use dateByAddingTimeInterval method:
NSDate *now = [NSDate date];
NSDate *sevenDaysAgo = [now dateByAddingTimeInterval:-7*24*60*60];
NSLog(#"7 days ago: %#", sevenDaysAgo);
output:
7 days ago: 2012-04-11 11:35:38 +0000

Swift 3
Calendar.current.date(byAdding: .day, value: -7, to: Date())

Swift operator extension:
extension Date {
static func -(lhs: Date, rhs: Int) -> Date {
return Calendar.current.date(byAdding: .day, value: -rhs, to: lhs)!
}
}
Usage
let today = Date()
let sevenDayAgo = today - 7

Swift 4.2 - Mutate (Update) Self
Here is another way the original poster can get one week ago if he already has a date variable (updates/mutates itself).
extension Date {
mutating func changeDays(by days: Int) {
self = Calendar.current.date(byAdding: .day, value: days, to: self)!
}
}
Usage
var myDate = Date() // Jan 08, 2019
myDate.changeDays(by: 7) // Jan 15, 2019
myDate.changeDays(by: 7) // Jan 22, 2019
myDate.changeDays(by: -1) // Jan 21, 2019
or
// Iterate through one week
for i in 1...7 {
myDate.changeDays(by: i)
// Do something
}

dymv's answer work great. This you can use in swift
extension NSDate {
static func changeDaysBy(days : Int) -> NSDate {
let currentDate = NSDate()
let dateComponents = NSDateComponents()
dateComponents.day = days
return NSCalendar.currentCalendar().dateByAddingComponents(dateComponents, toDate: currentDate, options: NSCalendarOptions(rawValue: 0))!
}
}
You can call this with
NSDate.changeDaysBy(-7) // Date week earlier
NSDate.changeDaysBy(14) // Date in next two weeks
Hope it helps and thx to dymv

Swift 4.2 iOS 11.x Babec's solution, pure Swift
extension Date {
static func changeDaysBy(days : Int) -> Date {
let currentDate = Date()
var dateComponents = DateComponents()
dateComponents.day = days
return Calendar.current.date(byAdding: dateComponents, to: currentDate)!
}
}

Swift 3.0+ version of the original accepted answer
Date().addingTimeInterval(-7 * 24 * 60 * 60)
However, this uses absolute values only. Use calendar answers is probably more suitable in most cases.

Swift 5
Function to add or subtract day from current date.
func addOrSubtructDay(day:Int)->Date{
return Calendar.current.date(byAdding: .day, value: day, to: Date())!
}
Now calling the function
var dayAddedDate = addOrSubtructDay(7)
var daySubtractedDate = addOrSubtructDay(-7)
To Add date pass prospective day value
To Subtract pass negative day
value

Swift 3:
A modification to Dov's answer.
extension Date {
func dateBeforeOrAfterFromToday(numberOfDays :Int?) -> Date {
let resultDate = Calendar.current.date(byAdding: .day, value: numberOfDays!, to: Date())!
return resultDate
}
}
Usage:
let dateBefore = Date().dateBeforeOrAfterFromToday(numberOfDays : -7)
let dateAfter = Date().dateBeforeOrAfterFromToday(numberOfDays : 7)
print ("dateBefore : \(dateBefore), dateAfter :\(dateAfter)")

FOR SWIFT 3.0
here is fucntion , you can reduce days , month ,day by any count
like for example here , i have reduced the current system date's year by 100 year , you can do it for day , month also
just set the counter
and store it in an array , you can this array anywhere then
func currentTime()
{
let date = Date()
let calendar = Calendar.current
var year = calendar.component(.year, from: date)
let month = calendar.component(.month, from: date)
let day = calendar.component(.day, from: date)
let pastyear = year - 100
var someInts = [Int]()
printLog(msg: "\(day):\(month):\(year)" )
for _ in pastyear...year {
year -= 1
print("\(year) ")
someInts.append(year)
}
print(someInts)
}

Related

How to convert decimal-based time to NSDate?

I have times that are represented as doubles. For example:
8:00am is 8.00
1:30pm is 13.50
6:15pm is 18.25
11:20pm is 23.333
How can I convert the doubles into an NSDate of today?
let input = 13.50
let hour = Int(input)
let minute = Int((input - Double(Int(input))) * 60)
let resultDate = NSCalendar.currentCalendar().dateBySettingHour(hour, minute: minute, second: 0, ofDate: NSDate(), options: nil)!
Get midnight today using this answer : How can I get an NSDate object for today at midnight?
NSDate *date = [NSDate date];
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
NSUInteger preservedComponents = (NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit);
date = [calendar dateFromComponents:[calendar components:preservedComponents fromDate:date]];
Then once you have the time at midnight, we will use addTimeInterval to add on the seconds from your decimal value.
int hoursToAdd = (int)timeDecimal;
int minutesToAdd = timeDecimal - hoursToAdd;
int secondsFromHours = hoursToAdd*60*60;
int secondsFromMinutes = minutesToAdd*60;
int totalSeconds = secondsFromHours + secondsFromMinutes;
NSDate *newDate = [date addTimeInterval:totalSeconds];
Should do the trick!
Start with midnight of today and add your amount of hours:
func dateFromDecimalHours(hours: Double) -> NSDate {
let midnight = NSCalendar.currentCalendar().startOfDayForDate(NSDate())
let date = midnight.dateByAddingTimeInterval(round(hours * 3600.0))
return date
}
(Most decimal fractions are not represented exactly by a Double,
that's why the time interval is rounded to seconds.)
Examples/test cases:
let fmt = NSDateFormatter()
fmt.dateFormat = "dd/MM/yyyy hh:mm.ss a"
let d1 = dateFromDecimalHours(18.25)
println(fmt.stringFromDate(d1)) // 07/05/2015 06:15.00 pm
let d2 = dateFromDecimalHours(23.3333)
println(fmt.stringFromDate(d2)) // 07/05/2015 11:20.00 pm
let d3 = dateFromDecimalHours(1.0 + 23.0/60.0 + 45.0/3600.0)
println(fmt.stringFromDate(d3)) // 07/05/2015 01:23.45 am

How to get the day of week from a given number

I want to have the day of week name for a given number, here is the pseudo-code :
getDayStringForInt:0 = sunday
getDayStringForInt:1 = monday
getDayStringForInt:2 = tuesday
getDayStringForInt:3 = wenesday
getDayStringForInt:4 = thursday
getDayStringForInt:5 = friday
getDayStringForInt:6 = saturday
I have tried with the follow code, but some thing is not working ...
- (void) setPeriodicityDayOfWeek:(NSNumber *)dayOfWeek{
gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
dateFormatter = [[NSDateFormatter alloc] init];
NSLocale *frLocale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US"];
[dateFormatter setLocale:frLocale];
[gregorian setLocale:frLocale];
NSDate *today = [NSDate date];
NSDateComponents *nowComponents = [gregorian components:NSYearCalendarUnit | NSWeekCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit fromDate:today];
[nowComponents setWeekday:dayOfWeek];
NSDate *alertDate = [gregorian dateFromComponents:nowComponents];
[dateFormatter setDateFormat:#"EEEE"];
NSLog(#"Day Of Week : %# - Periodicity : %#", dayOfWeek, [dateFormatter stringFromDate:alertDate]);
alert.periodicity = [dateFormatter stringFromDate:alertDate];
}
My log is very strange :
Day Of Week : 0 - Periodicity : monday
Day Of Week : 1 - Periodicity : wenesday
Day Of Week : 2 - Periodicity : friday
Day Of Week : 3 - Periodicity : friday
Day Of Week : 4 - Periodicity : tuesday
Day Of Week : 5 - Periodicity : sunday
Day Of Week : 6 - Periodicity : sunday
Any idea ? any better solution ...
Since this has become the accepted answer, I'll post the "right" solution here too. Credits to Rob's answer.
The whole thing can simply be achieved using the [shortWeekdaySymbols][1] method of NSDateFormatter, so the full solution boils down to
- (NSString *)stringFromWeekday:(NSInteger)weekday {
NSDateFormatter * dateFormatter = [NSDateFormatter new];
dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US"];
return dateFormatter.shortWeekdaySymbols[weekday];
}
Original answer
Beware, you're passing a pointer to NSNumber to a method that requires a NSInteger.
The compiler is not warning you since a pointer is indeed an integer, just not the one you would expect.
Consider this simple test:
- (void)foo:(NSInteger)a {
NSLog(#"%i", a);
}
- (void)yourMethod {
[self foo:#1]; // #1 is the boxed expression for [NSNumber numberWithInt:1]
}
This prints something like 185035664, which is the pointer value, i.e. NSNumber * when cast to NSInteger.
You should either use [dayOfWeek integerValue] or directly turn dayOfWeek into a NSInteger in your method signature.
Also I think you're getting something else wrong: from the doc of setWeekday:
Sets the number of weekday units for the receiver. Weekday units are
the numbers 1 through n, where n is the number of days in the week.
For example, in the Gregorian calendar, n is 7 and Sunday is
represented by 1.
Sunday is 1, so you'd better check the correspondence with your representation too.
See https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSDateFormatter_Class/Reference/Reference.html#//apple_ref/occ/instm/NSDateFormatter/weekdaySymbols
Simply use weekdaySymbols to retrieve the dayname.
Thanx to Every one, here is a clean response :
/**
* getting the day of week string for a given day of week number
*
* #param dayOfWeekNumber 0 return sunday, 6 return saturday
*
* #return a string corresponding at the given day of week.
*/
- (NSString*) getDayOfWeekStringForDayOfWeek:(NSInteger)dayOfWeek{
return [[dateFormatter shortWeekdaySymbols] objectAtIndex:dayOfWeek];
}

NSDatePicker with date in yy to yyyy format

I have as NSDatePicker, where I enter 0023 and I expect it to change it to 2023. My logic is to convert the yy to yyyy based on +-50 years.
But the default behavior of NSDatePicker changes it to 0023 etc.
What I need to do to show in yyyy format with nearest 50 years range.
Is there any way to do it through Interface Builder or through codes.
Your help will be highly appreciable.
It does not "change" 0023 to 0023, it leaves it at 0023, which is correct the correct behaviour. You'd need to manually check and fix this yourself. Maybe like (untested):
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar
components:NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit
fromDate:myPossiblyIncorrectDate
];
NSDate *correctedDate;
if ([components year] < 100) {
NSUInteger currentYearLastDigits = 13; // Insert logic to get current year here.
NSUInteger yearLastDigits = [components year];
if (yearLastDigits > currentYearLastDigits) {
[components setYear:1900 + yearLastDigits];
} else {
[components setYear:2000 + yearLastDigits];
}
correctedDate = [calendar dateFromComponents:components];
} else {
correctedDate = myPossiblyIncorrectDate;
}
Depending on how exact you need this to be, you might want to get/set more components. See the NSCalendar constants.
But it would be better to catch the wrong year number before the number is even interpreted as year number since the date might be invalid otherwise.

Is the iOS Do Not Disturb Bug Causing this Bug?

I am trying to find out if the recent Do Not Disturb bug (Ars Technica link) is affecting my code. I am trying to get the date and timestamp for midnight the previous Monday. Since I am writing this on a Monday, I would expect to get today's date (January 7, 2013), yet I am January 4, 2013.
I am following the guide posted by Apple, but I am trying to modify it to find the previous Monday, instead of Sunday.
+(NSTimeInterval)StartOfWeekMonday {
NSTimeInterval finalTime = -1;
NSInteger weekday;
NSDate *monday = 0;
NSCalendar *greg = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *weekdays = [greg components:NSWeekdayCalendarUnit fromDate:[NSDate date]];
NSDateComponents *subtract = [[NSDateComponents alloc] init];
NSDateComponents *final = 0;
weekday = ( weekdays.weekday == 1 ) ? 6 : weekdays.weekday;
[subtract setDay:(0 - weekday - 1)];
monday = [greg dateByAddingComponents:subtract toDate:[NSDate date] options:0];
final = [greg components:(NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit) fromDate:monday];
monday = [greg dateFromComponents:final];
#ifdef DEBUG
NSLog( #"%s - %d -> Weekday: %d", __FILE__, __LINE__, weekday );
NSLog( #"%s - %d -> Monday: %#", __FILE__, __LINE__, [monday descriptionWithLocale:[NSLocale currentLocale]] );
#endif
finalTime = [monday timeIntervalSince1970];
return finalTime;
}
My log out put below, the weekday is correct (I am writing this on a Monday), yet the date is obviously wrong, it should be Monday: Monday, January 7, 2013, 12:00 AM
2013-01-07 15:07:33.792 MY-APP[5524:14c03] Weekday: 2
2013-01-07 15:07:36.757 MY-APP[5524:14c03] Monday: Friday, January 4, 2013, 12:00:00 AM Eastern Standard Time
This is being in the simulator right now, but all my other date calculations are giving the expected values.
Is it likely that I am being affected by the recent Do Not Disturb Bug and will have to wait for tomorrow (January 8, 2013) to see the expected results, or am I missing something entirely different?
The issue was with how to calculate the subtraction. Either I completely mis understood the example provided by Apple, or it was not clear enough. The solution for calculating the subtraction was as follows:
weekday = ( weekdays.weekday == 1 ) ? 8 : weekdays.weekday;
toSubtract = ( 2 - weekday );
[subtract setDay:toSubtract];
Running various tests produced the proper "Monday." In the end, this had nothing to do with the date bug affecting Do Not Disturb.

How to get the difference between two dates?

I have two dates in format(MM/dd/yyyy hh:mm:ss:SS). For the both dates I have converted the two dates to strings by using (stringFromDate) method. But I could not get the difference between them and show them in my console. Please give me an idea how I should get it?
Thank you.
Example
NSDate *today = [NSDate date];
NSTimeInterval dateTime;
if ([visitDate isEqualToDate:today]) //visitDate is a NSDate
{
NSLog (#"Dates are equal");
}
dateTime = ([visitDate timeIntervalSinceDate:today] / 86400);
if(dateTime < 0) //Check if visit date is a past date, dateTime returns - val
{
NSLog (#"Past Date");
}
else
{
NSLog (#"Future Date");
}
Keep the dates as dates, get the difference between them, then print the difference.
From the docs on NSCalendar and assuming gregorian is an NSCalendar:
NSDate *startDate = ...;
NSDate *endDate = ...;
unsigned int unitFlags = NSMonthCalendarUnit | NSDayCalendarUnit;
NSDateComponents *comps = [gregorian components:unitFlags fromDate:startDate toDate:endDate options:0];
int months = [comps month];
int days = [comps day];
Generally I see day delta calculations handled by converting day/year values into flat days (usually days since some starting epoch, like 01/01/1970).
To aid in this, I've found it helpful to create a table of days into the year that each month starts. Here's a class I used for this recently.
namespace {
// Helper class for figuring out things like day of year
class month_database {
public:
month_database () {
days_into_year[0] = 0;
for (int i=0; i<11; i++) {
days_into_year[i+1] = days_into_year[i] + days_in_month[i];
}
};
// Return the start day of the year for the given month (January = month 1).
int start_day (int month, int year) const {
// Account for leap years. Actually, this doesn't get the year 1900 or 2100 right,
// but should be good enough for a while.
if ( (year % 4) == 0 && month > 2) {
return days_into_year[month-1] + 1;
} else {
return days_into_year[month-1];
}
}
private:
static int const days_in_month[12];
// # of days into the year the previous month ends
int days_into_year[12];
};
// 30 days has September, April, June, and November...
int const month_database::days_in_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
month_database month;
}
As you can see from the start_day method, the main issue you are going to be wrestling with is how many leap days are contained in your range. Within our epoch the calculation I used there is good enough. The actual rule for which years contain leap days is discussed here.
February 29 in the Gregorian calendar,
the most widely used today, is a date
that occurs only once every four
years, in years evenly divisible by 4,
such as 1976, 1996, 2000, 2004, 2008,
2012 or 2016 (with the exception of
century years not divisible by 400,
such as 1900).
If you just want the difference in days, you can do this. (Based on mihir mehta's answer.)
const NSTimeInterval kSecondsPerDay = 60 * 60 * 24;
- (NSInteger)daysUntilDate:(NSDate *)anotherDate {
NSTimeInterval secondsUntilExpired = [self timeIntervalSinceDate:anotherDate];
NSTimeInterval days = secondsUntilExpired / kSecondsPerDay;
return (NSInteger)days;
}