How to create NSDates (begin and end of day) without using NSCalendar? - ios

I have an iPad app, using XCode 4.5, iOS 6.0 and Storyboards. I need to create a NSCompoundPredicate using a NSDate, which I am given by the user selecting from UIDatePicker. The examples I have seen show the use of NSCalendar and NSCalendarComponents, both of which use the "default" calendar.
This is the code, using one NSPredicate, which works but gets all of the records for that date and all dates in the future, which is wrong.
NSMutableArray *apptDataArray = [NSMutableArray new];
NSPredicate *predicate = [NSPredicate predicateWithFormat:#"(aStartTime = %#)", [dict objectForKey:#"selectedDate"]];
I need to use a NSCompoundPredicate because I need to get all of the records for a particular date (from 1 minute after midnight to midnight of the selected date).
Is there a way to create two NSDates (begin and end of the day) for the NSCompoundPredicate from a given NSDate, in this case: [dict objectForKey:#"selectedDate"] (which is a NSDate)? (This question is NOT a duplicate of this which uses the NSCalendar code mentioned above.)
UPDATE: updated question in bold.

While you say that you don't want to use a NSCalendar, you already are:
From the UIDatePicker Class Reference:
calendar
The calendar to use for the date picker.
#property(nonatomic, copy) NSCalendar *calendar
Discussion
The default value of this property corresponds to the user’s current calendar as configured in Settings. This is equivalent
to the value returned by calling the NSCalendar class method
currentCalendar. Setting calendar to nil is equivalent to setting it
to its default value.
Calendars specify the details of cultural systems used for reckoning
time; they identify the beginning, length, and divisions of a year.
Basically, the only way to get accurate values that you can use for a query is to use the same calendar that was used to create your NSDate. So, the short version is: Go ahead and use a calendar. In fact, use this one:
NSCalendar *cal = [NSCalendar currentCalendar];
You can't really create a meaningful NSDate object without referencing a calendar at some point. As others have pointed out, an NSDate is stored as the number of seconds since a particular date and time. Unless you feel like completely re-writing all calendar operations in order to account for things like leap years, leap seconds, etc you should use what Apple has already given us.

An NSDate represents the number of seconds since a fixed epoch. Internally, the epoch used is January 1, 2001 12:00:00AM UTC+0. Most APIs across platforms use another epoch, January 1, 1970 12:00:00AM UTC+0, called the "UNIX epoch" or "time_t epoch", so there are APIs to convert to/from that epoch as well. As a result, a date is just a single number, of type NSTimeInterval (a typedef of double.)
To get the first and last moments of a day, you need to define a "day." This is done with a calendar. Most calendars have 24-hour days, but I'm sure there's one out there that doesn't.
You say you cannot use NSCalendar because you need to work in a calendar that it does not support. Can you tell us which calendar you need to use?

To my mind its not possible (why you don't want to use NSCalendar?)

Related

Need a time object in one of my iOS app (Swift)

I am currently creating an app where I ask the user to input a time (through datePicker) and send the user a notification every day on that time.However, I noticed that datePicker only has an NSDate object, and was wondering if there was a Time object counterpart.Also, would this Time object be a good way of storing the time, or should I convert the hour and minutes to Integers for storage?
Thanks in advance!
NSDate also contains Time information within it. You can store the exact date and time using only NSDate.
NSDate is a generic representation independent of any time zone. According to the apple docs:
NSDate objects encapsulate a single point in time, independent of any particular calendrical system or time zone. Date objects are immutable, representing an invariant time interval relative to an absolute reference date (00:00:00 UTC on 1 January 2001)
NSDate is basically the number of seconds from the reference date mentioned above.
And yes NSDate is the best way for storing time and date information in your app.
Whenever you want to display the time, use NSDateFormatter to format the date and time into any format you desire and for any Time Zone you require.
Swift 3
The NSDate class has been renamed to Date in Swift 3

Best way to store the day of the week using NSDate and NSDateFormatter

I'm trying to reproduce some of the functionality of the default Clock where I let users select a repeat frequency for an alarm. The problem is that different NSCalendar settings will give you different names for the days of the week. How do I store the selected days of the week in such a way that if the user changes their calendar the frequency always falls on the right day of the week?
One solution would be to check if the calendar has changed every time the app comes into foreground, and if so, make appropriate changes from there. Probably not the most elegant solution, nor the best practice, but it could get the job done.
Take (long) [dateYouWantToRemember timeIntervalSince1970] and store that in a property file or some such. (You could use timeIntervalSinceReferenceDate, but the 1970 number is the "UNIX epoch date" and more standardized -- you can find converters online to check it.)
Later, under the (potentially) different calendar, do [NSDate dateWithTimeIntervalSince1970:theLongYouStored] and you will reconstruct the date, in the new calendar.
Now use NSCalendar/NSDateComponents to find out the new ordinal day of week of that date, and use [NSDateFormatter weekdaySymbols] to fetch a list of the weekday names. Index the list with the ordinal to fetch the new day name. Use NSDateComponents to do arithmetic on you dates to select the next date that is that day of the week, as needed for your app.

Converting time strings to dates and finding the upcoming one

In my program, I have an NSArray of various dates and times, stored as strings and formatted like this: #[#"07:23",#"18:09",#"13:55"];
When I use an NSDateFormatter to convert these to NSDates, the times are correct, but year/month/day information is added.
The arrays that I have created are columns of a bus schedule. Each entry is one timeslot for whatever stop the array represents. My application needs to take the current time: [NSDate date] and see which time from the array is next in sequence. I'm just trying to display when the very next bus will arrive.
I have thought of comparing each element of the array with the current date and time using -[NSDate's laterDate:], but the problem is that when I convert the strings to NSDate objects, it gives them some random day-month-year like 13:55:00 January 1st, 2001 which will always be before the current date, so my test won't work.
I can find some workarounds that are really tragically McGuyvered but I would prefer something clean.
What I want to know are these things:
Can I remove the day/month/year portion from the NSDate?
Is it possible to easily set the day/month/year of each object in my array to today without using NSDateComponents and NSCalendar? I can manipulate them as they enter the array.
Would it be easier to reformat the current date/time to match the day/month/year of the array?
Otherwise, is there a better, cleaner solution to find the next upcoming timeslot? I am open to changing the entire format from arrays if necessary.
Can I remove the day/month/year portion from the NSDate?
No. An NSDate is merely an instant in time that is some number of seconds since some reference date. Describing that instant in time as some year/month/day depends on the local calendar. For example, the "day of month" of [NSDate date] as I type this is 28 where I live but 29 for the same NSDate value in Japan.
Is it possible to easily set the day/month/year of each object in my
NSMutableArray to today? without using NSDateComponents and
NSCalendar?
No. That's what NSDateComponents is for.
Otherwise, is there a better, cleaner solution to find
the next upcoming timeslot? I am open to changing the entire format
from arrays if necessary.
Use NSCalendar's -components:fromDate: to get an NSDateComponents object that matches [NSDate date]. Replace the hour/minute/second components with an arrival time's hour/minute/second: this is an arrival time today. Add one to the day component: this is an arrival time tomorrow. (Weekend and holiday schedules cause extra complication; the weekday component may be useful.) Convert back to NSDate using NSCalendar's -dateFromComponents: and perform your date comparisons there.

How can I find out whether an NSDate is a business day?

How can I find out whether an NSDate is a business day? That is to say, whether or not it is a weekend according to the user's current locale and calendar settings - so not hardcoded to just be Monday to Friday?
NSCalendar has a firstWeekday property, but that just seems to be a presentational thing; it's Sunday in the US and Monday in the UK.
EDIT: I'm not worried about holidays, I just want to be able to shade the weekends of a calendar in the same way as the built-in calendar app.
Update for iOS 8 and higher:
NSCalendar now contains method - (BOOL)isDateInWeekend:(NSDate *)date
which checks whether a date falls under weekend in a particular calendar & locale.
Old answer
If you only need to shade the weekends, [NSDateComponents weekday] is your friend. This method will return 1 for Sunday and 7 for Saturday.
Fact: Most applications assume weekend = Saturday & Sunday. AFAIK this is correct for all countries using Gregorian Calendar. The only possibility covering all other calendars is to have a local database per calendar/locale and watch for changes. If such a change happens an application update is needed or new data has to be downloaded.
If we are talking about business days (not only weekends), we are talking about something that
has no clear definition (what is a business day changes between companies)
has no specification (for example - date formatting, time zones etc. has internationally accepted specifications)
is often changed by local law (e.g. holidays added)
What you need is to let the users set up your applications for their individual needs, depending on their nationality and employer.
You can get if the day is Monday to Friday, but as far as I know, there's no such things as business day for NSDate depending on the location, as for example firstWeekday, so you will need to implement it yourself.
Use NSDateComponents.
NSDate *date = [NSDate date];
NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:NSWeekdayCalendarUnit fromDate:date];
NSLog(#"Weekday: %d", dateComponents.weekday);
This will also differentiate whether the device is in a territory where Sunday or Monday are considered to be the first day of the week.

Xcode - Connect a Date Picker and a Time Picker to the same NSDate

I have a Time Picker and a Date Picker.
How to get the time included with the date in same NSDate?
I need the time between 2 dates (including time) How?
I have the code for getting time between dates, i just need help to include the time.
By default, a UIDatePicker is set to allow the user to choose a Date and a Time. The mode can be set to either Date, Time or Date and Time. As long as the mode of your UIDatePicker is set to Date and Time it will set both the date and time in the linked NSDate object.
If you really want to have two separate UIDatePickers, one set to Date and the other to Time then you will need to link them to two different NSDate objects and then have code behind to combine the two NSDates into a single NSDate using something like the code here Problem combining a date and a time into a single NSDate

Resources