I have this information:
Days Dec'15 Jan'16
---------------------
Sun 27
Mon 28
Tue 29
Wed 30
Thu 31
Fri 1
Sat 2
I have 1st Jan'16. So I have to get Fri and then the difference of days from the Sun. So, in this case, the difference should be 5. Because, before Friday there are 5 other days. So if I want to know it for 2nd Jan'16 it should be 6. And likewise.
How do I get it easy with date functions?
The following code may help you
extension Date {
func weekdayDiffence() -> Int {
return Calendar.current.dateComponents([Calendar.Component.weekday], from: self).weekday ?? 0
}
}
Example
let d = Date().weekdayDiffence()
print(d)
I'm trying to find the first day of weeks using DateTools like so:
for (NSInteger week = 46; week <= 53; week++) {
NSDate *tempDate = [NSDate dateWithString:[NSString stringWithFormat:#"2015-%d", (int)week] formatString:#"Y-w"];
NSLog(#"INFO: tempDate: %#, day: %.2d, week: %d", tempDate, (int)[tempDate day], (int)week);
}
for (NSInteger week = 1; week <= 5; week++) {
NSDate *tempDate = [NSDate dateWithString:[NSString stringWithFormat:#"2016-%d", (int)week] formatString:#"Y-w"];
NSLog(#"INFO: tempDate: %#, day: %.2d, week: %d", tempDate, (int)[tempDate day], (int)week);
}
and I get this output:
INFO: tempDate: 2015-11-07 22:00:00 +0000, day: 08, week: 46
INFO: tempDate: 2015-11-14 22:00:00 +0000, day: 15, week: 47
INFO: tempDate: 2015-11-21 22:00:00 +0000, day: 22, week: 48
INFO: tempDate: 2015-11-28 22:00:00 +0000, day: 29, week: 49
INFO: tempDate: 2015-12-05 22:00:00 +0000, day: 06, week: 50
INFO: tempDate: 2015-12-12 22:00:00 +0000, day: 13, week: 51
INFO: tempDate: 2015-12-19 22:00:00 +0000, day: 20, week: 52
INFO: tempDate: 2015-12-26 22:00:00 +0000, day: 27, week: 53
INFO: tempDate: 2015-12-26 22:00:00 +0000, day: 27, week: 1
INFO: tempDate: 2016-01-02 22:00:00 +0000, day: 03, week: 2
INFO: tempDate: 2016-01-09 22:00:00 +0000, day: 10, week: 3
INFO: tempDate: 2016-01-16 22:00:00 +0000, day: 17, week: 4
INFO: tempDate: 2016-01-23 22:00:00 +0000, day: 24, week: 5
and as you can see, the week 53 from 2015 has the same day as the week 1 from 2016 (This site tells me that there are 53 weeks in 2015).
Actually, the week 1 from 2016 starts from 04.01.2016.
Also, notice the dateWithString:formatString: gives me the previous day of the first day of the week. Why is that? I can simply use dateByAddingDays:1 but I don't know if it's hackish and the problem should be solved somewhere else.
I tried using NSDateComponents as #DarkDust mentioned, to no avail. So this:
for (NSInteger week = 1; week <= 5; week++) {
NSDate *tempDate = [NSDate dateWithString:[NSString stringWithFormat:#"2016-%d", (int)week] formatString:#"Y-w"];
NSDateComponents *dateComponents = [NSDateComponents new];
dateComponents.year = 2016;
dateComponents.weekOfYear = week;
NSLog(#"INFO: tempDate: %#, day: %.2d, week: %d = %#", tempDate, (int)[tempDate day], (int)week, [calendar dateFromComponents:dateComponents]);
}
gives me this:
INFO: tempDate: 2015-12-26 22:00:00 +0000, day: 27, week: 1 = 2015-12-31 22:00:00 +0000
INFO: tempDate: 2016-01-02 22:00:00 +0000, day: 03, week: 2 = 2015-12-31 22:00:00 +0000
INFO: tempDate: 2016-01-09 22:00:00 +0000, day: 10, week: 3 = 2015-12-31 22:00:00 +0000
INFO: tempDate: 2016-01-16 22:00:00 +0000, day: 17, week: 4 = 2015-12-31 22:00:00 +0000
INFO: tempDate: 2016-01-23 22:00:00 +0000, day: 24, week: 5 = 2015-12-31 22:00:00 +0000
Here is the DateTools' dateWithString:formatString: implementation:
+ (NSDate *)dateWithString:(NSString *)dateString formatString:(NSString *)formatString {
return [self dateWithString:dateString formatString:formatString timeZone:[NSTimeZone systemTimeZone]];
}
+ (NSDate *)dateWithString:(NSString *)dateString formatString:(NSString *)formatString timeZone:(NSTimeZone *)timeZone {
static NSDateFormatter *parser = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
parser = [[NSDateFormatter alloc] init];
});
parser.dateStyle = NSDateFormatterNoStyle;
parser.timeStyle = NSDateFormatterNoStyle;
parser.timeZone = timeZone;
parser.dateFormat = formatString;
return [parser dateFromString:dateString];
}
As for the duplicate report:
The top 3 are wrong, 2 of them with downvotes, and they don't even do what I need at all.
This is a bad idea what you are doing. You must understand a date is a time stamp which can be interpreted differently depending on the time zone and the calendar you are using. As it was already mentioned in comments you should use date components for your solution. Note that printing out the date may use a different format and the result may not be expected.
Next a first weekday in a year depends on definition. If I remember correctly some standards (or all) will treat the first week of the year depending on what day of week is the first day. In other words if 1.1 is sunday then the first week of the year is in december but if it is tuesday then it is in january.
So if you want to find the beginning of the first monday of the given year the code should look something like this (I did not test it):
+ (NSDate *)firstWeekInYear:(NSInteger)year {
NSCalendar *calendar = [NSCalendar autoupdatingCurrentCalendar];
NSDate *toReturn = nil;
NSDateComponents *components = [[NSDateComponents alloc] init];
components.year = year;
NSDate *beginningOfTheYear = [calendar dateFromComponents:components];
NSInteger day = [calendar component:NSCalendarUnitWeekday fromDate:beginningOfTheYear];
NSInteger daysToAdd = (8-day)%7;
toReturn = [calendar dateByAddingUnit:NSCalendarUnitDay value:daysToAdd toDate:beginningOfTheYear options:kNilOptions];
return toReturn;
}
So you need to choose the calendar, create date components with a target year, get the date from those components with the calendar to get the beginning of the year. Then find out what weekday that is and increase such a number of days so the result is the beginning of the first monday in a year.
I finally figured it out. #Matic's solution doesn't work in iOS 7 and it's hard to understand, so I managed to find a simpler solution that works on iOS 7 too:
+ (NSDate *)getFirstDayInWeek:(NSInteger)week ofYear:(NSInteger)year {
/* create the calendar only once */
static NSCalendar *calendar = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
calendar.firstWeekday = 2;
calendar.minimumDaysInFirstWeek = 4;
});
NSDateComponents *components = [NSDateComponents new]; // create an empty date components object
components.year = year;
components.weekOfYear = week; // set the number of the week in the year
components.weekday = calendar.firstWeekday; // important! set the result date's day of week
return [calendar dateFromComponents:components];
}
I am using
NSDateComponents *components = [CURRENT_CALENDAR components:DATE_COMPONENTS fromDate:_startDate];
[components setHour:0];
[components setMinute:0];
[components setSecond:0];
_date = [CURRENT_CALENDAR dateFromComponents:components];
With dates I receive from an API.
The _date returns 2 different outputs depending on the calendar day:
2016-01-04 05:00:00 +0000
2015-10-26 04:00:00 +0000
As if there was a change in time zone.
Is there a reason the time of _date changes from 5 to 4 ?Is there something to prevent that?
Problem is that unexpected time offset (-1) reflects in all the other dates I create with dateFromComponents:components
Output for different dates showing the offset
2016-01-04 05:00:00 +0000
2015-12-21 05:00:00 +0000
2015-12-14 05:00:00 +0000
2015-12-07 05:00:00 +0000
2015-11-23 05:00:00 +0000
2015-11-16 05:00:00 +0000
2015-11-09 05:00:00 +0000
2015-11-02 05:00:00 +0000
2015-10-26 04:00:00 +0000
2015-10-19 04:00:00 +0000
2015-10-22 04:00:00 +0000
2015-10-01 04:00:00 +0000
2015-09-24 04:00:00 +0000
NSDateComponents.quarter is returning 0 instead of valid quarter count.
I googled and it is said it is a bug for apple found in 2012. However, now it is 2015 and iOS 8.3, bug still exists.
What I need is the quarter count from firstDate to lastDate
for example:
unitFlags = NSQuarterCalendarUnit;
(lldb) po firstDate
2009-12-31 16:00:00 +0000
(lldb) po lastDate
2013-09-30 16:00:00 +0000
(lldb) po [gregorian components:unitFlags fromDate:firstDate toDate:lastDate options:0];
<NSDateComponents: 0x170158b50>
Quarter: 0
I have an app that shows certain states of hardware. I know the time when the hardware entered said state (failed, active, idle, unconnected, etc). I've been experimenting with showing the state with an "ago" time. But I've struggled with how to adjust the resolution.
Under an hour is easy, just show "minutes ago". As you move into hours ago though, the minutes become less and less important. I'm not sure that suddenly jumping to "1 hour ago" at 61 minutes is the right way though. And when to switch to "2 hours ago". Do you round, or truncated that computation. The same dilemma exists at the 24 hour point. Do you show 25 hours ago, or just say 1 day ago. Or should there be a period where I show "1 hour and 13 minutes ago" and then at some point drop the minutes.
I know these "ago" labels aren't original. I'm curious how others have implemented this.
Moment.js is a very popular library used in web development that can output time from now just as you are asking. Below is a listing of how they break down their intervals into a more digestible format.
From their documentation:
0 to 45 seconds seconds ago
45 to 90 seconds a minute ago
90 seconds to 45 minutes 2 minutes ago ... 45 minutes ago
45 to 90 minutes an hour ago
90 minutes to 22 hours 2 hours ago ... 22 hours ago
22 to 36 hours a day ago
36 hours to 25 days 2 days ago ... 25 days ago
25 to 45 days a month ago
45 to 345 days 2 months ago ... 11 months ago
345 to 547 days (1.5 years) a year ago
548 days+ 2 years ago ... 20 years ago
As a sumplement to #JimmyBoh 's answer, I thought I'd add the ObjectiveC code I used:
#import "NSDate+AgoPrint.h"
#define SECONDS(s) (s)
#define MINUTES(m) ((m) * 60)
#define HOURS(h) ((h) * 3600)
#define DAYS(d) ((d) * 3600 * 24)
#define YEARS(y) ((y) * 3600 * 24 * 365)
#implementation NSDate (AgoPrint)
- (NSString*) simpleAgoString {
NSTimeInterval ago = -self.timeIntervalSinceNow;
if (ago <= SECONDS(45)) { // 0 to 45 seconds seconds ago
return [NSString stringWithFormat: #"%u seconds ago", (unsigned int)round(ago)];
}
else if (ago <= SECONDS(90)) { //45 to 90 seconds a minute ago
return #"a minute ago";
}
else if (ago <= MINUTES(45)) { //90 seconds to 45 minutes 2 minutes ago ... 45 minutes ago
return [NSString stringWithFormat: #"%u minutes ago", (unsigned int)round(ago / MINUTES(1))];
}
else if (ago <= MINUTES(90)) { // 45 to 90 minutes an hour ago
return #"an hour ago";
}
else if (ago <= HOURS(22)) { // 90 minutes to 22 hours 2 hours ago ... 22 hours ago
return [NSString stringWithFormat: #"%u hours ago", (unsigned int)round(ago / HOURS(1))];
}
else if (ago <= HOURS(36)) { // 22 to 36 hours a day ago
return #"a day ago";
}
else if (ago <= DAYS(25)) { // 36 hours to 25 days 2 days ago ... 25 days ago
return [NSString stringWithFormat: #"%u days ago", (unsigned int)round(ago / DAYS(1))];
}
else if (ago <= DAYS(45)) { // 25 to 45 days a month ago
return #"a month ago";
}
else if (ago <= DAYS(345)) { // 45 to 345 days 2 months ago ... 11 months ago
return [NSString stringWithFormat: #"%u months ago", (unsigned int)round(ago / DAYS(30))];
}
else if (ago < DAYS(547)) { // 345 to 547 days (1.5 years) a year ago
return #"a year ago";
}
else { // 548 days+ 2 years ago ... 20 years ago
return [NSString stringWithFormat: #"%u years ago", (unsigned int)round(ago / YEARS(1))];
}
}
#end
I may end up adding weeks or replacing months or weeks, but the general approach seems pretty clear how I would slot that in.