NSCalendar firstWeekday always 1 regardless of user preference - ios

I am attempting to get the firstWeekday as set in the user's system preferences, using [[NSCalendar currentCalendar] firstWeekday], however the value returned is always 1 (Sunday) regardless of what is set in the system preferences. Also tried the autoupdatingCurrentCalendar with the same results.
From the docs, it states [NSCalendar currentCalendar] returns a calendar formed from the settings for the current user’s chosen system locale overlaid with any custom settings the user has specified in System Preferences. From that description it sounds like I should be able to access the firstWeekday set in the user settings.
Anyone have any ideas as to why this is not returning the correct firstWeekday?

Here's the deal…
Changing the first weekday in Settings > Calendar > First Weekday ONLY adjusts the day weeks start on in Apple's Calendar app. It does NOT adjust underlying NSCalendar objects. To do that you'll have to change your phone's region under Settings > General > Date & Time > Language & Region > Region to something like Germany to test a calendar with the start of the week as Monday, or US for Sunday, etc.
(To anyone setting out to work on calendar based code: thank you for caring about localization and also here be dragons. Good luck!)

Related

Update calendar 'start of week' from phones system calendar

A user is able to set their custom start day of the week in their phone like this. Coupled with this different cultures have different days to start the week:
Australia, UK: Sunday, Monday, ..., Saturday
China: Monday, Tuesday, ..., Sunday
This means that when developing a calendar functionality we might have many different days of the week to start our calendar from (left to right) to make the user experience optimal.
We can customise a calendar to have a specific starting day of the week:
var customCalendar = Calendar(identifier: .gregorian)
customCalendar.firstWeekday = 3
The problem comes with updating my custom calendar to the user's system calendar.
Does this happen automatically when I use Calender (pulling from the user's phone) or do I need to do something custom?
Currently there is very little information that explicitly says whether something manual needs to be done to account for this. Thanks for any help anyone can give.
If you use Calendar.current and don't explicitly change its locale or its firstWeekday property then the calendar's firstWeekday property will automatically be appropriate for the user's device settings.
Code your logic based on that property value and you will be showing the correct results (assuming no bugs in your code of course).

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.

Timezone in the future

I'm working on an app that can book services in later dates in many timezones.
My problem is that when i'm getting timezone for one country, i got this timezone for now.
But this week-end we will change our timezone, and Paris (Actually +1) we'll become +2.
How can I get this timezone for a date like tuesday programmatically ?
You can use various methods.
One would be to use
- (NSInteger)secondsFromGMTForDate:(NSDate *)aDate
of NSTimeZone and get the GMT offset for a certain date and a certain timezone.
Or you can use
– daylightSavingTimeOffsetForDate:
to check wether there needs a DST offset to be accounted for.

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.

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

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?)

Resources