NSDate to Tick conversion - ios

I wanted to convert a date (nsdate) to tick values. Tick values are (1 Tick = 0.1 microseconds or 0.0001 milliseconds) since 1 Jan 0001 00:00:00 GMT. NSDate has functions like timeIntervalSince1970. So, how do I convert it?

I would like to share my experience:
I tried to find the seconds from 01/01/0001 and then multiply by 10,000,000. However, it gave me wrong results. So, I found out that 01/01/1970 is 621355968000000000 ticks from 01/01/0001 and used the following formula along with timeIntervalSince1970 function of NSDate.
Ticks = (MilliSeconds * 10000) + 621355968000000000
MilliSeconds = (Ticks - 621355968000000000) / 10000
Here is the outcome:
+(NSString *) dateToTicks:(NSDate *) date
{
NSString *conversionDateStr = [self dateToYYYYMMDDString:date];
NSDate *conversionDate = [self stringYYYYMMDDToDate:conversionDateStr];
NSLog(#"%#",[date description]);
NSLog(#"%#",[conversionDate description]);
double tickFactor = 10000000;
double timeSince1970 = [conversionDate timeIntervalSince1970];
double doubleValue = (timeSince1970 * tickFactor ) + 621355968000000000;
NSNumberFormatter *numberFormatter = [[[NSNumberFormatter alloc] init] autorelease];
[numberFormatter setNumberStyle:NSNumberFormatterNoStyle];
NSNumber *nsNumber = [NSNumber numberWithDouble:doubleValue];
return [numberFormatter stringFromNumber:nsNumber];
}
Likewise, to convert from tick to date:
//MilliSeconds = (Ticks - 621355968000000000) / 10000
+(NSDate *) ticksToDate:(NSString *) ticks
{
double tickFactor = 10000000;
double ticksDoubleValue = [ticks doubleValue];
double seconds = ((ticksDoubleValue - 621355968000000000)/ tickFactor);
NSDate *returnDate = [NSDate dateWithTimeIntervalSince1970:seconds];
NSLog(#"%#",[returnDate description]);
return returnDate;
}

Related

Convert Datetime c# to Objective c and invertion

How to convert Datetime timestamp to a NSDate?
How to make the inverse?
My method to convert datetime to a string :
+(NSString*) dateTojson:(NSDate*)date{
return [NSString stringWithFormat:#"/Date(%f)/",(double)([date dateWithTimeIntervalSince1970] * 1000)];
}
My inverse method:
+(NSDate*) jsonToDate:(NSString *)json
{
double milisec = 0;
json = [[[json stringByReplacingOccurrencesOfString:#"/Date(" withString:#""] stringByReplacingOccurrencesOfString:#"/" withString:#""] stringByReplacingOccurrencesOfString:#"-0200" withString:#""];
NSArray *arr = [json componentsSeparatedByString:#"-"];
for(NSString *s in arr) {
if(![s isEqualToString:#""]){
milisec += [s doubleValue];
}
}
NSDate *date = [NSDate dateWithTimeIntervalSince1970:(milisec / 1000.0)];
return date;
}
When i use [self jsonToDate:#"/Date(1495497600)/"] where 1495497600 represents "05/23/2017", the method return me a wrong date (result = "01/18/1970").
Why?
Notes:
i'm not considering the time, only date.
My variable milisec is equals to 1495497600, so i think the problem is the method dateWithTimeIntervalSince1970.
already try some posts like:
Convert milliseconds to NSDate
How to Convert a milliseconds to nsdate in objective C
You don't really need to divide the milliseconds at the end:
NSDate *date = [NSDate dateWithTimeIntervalSince1970:milisec];
Result:
2017-05-23 00:00:00 +0000

Convert String to Float to move UISlider

How I can convert time of my JSON data to float value. Below code is written to convert time to float and I passed it to UISlider as total length of audio. I want to move slider with that time spans
//Json Data
{
duration = "00:03:45";
id = 8;
}
//Audio player sider bar function
if(audioController.playbackState == MPMusicPlaybackStatePlaying){
if (isSelected == YES) {
currentAutio = audioList[selectedAudio];
} else {
currentAutio = audioList[0];
}
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc] init];
numberFormatter.numberStyle = NSNumberFormatterDecimalStyle;
float value = [numberFormatter numberFromString:currentAutio.duration].floatValue;
float currentPlaybackTime = [audioController currentPlaybackTime];
float TotalLength = value;
float remainingPlaybackTime = TotalLength - currentPlaybackTime;
float sliderPosition = (currentPlaybackTime *100) / TotalLength;
NSLog(#"current playbacktime %f",currentPlaybackTime);
NSLog(#"TotalLength %f",TotalLength);
NSLog(#"remainingPlaybackTime %f",remainingPlaybackTime);
NSLog(#"sliderPosition %f",sliderPosition);
//Update slider
[progressSlider setValue:sliderPosition];
//Update labels
NSDate* d1 = [NSDate dateWithTimeIntervalSince1970:currentPlaybackTime];
NSDate* d2 = [NSDate dateWithTimeIntervalSince1970:remainingPlaybackTime];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"mm:ss"];
NSString *currentTime = [dateFormatter stringFromDate:d1];
NSString *ramainingTime = [dateFormatter stringFromDate:d2];
[trackCurrentPlaybackTimeLabel setText:currentTime];
[trackLengthLabel setText:[NSString stringWithFormat:#"-%#",ramainingTime]];
}
I am getting following output:
Value = 0.00000
I don't think there is a built-in mechanism for converting a time interval into a float, but it's trivially easy to write:
func timeIntervalFrom(_ timeString: String) -> TimeInterval? {
//Add code to validate that string is in correct format
let components = time.components(separatedBy: ":")
guard components.count == 3,
let hours = Double(components[0]),
let minutes = Double(components[1]),
let seconds = Double(components[2]) else {
return nil
}
return hours * 3600 + minutes * 60 + seconds
}
Just convert the duration from String to integer components.
Then calculate the total duration in seconds.
You can get the integer components simply like this:
Swift
let timeComponents = duration.components(separatedBy: ":")
Objective C
NSArray *timeComponents = [duration componentsSeparatedByString:#":"];
timeComponents[0] will be the hours part.
timeComponents[1] will be the minutes part.
timeComponents[2] will be the seconds part.
Total seconds: (hours * 60 * 60) + (minutes * 60) + seconds.
After that, adjusting the slide bar value will be easy :)

ios8 - seeing if a record is past or future

I'm parsing an array and want to weed out records from before now.
I've got this code:
int i = 0;
for (i=0; i < tempArray.count; i++) {
currentObjectArray = tempArray[i];
NSString *dateString = [currentObjectArray valueForKey:#"ScheduleTime" ];
NSDate *schedule = [dateFormatter dateFromString:dateString];
NSLog(#"schedule: %lu", (unsigned long) schedule );
NSLog(#"now: %lu", (unsigned long)[NSDate date] );
NSTimeInterval distanceBetweenDates = [schedule timeIntervalSinceDate: schedule];
NSLog(#"distanceBetweenDates: %lu", (unsigned long)distanceBetweenDates );
result:
schedule: 16436914033316069376
now: 6174145184
distanceBetweenDates: 0
but the two resulting numbers are incorrect, thus the result is incorrect. Could someone please tell me what I'm doing wrong? Thanks
UPDATE: Thanks to answers below, I've updated my code as follows:
NSString *dateString = [currentObjectArray valueForKey:#"ScheduleTime" ];
NSDate *schedule = [dateFormatter dateFromString:dateString];
float s = [schedule timeIntervalSince1970];
NSLog(#" %f", s );
NSTimeInterval timeInterval = [currentObjectArray timeIntervalSinceNow];
if (timeInterval > 0) {
NSLog(#"YES");
} else {
NSLog(#"NO");
The schedule date format is: "YYYY-MM-DD'T'HH:mm:ss"
Update2: I forgot to add in the local time zone. Thanks for all the help.
These two lines don't do what you think they do.
NSLog(#"schedule: %lu", (unsigned long) schedule );
NSLog(#"now: %lu", (unsigned long)[NSDate date] );
Performing this type cast is asking the system to return you an unsigned long representation of the pointer to the object, which is a memory address and not at all related to time. It is likely that you actually wanted to ask for the NSTimeInterval values.
NSLog(#"schedule: %f", [schedule timeIntervalSince1970] );
NSLog(#"now: %f", [[NSDate date] timeIntervalSince1970] );
Compounding your confusion, you have also misunderstood this line:
NSTimeInterval distanceBetweenDates = [schedule timeIntervalSinceDate: schedule];
You are asking the system to tell you how many seconds are between schedule and schedule; which is obviously always going to be 0 since they are identical. Instead, you probably meant one of:
NSTimeInterval distanceBetweenDates1 = [[NSDate date] timeIntervalSinceDate:schedule];
NSTimeInterval distanceBetweenDates2 = [schedule timeIntervalSinceDate:[NSDate date]];
You only need to check if the time interval is negative or positive to determine if a time comes before or after, respectively.
- (BOOL)isDateInPast:(NSDate *)date {
NSTimeInterval timeInterval = [date timeIntervalSinceNow];
if (timeInterval < 0) {
return YES;
} else {
return NO;
}
}
Note that this doesn't check the condition where the time interval is 0 (the present).
EDIT: Adding to this for further clarification. Your loop code could look something like this...
NSMutableArray *datesOnlyInFuture = [NSMutableArray array];
for (NSDate *date in dateArray) {
if (![self isDateInPast:date]) {
[datesOnlyInFuture addObject:date];
}
}
NSLog(#"Future only dates: %#", datesOnlyInFuture);
This will actually create a new array for you. Clearly plenty of optimizations should be made. For example timeIntervalSinceNow is going to be different each time it is called, so you could pass in a constant date that is set before the loop starts so you're always checking against the same date/time.

NSString of comma separated days to NSDate calculate closest day to current day

I have a string like this 13, 27, 29 representing days of the month I want to separate them like below into date objects
mayString = [mayString componentsSeparatedByString:#","];
I then want to be able to work out which of these days i.e 13 or 27 or 29 is closest to todays date which obviously taking the above dates would be 27 as the next closest date to current date.
I can grab current day using the below but really stuck on how to get the logic to do this?
//Grab current day from sys date
NSDateFormatter *dayFormatter = [[NSDateFormatter alloc] init];
[dayFormatter setDateFormat:#"dd"];
NSString *dayString = [dayFormatter stringFromDate:[NSDate date]];
I have a partial completed solution but it doesnt seem to give me the correct result of what index in the array is closest to current day (sepDates is an array)
sepDates = [mayString componentsSeparatedByString:#","];
//Day string is todays date i.e 16 (16th)
NSDate *dayFromString = [dayFormatter dateFromString:dayString];
NSLog(#"Day from string %#", dayFromString);
double min = [dayFromString timeIntervalSinceDate:[sepDates objectAtIndex:0]];
NSLog(#"Min %f", min);
//I then want to calculate which of the dates in the sepDates array at index is closest to todays current day 16
int minIndex = 0;
for (int d = 1; d < [sepDates count]; ++d)
{
double currentmin = [dayFromString timeIntervalSinceDate:[sepDates objectAtIndex:d]];
if (currentmin < min) {
min = currentmin;
minIndex = d;
NSLog(#"minIndex = %d", minIndex);
}
}
dayString shouldn't be a string, it should be NSInteger
While iterating through your array with dates, also convert all strings to integer (for example, [currentDayString integerValue])
Actual algorithm of searching the closest day would be to iterate through your initial array and find abs of difference between values in array and current day. Store those differences in separate array. Find minimum value in the second array. Location (index) of the minimal difference will be the same as location of closest day in the first array.
Here is the code snippet from the question that gives correct minIndex
NSArray *sepDates = #[#"13", #"15", #"27", #"29"];
NSDateFormatter *dayFormatter = [[NSDateFormatter alloc] init];
[dayFormatter setDateFormat:#"dd"];
NSString *dayString = [dayFormatter stringFromDate:[NSDate date]];
NSDate *dayFromString = [dayFormatter dateFromString:dayString];
NSLog(#"Day from string %#", dayFromString);
NSInteger min = [[sepDates lastObject] integerValue]; //or set it to some large int
NSLog(#"Min %d", min);
int minIndex = 0;
for (int d = 1; d < [sepDates count]; ++d)
{
NSInteger currentmin = [sepDates[d] integerValue] - [dayString integerValue];
NSLog(#"Current min: %d", currentmin);
//currentmin must be positive since you need next closest day
if (currentmin > 0 && currentmin < min) {
min = currentmin;
minIndex = d;
NSLog(#"minIndex = %d", minIndex);
}
}
Iterate through your dates and calculate the time from the current target and store that date if it is less than previously calculated or if nothing has been calculated (i.e. first element). The results from that will give you the answer.
Do this.
After you have separated the dates. convert them to int and add them to a mutable index set.
then, get todays date as string with format "dd" using date formatter, convert todays date (date string) to int and then add that date to the mutable index set.
NSMutableIndexSet is auto sorted.
then do this
NSInteger closestDateAsInt = [indexSet indexGreaterThanIndex:''today's date as int"];
this will give u the closest next date.
Once u have the closest date's int value. Convert it to date using date components.
Hope this helps. Cheers.

Is there any easy way to round a float with one digit number in objective c?

Yes. You are right. Of Course this is a duplicate question. Before flag my question, please continue reading below.
I want to round a float value, which is
56.6748939 to 56.7
56.45678 to 56.5
56.234589 to 56.2
Actually it can be any number of decimal precisions. But I want to round it to nearest value. (If it is greater than or equal to 5, then round up and if not, then round down).
I can do that with the below code.
float value = 56.68899
NSNumberFormatter *numberFormatter = [[NSNumberFormatter alloc]init];
[numberFormatter setMaximumFractionDigits:1];
[numberFormatter setRoundingMode:NSNumberFormatterRoundUp];
NSString *roundedString = [numberFormatter stringFromNumber:[NSNumber numberWithFloat:value]];
NSNumber *roundedNumber = [NSNumber numberFromString:roundedString];
float roundedValue = [roundedNumber floatValue];
Above code looks like a long process. I have several numbers to round off. So this process is hard to convert a float value into NSNumber and to NSString and to NSNumber and to float.
Is there any other easy way to achieve what I asked ?
I still have a doubt in the above code. It says roundUp. So when it comes to roundDown, will it work?
Can't you simply multiply by 10, round the number, then divide by 10?
Try
CGFloat float1 = 56.6748939f;
CGFloat float2 = 56.45678f;
NSLog(#"%.1f %.1f",float1,float2);
56.7 56.5
EDIT :
float value = 56.6748939f;
NSString *floatString = [NSString stringWithFormat:#"%.1f",floatValue];
float roundedValue = [floatString floatValue];
NSString* strr=[NSString stringWithFormat: #"%.1f", 3.666666];
NSLog(#"output is: %#",strr);
output is:3.7
float fCost = [strr floatValue];
This works for me
NSNumberFormatter* formatter = [[NSNumberFormatter alloc] init];
[formatter setMaximumFractionDigits:1];
[formatter setMinimumFractionDigits:0];
CGFloat firstnumber = 56.6748939;
NSString *result1 = [formatter stringFromNumber:[NSNumber numberWithFloat:firstnumber]];
NSLog(#"RESULT #1: %#",result1);
CGFloat secondnumber = 56.45678;
NSString *result2 = [formatter stringFromNumber:[NSNumber numberWithFloat:secondnumber]];
NSLog(#"RESULT #2: %#",result2);
CGFloat thirdnumber = 56.234589;
NSString *result3 = [formatter stringFromNumber:[NSNumber numberWithFloat:thirdnumber]];
NSLog(#"RESULT #2: %#",result3);
You don't want float, because that only gives you six or seven digits precision. You also don't want CGFloat, because that only gives you six or seven digits precision except on an iPad Air or iPhone 5s. You want to use double.
Rounding to one digit is done very simply:
double x = 56.6748939;
double rounded = round (10 * x) / 10;
You can use
[dictionaryTemp setObject:[NSString stringWithFormat:#"%.1f",averageRatingOfAllOrders] forKey:#"AvgRating"];
%.1f will give us value 2.1 only one digit after decimal point.
Try this :
This will round to any value not limited by powers of 10.
extension Double {
func roundToNearestValue(value: Double) -> Double {
let remainder = self % value
let shouldRoundUp = remainder >= value/2 ? true : false
let multiple = floor(self / value)
let returnValue = !shouldRoundUp ? value * multiple : value * multiple + value
return returnValue
}
}

Resources