how I can convert an epoch time value to NSDate. For example I use this value : 1310412600000. and I am in the EDT time zone.
When I try this :
NSString *bar = [[NSDate dateWithTimeIntervalSince1970:epoch] description];
I got a wrong value...
What is the good way? I spend a lot of time with that....
Thanks
Epoch time (also known as "Unix" and "POSIX" time) is the number of seconds since the start of 1970. You can convert epoch time to NSDate with this algorithm:
Instantiate NSDate object and pass the epoch time as a parameter to NSDate's initWithTimeIntervalSince1970 initializer. You're done. The NSDate object is set to the epoch time. NSDate stores times internally in the UTC time zone. It's up to you how it is displayed.
[Optional] Format your NSDate to the appropriate time zone with an NSDateFormatter.
Here's the code I used:
// Sample string epochTime is number of seconds since 1970
NSString *epochTime = #"1316461149";
// Convert NSString to NSTimeInterval
NSTimeInterval seconds = [epochTime doubleValue];
// (Step 1) Create NSDate object
NSDate *epochNSDate = [[NSDate alloc] initWithTimeIntervalSince1970:seconds];
NSLog (#"Epoch time %# equates to UTC %#", epochTime, epochNSDate);
// (Step 2) Use NSDateFormatter to display epochNSDate in local time zone
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"yyyy-MM-dd HH:mm:ss zzz"];
NSLog (#"Epoch time %# equates to %#", epochTime, [dateFormatter stringFromDate:epochNSDate]);
// (Just for interest) Display your current time zone
NSString *currentTimeZone = [[dateFormatter timeZone] abbreviation];
NSLog (#"(Your local time zone is: %#)", currentTimeZone);
Per the documentation, dateWithTimeIntervalSince1970: runs from January 1, 1970, 00:00 GMT. So you should be getting results four hours later than those you really want.
Hence the simplest thing — if you don't mind hard coding the offset from GMT to EDT — would seem to be:
[[NSDate dateWithTimeIntervalSince1970:epoch] dateByAddingTimeInterval:-240]
// or:
[NSDate dateWithTimeIntervalSince1970:epoch - 240]
Though to eliminate arbitrary constants (and be a little cleaner), you probably want something like:
NSTimeZone *EDTTimeZone = [NSTimeZone timeZoneWithAbbreviation:#"EDT"];
NSInteger secondsDifferenceFromGMT =
[EDTTimeZone secondsFromGMTForDate:[NSDate dateWithTimeIntervalSince1970:0]];
NSDate *startOfEpoch =
[NSDate dateWithTimeIntervalSince1970:secondsDifferenceFromGMT];
...
NSDate *newDate = [startOfEpoch dateByAddingTimeInterval:firstInterval]; // etc
Are you passing the value in seconds?
The method accepts value in seconds , not milliseconds.
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSDate_Class/Reference/Reference.html
Related
I am trying to get the epoch time for a date (2016-03-31T17:58:30.812Z) and I'm having trouble converting. Here is what I have tried:
NSDateFormatter* df = [NSDateFormatter new];
NSDate* tokenCreated = [NSDate new];
[df setDateFormat:#"yyyy-MM-dd'T'HH:mm:sssZ"];
tokenCreated = [df dateFromString:#"2016-03-31T17:58:30.812Z"];
NSTimeInterval timeTokenCreated = [tokenCreated timeIntervalSince1970];
NSLog(#"TIME TOKEN::::%f", timeTokenCreated);
What is happening is that tokenCreated is being set to nil, and I'm unable to convert. Can someone please point me in the right direction and tell me where I'm going wrong?
What is happening is that tokenCreated is being set to nil
Because your date format doesn't match your string. For example, your format fails to distinguish between the seconds and the fractional seconds. You would need this:
#"yyyy-MM-dd'T'HH:mm:ss.SSSZ"
Below is a string represented a date
NSString *dateStr = #"2011-07-06";
And when I am trying to convert it to NSDate by doing :
NSDateFormatter *format = [[NSDateFormatter alloc] init];
[format setDateFormat:#"yyyy-MM-dd"];
NSDate *tmp = [format dateFromString:dateStr];
NSLog(#"tmp is %#",[tmp description]);
What I am getting from the console is
tmp is 2011-07-06 04:00:00 +0000
I dont understand why I am getting extra info :04:00:00 +0000 for the result
Please help if you experienced it before
Your code
NSString *dateStr = #"2011-07-06";
NSDateFormatter *format = [[NSDateFormatter alloc] init];
[format setDateFormat:#"yyyy-MM-dd"];
NSDate *tmp = [format dateFromString:dateStr]
will result in a NSDate object, that represents your local time at 0:00 — the beginning of the day.
but if you print a plain date object, it will result in a string that represents the time in GMT timezone, as internally all dates are normalized to that timezone.
As your string is 4 hours ahead, we can tell, that you most likely are in East Europe, maybe Moscow.
So if you want to see the string in your timezone, you need to use a NSDateFormatter to create it from the date object.
NSLog(#"tmp is %#",[formatter stringFromDate:tmp]);
to check, if it is correct, what I said, change the format to contain the time components.
formatter.format = [#"yyyy-MM-dd HH:mm"];
NSLog(#"tmp is %#",[formatter stringFromDate:tmp]);
The formatter will also take "oddities" like Leap Day, Leap Month (yes — those exits), Daylight Saving Times, Leap Seconds … in account — accordantly to the current calendar.
A great WWDC 2011 Video: Performing Calendar Calculations — a must-see for every cocoa developer.
BTW: to print a object with NSLog you dont need to call -description on it to pass in a string. NSLog will do this internally.
NSLog(#"tmp is %#", tmp);
is just fine.
The answer is simple, NSLog just converts the NSDate to a NSString, using its formatter with GMT (zero) timezone.
Your formatter is by default set to your default time zone, which is probably -4:00. When you print it out, NSLog converts it to 0:00, adding 4 hours.
In general, it's unsafe to parse dates without specifying their timezone.
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 using the following code to set my timezone to Stockholm, Europe.
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"Europe/Stockholm"]];
[dateFormatter setDateFormat:#"yyyy-MM-dd HH:mm"];
NSDate *webUpdateDate = [dateFormatter dateFromString:#"2011-07-22 22:10"];
// Outputs "2011-07-22 20:10 +0000"
Anyone know why?
I assume you're inspecting the date using NSLog. An NSDate object represents an absolute time -- it has no notion of time zone, so when it is asked for its description, it displays as if it were a time in GMT. If you want that absolute time represented for the Stockholm time zone, you need to use the date formatter again:
NSLog(#"%#", [dateFormatter stringFromDate:webUpdateDate]);
Since the date was originally created via the formatter, which already had its time zone set to Stockholm, I believe this will give you the same string that you used for input: #"2011-07-22 22:10".
I'm using the JSON library from Stig Brautaset(http://code.google.com/p/json-framework) and I need to serialize an NSDate. I was considering converting it into a string before JSONifying it, however, I ran into this weird behavior:
Why aren't these NSDates considered equal?
NSDate *d = [[NSDate alloc] init];
NSDate *dd = [NSDate dateWithString:[d description]];
NSLog(#"%#", d);
NSLog(#"%#", dd);
if( [d isEqualToDate:dd] ){
NSLog(#"Yay!");
}
When you describe the original date object you lose some sub-second precision from the original object — in other words, -description shaves off fractional seconds, and returns
A string representation of the receiver in the international format YYYY-MM-DD HH:MM:SS ±HHMM, where ±HHMM represents the time zone offset in hours and minutes from GMT
When you create a new date object based on the description, you get it in whole seconds because the string is only precise to a whole second. So -isEqualToDate: returns NO because there is a difference of a fraction of a second between your two date objects, which it's sensitive to.
This method detects sub-second differences between dates. If you want to compare dates with a less fine granularity, use timeIntervalSinceDate: to compare the two dates.
So you'd do something like this instead (NSTimeInterval measures in seconds):
if ([d timeIntervalSinceDate:dd] == 0) {
NSLog(#"Yay!");
}
isEqualToDate detects subseconds differences between dates, but the description method does not include subseconds.
Because they're not equivalent:
NSDate *d = [NSDate date];
NSDate *dd = [NSDate dateWithString:[d description]];
NSLog(#"%f", [d timeIntervalSinceReferenceDate]);
NSLog(#"%f", [dd timeIntervalSinceReferenceDate]);
Produces:
2011-04-28 11:58:11.873 EmptyFoundation[508:903] 325709891.867788
2011-04-28 11:58:11.874 EmptyFoundation[508:903] 325709891.000000
In other words, the +dateWithString: method does not maintain sub-second precision.