Translate NSCalendar.weekdaySymbols index to NSDateComponents.weekday - ios

I'm writing a feature of my iOS app that involves scheduling weekly repeating local notifications on particular days of the week. I'd like to use the NSCalendar APIs properly so I don't assume things I shouldn't. But I don't see any property on NSCalendar about how many days there are in a week.
I'm displaying days of the week using weekdaySymbols, and letting the user choose which days they want notifications on. Then I'm scheduling local notifications based on that.
The real question is: How do I translate a day's index in weekdaySymbols into the value I give to NSDateComponents for weekday?

This is a bit of a simplification, but you can think of days of the week as belonging to the Gregorian calendar, independent of what calendar is actually in use. Those calendars largely govern day/month/year arithmetic, with the days of the week proceeding independently of the particulars of each calendar's number and length of months.
If you accept that as a given, then you just need to correct for the off-by-one difference between a calendar's weekdaySymbols (indexed from 0 to 6) and NSDateComponents.weekday (a value from 1 to 7).
extension DateComponents { // NSDateComponents in Swift < 3
func weekdaySymbol(in calendar: Calendar) -> String? {
guard let weekday = self.weekday else { return nil }
return calendar.weekdaySymbols[weekday - 1]
}
}

Related

Show only dates in the mentioned range for the month using FSCalendar

I am using FSCalendar. I am able to achieve everything except below point:
1) I want to remove dates for the collection view which are not in the range of the calendar. For Eg. My calendar date ranges from the current date to the past 30 days from the current date. In today's scenario from 20th April to the 21st of May. So, I don't want to show dates from 1st to 19th of April and 22nd to the month end of May. The logic written in the library is a bit complicated for me to get it done.
I have already shared the GitHub link for the code to check out and maybe help me. I haven't shared any of my code as it is not a single file change that is needed, it includes multiple files, and that why I shared the link to the library repo. Any help would be appreciated.
After exploring more detail in code in FSCalendar, I figure that you can do it. But it's mean you have to make some changes for the library.
First in FSCalendarExtension,
- (nullable NSDate *)fs_firstDayOfMonth:(NSDate *)month
{
if (!month) return nil;
NSDateComponents *components = [self components:NSCalendarUnitYear|NSCalendarUnitMonth|NSCalendarUnitDay|NSCalendarUnitHour fromDate:month];
components.day = today;
return [self dateFromComponents:components];
}
This will get the first day of the month, you have to set it back to the current date. As well as modified all the following functions :
- (nullable NSDate *)fs_firstDayOfWeek:(NSDate *)week
- (nullable NSDate *)fs_lastDayOfWeek:(NSDate *)week
- (NSInteger)fs_numberOfDaysInMonth:(NSDate *)month
I mean that's a lot of changes. And you have to change code for library, A better way for you is creating your own calendar. It would be better.
Base to the FSCalendar, you can show one month or a week .Because of they have the regular :unit.
If you want to show the unregulated days ,you may create custom function.
But I suggest you to use FSCalendar.That's enough.

Comparing working hours of an entity per day against the date (day of the week and hours) from the device

I would like to compare the working hours per day of an entity, fetched from JSON, against the day and hour information from the device. Related to that, I have two questions:
1) What is the best/right way of saving information of working hours per day for a particular entity in a JSON? I think, its structure should be something like this:
"working_hours": {
"<DAY_OF_THE_WEEK_1>":"<WORKING_HOURS>",
"<DAY_OF_THE_WEEK_2>":"<WORKING_HOURS>",
"<DAY_OF_THE_WEEK_3>":"<WORKING_HOURS>",
"<DAY_OF_THE_WEEK_4>":"<WORKING_HOURS>",
"<DAY_OF_THE_WEEK_5>":"<WORKING_HOURS>",
"<DAY_OF_THE_WEEK_6>":"<WORKING_HOURS>",
"<DAY_OF_THE_WEEK_7>":"<WORKING_HOURS>"
}
Here, I use days of the week as keys in a dictionary. However, I'm not sure what is the best/right way to enter "<DAY_OF_THE_WEEK_N>" and "<WORKING_HOURS>" inside a JSON.
2) After fetching this information, how to compare it against the time information from the device. Basically, I need to check the day of the week and then checking whether the current from the device is within the interval of a particular <WORKING_HOURS>.
For those who ask me whether I'm asking about comparing two numbers: I don't ask about that. I need to know the right format to save working hours in JSON also taking into account the day changes.
Currently, the problem is, when I save a time like 21:00 and transform it to a Date:
let workingHoursEnd = "21:00"
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "H:mm"
dateFormatter.timeZone = TimeZone.autoupdatingCurrent
let dateFromString = dateFormatter.date(from: workingHoursEnd)
I get Jan 1, 2000 at 9:00 PM. The time format is ok, I can change it later, however, what I need is to get the current date (especially, day of the week) because I need to take into account the current day, too.
If you can answer to both questions (or even to one of them), I would appreciate your help.

How to keep track of data over various periods of time (Swift) - Counter/Habit Tracking App

I'm trying to create a simple counter/habit tracking app that allows users to see how many times they've completed a task over a certain amount of time (daily/weekly/monthly/yearly/total).
My question is: what is the best way to track variables over time such that when the user selects a time period, the variable's value can update to reflect that change?
A few examples to clarify what I mean:
A user who initially created a monthly timer to track workouts should be able to switch to a weekly timer and see the data update as needed (there should be fewer in a week than in a month).
A user who has created a daily counter should see the daily counter reset to 0 at midnight each day, with the previous day's value visible to compare.
A user who has created a "total" counter should be able to switch to any time period (daily/weekly/monthly/yearly) and see the counter update as needed.
The UI for my app is basically a custom tableview with the counter number, counter name, and the time period over which the counter number is being tracked. A detail view allows users to add to/subtract from the counter's value.
I have been wracking my brain and Google for a long time, so I'd really appreciate any help!
Each task should have a date. When app needs to query for the average per day/week/month/year you can use a NSPredicate to restrict only the results from a given time period.
For instance, here's a predicate that models the last-week scenario that I have written for an app of mine:
func lastWeekPredicate() -> NSPredicate {
let calendar = NSCalendar.currentCalendar()
let endDate = NSDate()
let startDate = calendar.dateByAddingUnit(.CalendarUnitDay, value: -7, toDate: endDate, options: nil)
return NSPredicate(format: "day >= %# AND day =< %#", argumentArray: [startDate!, endDate!])
}
Let's say you modelled your data with Core Data. Querying with this predicate would give you the results of all the tasks that were completed in the last week. The predicate can be modified to work for days, months, year, or any specified number of days.

Array of times for each day of the week in iOS

I have times that I would like to compare to the current time for each day of the week. From what I've come across, it sounds like the best thing to do would be to have an array for each day of the week with the given times I want. For example:
mondayTimes(2:00:00, 5:00:00, 9:00:00, 14:00:00)
tuesdayTimes(3:00:00, 6:00:00, 10:00:00, 15:00:00)
etc...
I want to find out the given day of the week using the current date, and then depending on what day it is, use the array of times for that given day. Then use the current time to find which time is next in the array.
Basically it is like an "alarm clock" that always has set times for every day of the week.
Do I use NSStrings to populate the dates in each array and convert them so I am able to compare them to the current time? What is the best route to go about this?
Thanks!
To get the current date, use NSDate currentDate = [NSDate date];
Then, to extract the weekday: initialize a NSCalendar of your choice, then call [calendar components:NSWeekdayCalendarUnit fromDate:currentDate];, where calendar is your calendar instance.
This produces a number between 1 and 7 (for the Gregorian calendar) where 1 is Sunday and 7 is Saturday. I would then advise you put all of your times in an array of arrays, with the 1 index containing an array of your sundayTimes, 2 containing an array of mondayTimes, ... 7 containing an array of your saturdayTimes.
Then using [allTimes objectAtIndex weekday] will return a NSArray of your times. All that's left is to compare the times, which I'm sure you can figure out.

iPhone OS4.3: NSCalendar's [ordinalityOfUnit:inUnit:forDate:] method returns different/wrong result

I've following code snippet which I'm using to deduce the first day of the week, to display in my calendar view. This code has been working without any issue, till I tested it on iPhone OS 4.3 onwards.
int firstDOW = [m_calendar ordinalityOfUnit:NSWeekdayCalendarUnit inUnit:NSWeekCalendarUnit forDate:fom]%7;
where 'fom' is the first date of the month.
When debugged the code, on iOS prior to 4.3, return value for 'ordinality' method seems to return correct value( for example if the 'fom' date falls on Friday, the value returned from above method is '5'). But on iOS >= 4.3, the return value is somehow not the correct weekday( for example, if the 'fom' date falls on Friday, the value returned from above method is '6'!).
I don't understand, whether there is any issue with my code, or it really is a bug in the above method.
Has anyone else faced this in iOS >= 4.3??
Thanks and Regards.
I learned a bit more about this method call. It appears that the ordinalityOfUnit:inUnit:forDate: method pays attention to what current locale is and what that locale considers the first day of the week to be.
For example. In the United States locale the first day of the week is considered to be Sunday while in the Ireland locale, the first day of the week is considered to be Monday.
If you are in the US locale, and ask for the ordinality of Tuesday, it will return 2 (0 for Sunday, 1 for Monday and 2 for Tuesday). In the Ireland locale, however, it will return 1 (0 for Monday and 1 for Tuesday).
In short, the ordinality of the day within the week depends on which day is considered to begin the week. In contrast, if you use the NSDateComponents API and get the day of the week from there, you always get a day relative to Sunday === 0. e.g.
NSDateComponents *components = [[self calendar] components: NSWeekdayCalendarUnit fromDate: [self startingDay]];
NSUInteger weekdayIndex = [components weekday];

Resources