I cant calculate output from "old" and "now" NSDate. Here is the code:
NSLog(#"past is %#", past);
NSDate *now = [NSDate date];
NSLog(#"Now time is is %#", now);
NSTimeInterval distanceBetweenDates = [now timeIntervalSinceDate:past];
double secondsInAnHour = 3600;
NSInteger hoursBetweenDates = distanceBetweenDates / secondsInAnHour;
NSLog(#" Time between is %i", hoursBetweenDates);
Here is console output:
2015-11-11 18:52:35.608 TaskTimer[2578:130664] past is 2015-11-11 15:52:02 +0000
2015-11-11 18:52:35.608 TaskTimer[2578:130664] now is 2015-11-11 15:52:35 +0000
2015-11-11 18:52:35.609 TaskTimer[2578:130664] Time between is 0
I want to add, that last value is 0 even when time between two values more then couple of minutes. Why is it 0?
Because you're converting to an integer and it rounds down. Anything < a particular integer value will round down. And a few minutes is < 1 so you'll get 0 hours.
If you want to round to nearest then use round(distanceBetweenDates / secondsInAnHour), or to round up you would use ceil(distanceBetweenDates / secondsInAnHour) (though it will also round 2.1 up to 3)
There are 33 minutes between your 2 dates, which is a fraction of an hour.
NSInteger hoursBetweenDates = distanceBetweenDates / secondsInAnHour;
That statement is losing the fractional precision, and rounding down to 0, which is what you are displaying.
An alternative is to display in hh:mm:ss format using NSDateComponentsFormatter
NSDateComponentsFormatter *formatter = [[NSDateComponentsFormatter alloc] init];
formatter.allowedUnits = NSCalendarUnitHour | NSCalendarUnitMinute |
NSCalendarUnitSecond;
NSLog(#"Time between is %#", [formatter stringFromTimeInterval:distanceBetweenDates]);
Related
I have a simple snippet which runs a loop every 1 second and displays seconds since epoch using NSDate.
while(1){
NSDate *now = [NSDate date];
NSTimeInterval nowEpochSeconds = [now timeIntervalSince1970];
NSLog(#"%f",nowEpochSeconds);
[NSThread sleepForTimeInterval:1.0f];
}
nowEpochSeconds produces a floating point value in seconds with several decimal places as such
1568646562.613972
1568646563.618479
1568646564.621624
1568646565.626183
1568646566.626722
1568646567.628425
1568646568.633329
It's very close to one second intervals. Then I try dropping the decimal place using floorf
NSLog(#"%f",floorf(nowEpochSeconds));
But the seconds just remain the same. It's not the correct number of seconds either they just stagnate at one value
1568646528.000000
1568646528.000000
1568646528.000000
1568646528.000000
1568646528.000000
1568646528.000000
I don't know why floorf is giving me strange results
NSTimeInterval is a double, so you probably want to be using floor():
int j = 0;
while(++j < 6){
NSDate *now = [NSDate date];
NSTimeInterval nowEpochSeconds = [now timeIntervalSince1970];
NSLog(#"%f",nowEpochSeconds);
NSLog(#"%f",floor(nowEpochSeconds));
NSLog(#"\n");
[NSThread sleepForTimeInterval:1.0f];
}
Output:
1568648630.428520
1568648630.000000
1568648631.429841
1568648631.000000
1568648632.431206
1568648632.000000
1568648633.432594
1568648633.000000
1568648634.433988
1568648634.000000
I'm converting dates from an Excel spreadsheet to NSDate's, but for some reason they always come out two days ahead: Sundays come out as Tuesdays, etc.
My conversion method is based on the following info from cpearson.com:
Excel stores dates and times as a number representing the number of
days since 1900-Jan-0, plus a fractional portion of a 24 hour day:
ddddd.tttttt . This is called a serial date, or serial date-time.
(...) The integer portion of the number, ddddd, represents the number
of days since 1900-Jan-0. (...) The fractional portion of the number,
ttttt, represents the fractional portion of a 24 hour day. For
example, 6:00 AM is stored as 0.25, or 25% of a 24 hour day.
Similarly, 6PM is stored at 0.75, or 75% percent of a 24 hour day.
- (NSDate *)dateFromExcelSerialDate:(double)serialdate
{
if (serialdate == 0)
return nil;
NSTimeInterval theTimeInterval;
NSInteger numberOfSecondsInOneDay = 86400;
double integral;
double fractional = modf(serialdate, &integral);
NSLog(#"%# %# \r serialdate = %f, integral = %f, fractional = %f",
[self class], NSStringFromSelector(_cmd),
serialdate, integral, fractional);
theTimeInterval = integral * numberOfSecondsInOneDay; //number of days
if (fractional > 0) {
theTimeInterval += numberOfSecondsInOneDay / fractional; //portion of one day
}
NSCalendar *nl_gregorianCalendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
NSTimeZone *nl_timezone = [[NSTimeZone alloc] initWithName:#"Europe/Amsterdam"];
[nl_gregorianCalendar setTimeZone:nl_timezone];
NSDateComponents *excelBaseDateComps = [[NSDateComponents alloc] init];
[excelBaseDateComps setMonth:1];
[excelBaseDateComps setDay:1];
[excelBaseDateComps setHour:00];
[excelBaseDateComps setMinute:00];
[excelBaseDateComps setTimeZone:nl_timezone];
[excelBaseDateComps setYear:1900];
NSDate *excelBaseDate = [nl_gregorianCalendar dateFromComponents:excelBaseDateComps];
NSDate *inputDate = [NSDate dateWithTimeInterval:theTimeInterval sinceDate:excelBaseDate];
NSLog(#"%# %# \r serialdate %f, theTimeInterval = %f \r inputDate = %#",
[self class], NSStringFromSelector(_cmd),
serialdate, theTimeInterval,
[self.nl_dateFormatter stringFromDate:inputDate]);
return inputDate;
}
The spreadsheet was produced in the Netherlands, presumably on a Dutch version of Microsoft Excel.
Spreadsheet date Sunday July 6, 2014 00:00 yields the following results:
dateFromExcelSerialDate:
serialdate = 41826.000000, integral = 41826.000000, fractional =
0.000000 theTimeInterval = 3613766400.000000 inputDate = 08 jul. 2014 01:40
Similarly, Sunday July 13, 2014 00:00 yields:
serialdate = 41833.000000, integral = 41833.000000, fractional =
0.000000 theTimeInterval = 3614371200.000000 inputDate = 15 jul. 2014 01:40
I can correct the output by subtracting 2 days, one hour and 40 minutes:
theTimeInterval -= ((60 * 60 * 24 * 2) + (60*60) + (60*40));
but I have no idea how robust that is.
That difference of two days made me think it had something to do with leap year corrections, so I tried to let the calendar do the calculations by adding the NSTimeInterval seconds to the excelBaseDate, like so:
NSDateComponents *comps = [[NSDateComponents alloc] init];
[comps setSecond:theInterval];
NSDate *inputDate = [nl_gregorianCalendar dateByAddingComponents:comps
toDate:excelBaseDate
options:0];
Strangely enough, that gave me dates somewhere in the 1870's. Who knows what is going on?
there are two things here:
your start date is 1900-Jan-1 but your referred description clearly says: the reference is 1900-Jan-0 – you may add an extra day here;
year 1900 was not a leap-year – you may add an extra day here;
I guess, this is pretty much the reason why you get two extra days every occasion.
Microsoft knows about that, see more about the topic here.
I am trying to parse the pwdLastSet value from NSTask response when I do an ldapsearch. I've successfully extracted the value (129875475241190194) and I am trying to convert it to an NSDate Object.
Reference: http://www.chrisnowell.com/information_security_tools/date_converter/Windows_active_directory_date_converter.asp
I tried to extract the Javascript code from the page above and convert it but I am getting a different date.
int iYearsFrom1601to1970 = 1970 - 1601;
int iDaysFrom1601to1970 = iYearsFrom1601to1970 * 365;
iDaysFrom1601to1970 += (int)(iYearsFrom1601to1970 / 4); // leap years
iDaysFrom1601to1970 -= 3; // non-leap centuries (1700,1800,1900). 2000 is a leap century
float iSecondsFrom1601to1970 = iDaysFrom1601to1970 * 24 * 60 * 60;
int iTotalSecondsSince1601 = (int)(129875475241190194 / 10000000);
float iTotalSecondsSince1970 = iTotalSecondsSince1601 - iSecondsFrom1601to1970;
NSDate *date = [NSDate dateWithTimeIntervalSince1970:iTotalSecondsSince1970];
Any help would be appreciated.
Thanks!
Here's how I would do it:
NSDateComponents *base = [[NSDateComponents alloc] init];
[base setDay:1];
[base setMonth:1];
[base setYear:1601];
[base setEra:1]; // AD
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDate *baseDate = [gregorian dateFromComponents:base];
[base release];
[gregorian release];
NSTimeInterval timestamp = 129875475241190194.0 / 10000000.0;
NSDate *finalDate = [baseDate dateByAddingTimeInterval:timestamp];
This gives me a finalDate of 2012-07-24 03:58:22 +0000.
Since the timestamp is a time interval since Jan 1, 1601 at 00:00 UTC, you can use the -dateByAddingTimeInterval: method on NSDate to add the timestamp to the base date to get the final NSDate.
Once you've done that, you can run it through an NSDateFormatter to format it for display.
Assuming the, well, daring conversion between the basetimes is correct: actually looking at the warnings, instead of casting them away, might actually help:
int main(void)
{
int iTotalSecondsSince1601 = (129875475241190194 / 10000000);
return 0;
}
stieber#gatekeeper:~$ clang++ Test.cpp
Test.cpp:4:8: warning: implicit conversion from 'long' to 'int' changes value from 12987547524 to 102645636
....
That should account for a good deal of the difference...
Try this
NSTimeInterval value = 129875475241190194;
// instead of trying to compute seconds between 1601 and 1970
const NSTimeInterval EPOCH = 11644473600;
const NSTimeInterval NANO = 10000000;
NSTimeInterval seconds = value / NANO - EPOCH;
NSDate *answer = [NSDate dateWithTimeIntervalSince1970:seconds];
Also this is reason you don't want to calculate seconds since 1601: ...in the last millennium, 1600 and 2000 were leap years, but 1700, 1800 and 1900 were not. Excerpt from Wikipedia on Gregorian calendar.
The value for EPOCH is explained on Convert Active Directory "LastLogon:" time to (UNIX) readable time
.
Note: The information about accountExpires which starts from 12-31-1601 (11644473600). The values lastLogon and lastLogonTimeStamp however use 01-01-1601 as the date to calculate this value (11676009600).
I'm trying to retrieve all the events for a single day from an instance of EKEventStore using eventsMatchingPredicate:, but as I read, the NSDate objects are by default set to GMT while the EKEventStore isn't. So my question is how do I change the timezone of the EKEventStore or adjust the NSDate objects so that the times aren't off for each timezone?
For example, I'm in GMT -0600, and clicking on January 16th and 17th in the TKCalendarMonthView I'm using for a calendar UI shows Martin Luther King Day on both dates. The start time is 6 AM on 16 January, and the end time is 5:59 AM on 17 January (as a result of my timezone), rather than beginning at 12:00 AM and lasting until 11:59 PM. The code used to retrieve events follows.
- (void)calendarMonthView:(TKCalendarMonthView *)monthView didSelectDate:(NSDate *)d {
// Update tableData with event data from date
[tableData removeAllObjects];
NSArray *a = [systemCalendar eventsMatchingPredicate:[systemCalendar predicateForEventsWithStartDate:d endDate:[NSDate dateWithTimeInterval:84600 sinceDate:d] calendars:nil]];
[tableData addObjectsFromArray:a];
[self.eventsTable reloadData];
}
Given that I'm on a short timeline, I came up with a solution, and it seems to work. My only concern is that I had to multiply the offset by -1 even though the time interval offset itself is negative. This doesn't make sense because we are trying to subtract from the NSDate rather than add to it. A positive number minus a negative number gives us a larger number, so I'm slightly worried about the GMT zones on the other side of the PM and wondering whether I should actually be multiplying all time intervals by -1. Anyone have any thoughts?
- (void)calendarMonthView:(TKCalendarMonthView *)monthView didSelectDate:(NSDate *)d {
[NSTimeZone resetSystemTimeZone];
NSTimeZone *tz = [NSTimeZone systemTimeZone];
NSArray *comps = [[tz description] componentsSeparatedByString:#" "];
NSTimeInterval offset = (NSTimeInterval)[[comps lastObject] floatValue];
if (offset < 0) {
offset *= -1;
}
NSDate *startDate = [d dateByAddingTimeInterval:offset];
NSArray *a = [systemCalendar eventsMatchingPredicate:[systemCalendar predicateForEventsWithStartDate:startDate endDate:[NSDate dateWithTimeInterval:84600 sinceDate:startDate] calendars:nil]];
NSLog(#"Events for the date: %#", a);
[tableData addObjectsFromArray:a];
[self.eventsTable reloadData];
}
I want to convert a float to a NSDate
I converted a NSDate into a float using this:
// Turn the date into Integers
NSCalendar *calendar= [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSCalendarUnit unitFlags = NSHourCalendarUnit | NSMinuteCalendarUnit | NSSecondCalendarUnit;
NSDateComponents *dateComponents = [calendar components:unitFlags fromDate:nsdate_wakeTime];
NSInteger hour = [dateComponents hour];
NSInteger min = [dateComponents minute];
//Convert the time in 24:60 to x.x format.
float myTime = hour + min/60;
after some math stuff I do on the mytime variable i get a bunch of other times in the same float format.
How do I turn a float into a NSDate?
Thanks!
If you convert the time you've computed to seconds (so, mytime * 60), then you can use dateWithTimeIntervalSinceReferenceDate: to get back to an NSDate. From the math you are doing, it looks like the referenced date here would be 00:00 for the day in question. As Jason mentioned though, there's probably a better way to do what you are trying to accomplish.
Also, you need to change your "myTime" computation to dividing by 60.0 if you actually want the minutes; your sample code is dividing an integer value less than 60 by the integer value 60, which will always be 0.