0

It may sound simple however I am unsure how to do this. How do I display time in the following format?:

-00:00:00

I have tried using float and int values of the interval difference between two times however neither give a consistent display in the 00:00:00 format. I have also tried converting the time difference into date and then display as String.

This is the code I have used to convert my intervals :

NSDate * now = [NSDate date];
NSTimeInterval totalTime1 = [now timeIntervalSinceDate: timeEntry1];
NSTimeInterval totalTime2 = [now timeIntervalSinceDate: timeEntry2];

//must always be this way
int adjustedTime = totalTime1 - totalTime2;

int hours = adjustedTime / 3600;
int minutes = (adjustedTime / 60) % 60;
int seconds = adjustedTime % 60;

NSString * newTime = [NSString stringWithFormat:@"%02u:%02u:%02u", hours, minutes, seconds];

The above works fine for displaying positive time differences. However presents a variety of 00:423456:978098 and so on when it goes negative in both the NSLog and the Label.

When I convert and save as a type of NSDate I get (null) in NSLog and nothing in my Label.

When I use float it works but does not consistently display in the 00:00:00 format.

NOTE

The code I am using works immaculately for positive time differences. I need negative time differences to also display.

I also need to be able to save the negative time to CoreData. If this is not possible then I will work around, but displaying negative time formatted correctly is the main issue.

EDIT

My new revised code:

NSDate * now = [NSDate date];
NSTimeInterval totalTime1 = [now timeIntervalSinceDate: timeEntry1];
NSTimeInterval totalTime2 = [now timeIntervalSinceDate: timeEntry2];

//must always be this way
int adjustedTime = (int) (totalTime1 - totalTime2);
NSLog (@"What is the adjustedTime? %d", adjustedTime);

int hours = adjustedTime / 3600;
int minutes = (adjustedTime / 60) % 60;
int seconds = adjustedTime % 60;

NSString * newTime = [NSString stringWithFormat:@"%@%02d:%02d:%02d", adjustedTime < 0 ?@"-":@"", hours, minutes, seconds];
NSLog(@"What is the newTime? %@", newTime);

It is closer as now it displays negative numbers however the display is still incorrect when negative.

EDIT 2

A person who answered below suggested I try checking for negative if it is a boolean. Displaying did not change. Below are more log statements to demonstrate. NOTE I stopped using an updated seconds for sake of working out whether it affected the display and stored seconds separate to test, which is why there is no - sign or alteration to the seconds.

2015-01-09 09:30:14.526 App2.0[8398:498707] What is time 2 : 720
2015-01-09 09:30:14.526 App2.0[8398:498707] What is time 1 : 771
2015-01-09 09:30:14.526 App2.0[8398:498707] What is the adjusted time? 51
2015-01-09 09:30:14.527 App2.0[8398:498707] New Time: 00:00:51

2015-01-09 09:30:18.249 App2.0[8398:498707] What is time 2 : 900
2015-01-09 09:30:18.249 App2.0[8398:498707] What is time 1 : 771
2015-01-09 09:30:18.249 App2.0[8398:498707] What is the adjusted time? -129
2015-01-09 09:30:18.249 App2.0[8398:498707] New Time: -00:-2:51

2015-01-09 09:30:20.281 App2.0[8398:498707] What is time 2 : 840
2015-01-09 09:30:20.281 App2.0[8398:498707] What is time 1 : 771
2015-01-09 09:30:20.281 App2.0[8398:498707] What is the adjusted time? -69
2015-01-09 09:30:20.281 App2.0[8398:498707] New Time: -00:-1:51

2015-01-09 09:30:21.725 App2.0[8398:498707] What is time 2 : 780
2015-01-09 09:30:21.726 App2.0[8398:498707] What is time 1 : 771
2015-01-09 09:30:21.726 App2.0[8398:498707] What is the adjusted time? -9
2015-01-09 09:30:21.726 App2.0[8398:498707] New Time: -00:00:51

2015-01-09 09:30:30.161 App2.0[8398:498707] What is time 2 : 1080
2015-01-09 09:30:30.161 App2.0[8398:498707] What is time 1 : 771
2015-01-09 09:30:30.162 App2.0[8398:498707] What is the adjusted time? -309
2015-01-09 09:30:30.162 App2.0[8398:498707] New Time: -00:-5:51

2015-01-09 09:30:33.389 App2.0[8398:498707] What is time 2 : 4680
2015-01-09 09:30:33.389 App2.0[8398:498707] What is time 1 : 771
2015-01-09 09:30:33.390 App2.0[8398:498707] What is the adjusted time? -3909
2015-01-09 09:30:33.390 App2.0[8398:498707] New Time: --1:-5:51

2015-01-09 09:30:36.186 App2.0[8398:498707] What is time 2 : 8280
2015-01-09 09:30:36.187 App2.0[8398:498707] What is time 1 : 771
2015-01-09 09:30:36.187 App2.0[8398:498707] What is the adjusted time? -7509
2015-01-09 09:30:36.187 App2.0[8398:498707] New Time: --2:-5:51

2015-01-09 09:30:43.918 App2.0[8398:498707] What is time 2 : 660
2015-01-09 09:30:43.918 App2.0[8398:498707] What is time 1 : 771
2015-01-09 09:30:43.919 App2.0[8398:498707] What is the adjusted time? 111
2015-01-09 09:30:43.919 App2.0[8398:498707] New Time: 00:01:51
App Dev Guy
  • 5,396
  • 4
  • 31
  • 54
  • In your format you use unsigned so setting negative params is a problem. You should also manage negativity separately and keep all your params positive when you create the format (use negativity as a flag to add a dash). – Wain Jan 08 '15 at 07:37
  • have your tried to do the same procedure with `unsigned int` vars? – holex Jan 08 '15 at 08:31
  • Yeh tried based on one of the suggestion earlier however made no difference. – App Dev Guy Jan 08 '15 at 08:33
  • You need to take care when using modulo on a negative number. The implementation for negative numbers might be left up to the implementation of a C=based language. You should use the absolute value of adjustedTime for the calculations of hours, minutes and seconds – Walt Sellers Jan 08 '15 at 08:46
  • @WaltSellers could you elaborate please? – App Dev Guy Jan 08 '15 at 08:53
  • 1
    As noted in the following SO article, in Objective-C, the modulo of a negative is also negative. The example: -1 % 3 == -1. http://stackoverflow.com/questions/989943/weird-objective-c-mod-behavior-for-negative-numbers – Walt Sellers Jan 08 '15 at 08:56
  • 1
    @SASmith Maybe this belongs to Stackexchange/Philosophy, but a "negative time" would be before the universe. Probably you have a negative time interval. ;-) – Amin Negm-Awad Jan 08 '15 at 09:16
  • @Amin Negm-Awad I like the thought but in all seriousness I'm measuring to a point only hours past and not before the beginning of time lol. – App Dev Guy Jan 08 '15 at 09:43

4 Answers4

2

Since you're displaying the time components separately, you'll probably need some conditional logic to adjust the display depending on whether totalTime2 is before or after totalTime1 :

NSString *newTime = nil;

if (adjustedTime < 0) {
    newTime = [NSString stringWithFormat:@"-%02d:%02d:%02d", hours, minutes, seconds];
} 
else {
    newTime = [NSString stringWithFormat:@"%02d:%02d:%02d", hours, minutes, seconds];
}

or if you prefer something more compact:

NSString *newTime = adjustedTime < 0 ? @"-" : @"";
newTime = [newTime stringByAppendingFormat:@"%02d:%02d:%02d", hours, minutes, seconds];

Also, as Wain points out in the comments, you'll need to take the absolute value of each component before using it to display:

int hours = abs(adjustedTime / 3600);
int minutes = abs((adjustedTime / 60) % 60);
int seconds = abs(adjustedTime % 60);
App Dev Guy
  • 5,396
  • 4
  • 31
  • 54
Caleb
  • 124,013
  • 19
  • 183
  • 272
  • 2
    But you also need to `abs` your values for hours, mins and secs – Wain Jan 08 '15 at 07:46
  • While it is a logical suggestion it does not work when using ints. It just adds a '-' before displaying so looks like this -00:429469897:... Thanks for the suggestion though. – App Dev Guy Jan 08 '15 at 07:47
  • @SASmith See Wain's comment just above -- you do need to take the absolute value. Those long numbers you're getting are the result of displaying a signed (negative) integer as unsigned. I'll update the code above. – Caleb Jan 08 '15 at 07:51
  • Your edit has made no difference. It still displays the same as I mentioned in my first comment. Any other ideas? – App Dev Guy Jan 08 '15 at 07:54
  • Still nothing either sadly.Check my updated log statements as they contain how it displays with all three answers posted so far. – App Dev Guy Jan 09 '15 at 01:43
0

That should do the trick:

  NSDate *now = [NSDate date];
  NSTimeInterval totalTime1 = [now timeIntervalSinceDate: timeEntry1];
  NSTimeInterval totalTime2 = [now timeIntervalSinceDate: timeEntry2];

  NSLog(@"totalTime1: %f", totalTime1); // =>  -60.00;
  NSLog(@"totalTime2: %f", totalTime2); // => 6023.00;

  //must always be this way
  int timeOffset = (int) (totalTime1 - totalTime2);
  NSLog(@"timeOffset: %d", timeOffset); // => -6083;

  BOOL showNegativePrefix = timeOffset < 0;

  int hours   = abs(timeOffset / 3600);       // => 01
  int minutes = abs((timeOffset / 60 ) % 60); // => 41
  int seconds = abs(timeOffset % 60);         // => 23

  NSString * newTime = [NSString stringWithFormat:@"%@%02d:%02d:%02d", showNegativePrefix ? @"-" : @"", hours, minutes, seconds];
  NSLog(@"%@", newTime); // => -01:41:23
  • Very close, it is still displaying a negative value if the time difference is only minutes so displays like so: -00:-13:00 – App Dev Guy Jan 08 '15 at 07:58
  • are you sure you did not mixed some code? hours, minutes and seconds can't be negative numbers anymore. –  Jan 08 '15 at 08:01
  • Very sure I copy and pasted your suggestion and it displays like so for difference less than 1 hour -00:-13:00 and greater than an hour like so: --01:-13:00 – App Dev Guy Jan 08 '15 at 08:02
  • i updated my answer. I can't reproduce your error. Anyways, changed it to work with unsigned ints. –  Jan 08 '15 at 08:05
  • Adding the `(uint) abs(timeOffset / 3600)` has actually made it worse when going negative. The `uint hours` made no difference. Thanks for your effort though. – App Dev Guy Jan 08 '15 at 08:09
  • have you updated the stringFormat too? i really can not reproduce your behaviour. i've added some more logging information. can you provide the exact values of `totalTime1` and `totalTime2` for debugging purpose? –  Jan 08 '15 at 08:14
  • just add some logs and show us the data, otherwise i can not help you anymore. –  Jan 08 '15 at 08:17
  • it is not possible that hours minutes and seconds are negative. Its an unsigned int. it has no information about being negative or positive anymore. it's always positive. I'm sorry, your logs do not match my code. Have you updated the stringFormat too? –  Jan 08 '15 at 08:31
  • I did not even see the added `abs` code. Once I added that it worked perfect. Sorry on the mess around. Thanks for the help. Upvote and chosen. – App Dev Guy Jan 09 '15 at 02:08
0

You are almost there, all you need extra is a flag if the value is negative and to then format the positive difference preceded by a sign if needed. First set a flag and make the difference always positive:

int adjustedTime = ...;

BOOL isNeg;
if (adjustedTime < 0)
{
   isNeg = YES;
   adjustedTime = -adjustedTime; // make value +ve
}
else
   isNeg = NO;

then do your math as before and change the format line to:

NSString *newTime = [NSString stringWithFormat:@"%@%02d:%02d:%02d", (isNeg ? @"-" : @""), hours, minutes, seconds];

Note: you need to use %d as your values are int not unsigned int.

HTH

Addendum

Here is the code again, including the bit of yours I skipped ("do your math as before"), with added comments:

int adjustedTime = totalTime1 - totalTime2;

// At this point adjustedTime may be negative, use the standard approach
// test if it is -ve, and if so set a flag and make the value +ve

BOOL isNeg;
if (adjustedTime < 0)
{
   // we are here if -ve, set flag
   isNeg = YES;
   // and make the value +ve
   adjustedTime = -adjustedTime;
}
else
   isNeg = NO;

// at this point adjustedValue is ALWAYS +ve, isNeg is set if it was originally -ve

int hours = adjustedTime / 3600;
int minutes = (adjustedTime / 60) % 60;
int seconds = adjustedTime % 60;

// at this point hours, minutes & seconds MUST BE +VE as adjustedTime is +ve

// format the values, an optional sign based on isNeg followed by three POSITIVE numbers
NSString *newTime = [NSString stringWithFormat:@"%@%02d:%02d:%02d", (isNeg ? @"-" : @""), hours, minutes, seconds];

This can only print AT MOST ONE minus sign at the start from the string.

This approach (though with a test for the minimum negative integer as that cannot be negated) is the standard way to handle this issue.

CRD
  • 52,522
  • 5
  • 70
  • 86
  • This has made no difference to using `adjustedTime < 0 ?@"-":@""` sadly. Thanks for the suggestion. – App Dev Guy Jan 08 '15 at 08:32
  • Did you miss out the `adjustedTime = -adjustedTime` statement? The above changes will ensure the three values are always >= 0 and the only sign you'll get is the one you add. – CRD Jan 08 '15 at 08:50
  • No, I had that but the result when testing was no different to the one I was using. – App Dev Guy Jan 08 '15 at 08:50
  • 1
    Think about it, the change says "if the difference is negative then make it positive and set a flag" - you must have typed something in wrong. – CRD Jan 08 '15 at 08:53
  • I literally used your code. There was no difference at all to using the comparison inside the actual statement: so `[NSString stringWithFormat:@"%@%02d:%02d:%02d", adjustedTime < 0 ?@"-":@"", hours, minutes, seconds]` was no different in it's result. – App Dev Guy Jan 08 '15 at 08:56
  • Seriously have a cup of coffee then try again! – CRD Jan 08 '15 at 09:11
  • Had my coffee. Would you believe it but your answer still did not fix anything. I understand your point. I get that you are saying that the int should only recognise as `-` is it is indeed a negative otherwise remain unsigned. However it doesn't format that way. It still formats as --1:-03:00 if it is an hour and 3 minutes less than the first time. – App Dev Guy Jan 09 '15 at 01:26
  • @SASmith - I've added an addendum - same code but with added comments. This is the easiest way to do it - no messing with multiple calls to `abs()`. – CRD Jan 09 '15 at 05:26
0

The solutions presented by Sebastian Keller and CRD both suffer a problem when rolling over from negative to positive values, for example when displaying a countdown that starts with a negative value:

-1.896893 -00:00:01
-1.498020 -00:00:01
-1.099442 -00:00:01
-0.996686 00:00:00
-0.896971 00:00:00
-0.195021 00:00:00
-0.095020 00:00:00
0.004988 00:00:00
0.104940 00:00:00
0.504980 00:00:00
0.904981 00:00:00
1.000516 00:00:01
1.104926 00:00:01

As can be seen, both solutions actually display 00:00:00 for 2 seconds. The code below instead produces the correct output:

-1.899441 -00:00:02
-1.499838 -00:00:02
-1.095019 -00:00:02
-0.994941 -00:00:01
-0.899903 -00:00:01
-0.195743 -00:00:01
-0.097564 -00:00:01
0.001758  00:00:00
0.100495  00:00:00
0.503691  00:00:00
0.904986  00:00:00
1.004998  00:00:01
1.103652  00:00:01
2.004936  00:00:02

It's actually a category I wrote on NSNumber but the principle should also be applicable to any floating point number:

- (NSString *)ut_hmsString {
    NSString *sign  = (self.floatValue < 0.0f) ? @"-" : @" ";
    float corr      = (self.floatValue < 0.0f) ? 1.0000001f : 0;
    int seconds     = fmodf(fabsf(floorf(self.floatValue)), 60.0f);
    int fakesec     = fabsf(self.floatValue - corr);
    int minutes     = fakesec / 60 % 60;
    int hours       = fakesec / 3600;
    return [NSString stringWithFormat:@"%@%02i:%02i:%02i", sign, hours, minutes, seconds];
}
Mojo66
  • 1,109
  • 12
  • 21