The common question on stackoverflow is how to get the Day of Year from a date but how to you get the date from the Day of Year?
I'm using the following code to generate the Day of Year but how to I do the converse?
// Calculate Day of the Year
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSUInteger dayOfYear = [gregorian ordinalityOfUnit:NSDayCalendarUnit inUnit:NSYearCalendarUnit forDate:[NSDate date]];
setDayOfYear = dayOfYear;
return setDayOfYear;
Assuming you know the year you want and the actual time of the date doesn't matter and you have the correct locale and time zones set up, you can just convert the day of the year and year from components back into a date. Again, you may need to decide what your application needs to do about the time component and you have to make sure that the day and year actually make sense for the calendar, but assuming the gregorian calendar you listed in your example, and the 200th day of 2013 (19 July, 2013), you could so something like this:
NSDateComponents* components = [[NSDateComponents alloc] init];
[components setDay:200];
[components setYear:2013];
NSDate* july19_2013 = [gregorian dateFromComponents:components];
If I were to run this, I'd get a date that's 19 July, 2013 # 07:00 since my current locale is in a time zone equiv of America/Los_Angeles and I didn't configure the calendar.
Related
This question already has an answer here:
Programmatically getting the date "next Sunday at 5PM"
(1 answer)
Closed 8 years ago.
It's clear how can I calculate the time between two exact date, but I would like to know the date between the actual date and the next monday 2:00 PM.
As an instance, users can reserve places for yoga classes, there is a class that starts on every monday 2:00 PM. So how can I calculate the date of next monday compared to [NSDate date]? I would like to display the remaining time until the next class.
// Date of the next class - how can i get this date?
// NSDate *nextCourse = [NSDate ??];
NSCalendar *deviceCalendar = [NSCalendar autoupdatingCurrentCalendar];
NSDate *date2 = [[NSDate alloc] initWithTimeInterval:nextCourse sinceDate:date1];
unsigned int unitFlags = NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
NSDateComponents *conversionInfo = [deviceCalendar components:unitFlags fromDate:date1 toDate:date2 options:0];
I can recommend a third party library called DateTools, https://github.com/MatthewYork/DateTools.
Specifically, you can use the: daysUntil:, hoursUntil:, minutesUntil: methods.
For example:
double hoursUntilClass = [date2 hoursUntil];
I'd like to group dates for a given week, with the starting day being what the user chooses in their preferences.
For example my preference may be that my work week starts on a Friday, and so Friday to Thursday should be my week.
Sunday-Saturday. Monday-Sunday, etc.
So I'd like to present the user with a date picker, and although they can pick any calendar day, I'd like to have the collection of
dates start with their starting day.
For example if I pick a random Wednesday next month, and my preferences are for a starting work week of Monday, then my collection of dates
should start at Monday. The code must be able to walk backwards 2 days, find that monday, then walk forwards until Sunday.
My strategy was to do just that - loop backwards until the start date is found and simply add 6 days to end on a Saturday.
Before I go about it this way, is there a better way (or maybe some sort of specifics in iOS that would make this easier for me than somewhere else)?
Examine the NSCalendar class. In particular is the method: setFirstWeekday:.
Example code:
NSDate *today = [NSDate date]; // Or a date of your choice
NSLog(#"today: %#", today);
NSCalendar *caledar = [NSCalendar currentCalendar];
[caledar setFirstWeekday:5]; // Sunday is 1
NSDate *beginningOfWeek;
[caledar rangeOfUnit:NSWeekCalendarUnit
startDate:&beginningOfWeek
interval:NULL
forDate:today];
NSLog(#"beginningOfWeek: %#", beginningOfWeek);
NSLog output:
today: 2014-07-22 14:45:01 +0000
beginningOfWeek: 2014-07-17 04:00:00 +0000
Have you looked at NSDateComponents? You can specify a specific day of the week.
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *pickedDateComponents = [calendar components:NSCalendarUnitWeekday fromDate:pickedDate];
NSInteger saturday = 7; // In the Gregorian calendar, 1 is Sunday, 2 is Monday, etc..
NSDateComponents *daysUntilSaturdayComponents = [NSDateComponents new];
daysUntilSaturdayComponents.weekday = saturday - pickedDateComponents.weekday;
NSDate *saturdayAfterPickedDate = [calendar dateByAddingComponents:daysUntilSaturdayComponents toDate:pickedDate options:0];
Given a date (for example today 4 Feb 2014), I would like to get a list of NSDate instances that go from Monday 27 Jan 2014 to Sunday 2 Mar 2014.
Basically all the dates in the current month, plus the dates from the last week of the previous month, and the first week of the next month, if they share the same week with some of the dates in the current month.
How can I achieve this?
I can think of a way to obtain this (pseudo-code below), but it's way too long and complicated. Is there any simpler way, like a method that the SDK provides to short cut?
Extract the month component from [NSDate date] (today)
Construct the first day of the month
Calculate its weekday
If it's Wednesday (3rd day of the week) then add today-1, today-2 to the list and so on
Repeat from step 2, but with the last day of the month
Also to all the elitists out there, just because I'm not posting any code, doesn't mean this is not a coding question. The problem is real (construct a calendar grid of a month), and finding the right algorithm/method before coding is much better than playing around and manually do the maths with NSDate and NSCalendar (very error prone, as I will need to take into account all the weird cases). I figure many people have already encountered this same problem and if they could share some pointers, great. If you don't want to answer, no need to reply.
I'm going to post very general code. You are going to need to make it specific to your needs.
//Setup the calendar object
NSCalendar *calendar = [NSCalendar currentCalendar];
//Get the current date's month
NSUInteger month = [dateComponents month];
//Create an NSDate for the first and last day of the month
NSDateComponents *comp = [calendar components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:[NSDate date]];
[comp setDay:1];
NSDate *firstOfMonth = [calendar dateFromComponents:comp];
[comp setMonth:[comp month]+1];
[comp setDay:0];
NSDate *lastOfMonth = [calendar dateFromComponents:comp];
//Now get the first and last week number from there
NSUInteger unitFlags = NSWeekCalendarUnit;
//Create a date component object from today's date.
NSDateComponents *firstDateComponents = [calendar components:unitFlags
fromDate:firstOfMonth // for current date
options:0];
NSDateComponents *lastDateComponents = [calendar components:unitFlags
fromDate:lastOfMonth // for current date
options:0];
NSUInteger firstWeek = [firstDateComponents week];
NSUInteger lastWeek = [lastDateComponents week];
Now that you have the first and last weeks you can start at the first day of the first week and go through the last day of the last week to set up your calendar. Good luck.
Swift 5:
extension Date {
var startOfMonth: Date {
let calendar = Calendar(identifier: .gregorian)
let components = calendar.dateComponents([.year, .month], from: self)
return calendar.date(from: components)!
}
var endOfMonth: Date {
var components = DateComponents()
components.month = 1
components.second = -1
return Calendar(identifier: .gregorian).date(byAdding: components, to: startOfMonth)!
}
}
let date = Date()
let firstWeek = Calendar.current.dateComponents([.weekOfYear], from: date.startOfMonth)
let lastWeek = Calendar.current.dateComponents([.weekOfYear], from: date.endOfMonth)
I have the following two date strings: (1) 24/04/2013 and (2) 19/03/2013 I'm trying to convert these dates into Islamic (Um Al Qura) dates, I'm using this code block to do so:
NSDateFormatter *df = [[NSDateFormatter alloc] init];
df.dateFormat = #"dd/MM/yyyy";
df.calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *dateInGrogrian = [df dateFromString:#"24/04/2013"];
NSDateFormatter *df2 = [[NSDateFormatter alloc] init];
NSCalendar * cal = [[NSCalendar alloc] initWithCalendarIdentifier:NSIslamicCalendar];
[df2 setCalendar:cal];
[df2 setDateFormat:#"dd/MM/yyyy"];
NSLog(#"Converted date to Islamic = %#",[df2 stringFromDate:dateInGrogrian]);
if the input string was 24/04/2013 the NSLog displayed:
Converted date to Islamic = 14/06/1434 which is correct (according to the formal Islamic calendar which is used in all Islamic countries). But if the input string was 19/03/2013 the NSLog displayed:
Converted date to Islamic = 08/05/1434 which is incorrect (according to the Islamic calendar the correct date must be 07/05/1434 which's 1 day behind).
-Notes to consider before you suggest an answer:
(1) I have tried to use the calendar identifier NSIslamicCivilCalendar instead of NSIslamicCalendar , but to no avail: one of the converted dates was correct and the other was wrong (1 day behind).
(2) I have tried to use GMT time zone like this: [df2 setTimeZone : [NSTimeZone timeZoneWithName:#"GMT"]]; , this produced a correct converted date for day (2) but incorrect for day (1) (1 day behind).
(3) I have tried combinations of solutions: NSIslamicCivilCalendar with / without GMT time zone, NSIslamicCalendar with / without GMT time Zone, but also to no avail ...
can anybody provide a code block that satisfies both dates ? so I ensure that any provided gregorian date string is correctly converted into Islamic date string.
thank you so much.
After printing out all the dates from the last 4 years it seems that Apple uses a somewhat accepted formula for mathematically calculating the Islamic Calendar, since as Moxy pointed out, the actual calendar is not based on scientific days but instead a lunar approximation.
This formula is that all odd numbered months have 30 days and all even numbered months have 29 days with an extra day added to the last month in any year in which the number year mod 30 is one of the following: 2, 5, 7, 10, 13, 16, 18, 21, 24, 26, or 29.
The result is an average month length of 29.53056 days, which is quite close to the lunar month of 29.53059 days.
This formula has been used elsewhere in computers, as it is the only method to calculate the date without using a lookup table for every year in history. As such unless you write the lookup table yourself, this will be as accurate as you can get for all dates going backwards and forwards.
// Create a Gregorian Calendar
NSCalendar *gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
// Set up components of a Gregorian date
NSDateComponents *gregorianComponents = [[NSCalendar currentCalendar] components:NSDayCalendarUnit | NSMonthCalendarUnit | NSYearCalendarUnit fromDate:[NSDate date]];
NSLog(#"[In Gregorian calendar ->] Day: %ld, Month: %ld, Year:%ld",
(long)[gregorianComponents day],
(long)[gregorianComponents month],
(long)[gregorianComponents year]);
gregorianComponents.day = [gregorianComponents day];
gregorianComponents.month = [gregorianComponents month];
gregorianComponents.year = [gregorianComponents year];
// Create the date
NSDate *date = [gregorianCalendar dateFromComponents:gregorianComponents];
// Then create an Islamic calendar
NSCalendar *hijriCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSIslamicCivilCalendar];
// And grab those date components for the same date
NSDateComponents *hijriComponents = [hijriCalendar components:(NSDayCalendarUnit |
NSMonthCalendarUnit |
NSYearCalendarUnit)
fromDate:date];
NSLog(#"[In Hijri calendar ->] Day: %ld, Month: %ld, Year:%ld",
(long)[hijriComponents day],
(long)[hijriComponents month],
(long)[hijriComponents year]);
How can I find out the Date of Monday if I pass the week number. For example, I need the Monday of the Week 24 of the year
Fill out a NSDateComponents object with the information you have. Then you can ask the current NSCalendar what date corresponds to those components.
NSDateComponents *components = [NSDateComponents new];
components.weekday = 2;
components.weekOfYear = 24;
components.year = 2012;
NSDate *date = [[NSCalendar currentCalendar] dateFromComponents: components];
The weekday property starts with Sunday = 1.
If you are on OS X 10.7 or newer you should use the property yearForWeekOfYear instead of year.