NSTimeInterval Formatting - objective-c

I want to take my NSTimeInterval and format it into a string as 00:00:00 (hours, minutes, seconds). What is the best way to do this?

Since iOS 8.0 there is now NSDateComponentsFormatter which has a stringFromTimeInterval: method.
[[NSDateComponentsFormatter new] stringFromTimeInterval:timeInterval];

"Best" is subjective. The simplest way is this:
unsigned int seconds = (unsigned int)round(myTimeInterval);
NSString *string = [NSString stringWithFormat:#"%02u:%02u:%02u",
seconds / 3600, (seconds / 60) % 60, seconds % 60];
UPDATE
As of iOS 8.0 and Mac OS X 10.10 (Yosemite), you can use NSDateComponentsFormatter if you need a locale-compliant solution. Example:
NSTimeInterval interval = 1234.56;
NSDateComponentsFormatter *formatter = [[NSDateComponentsFormatter alloc] init];
formatter.allowedUnits = NSCalendarUnitHour | NSCalendarUnitMinute |
NSCalendarUnitSecond;
formatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;
NSString *string = [formatter stringFromTimeInterval:interval];
NSLog(#"%#", string);
// output: 0:20:34
However, I don't see a way to force it to output two digits for the hour, so if that's important to you, you'll need to use a different solution.

NSTimeInterval interval = ...;
NSDate *date = [NSDate dateWithTimeIntervalSince1970:interval];
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateFormat:#"HH:mm:ss"];
[dateFormatter setTimeZone:[NSTimeZone timeZoneWithName:#"UTC"]];
NSString *formattedDate = [dateFormatter stringFromDate:date];
NSLog(#"hh:mm:ss %#", formattedDate);

swift 4.2
extension Date {
static func timestampString(timeInterval: TimeInterval) -> String? {
let formatter = DateComponentsFormatter()
formatter.unitsStyle = .positional
formatter.zeroFormattingBehavior = .pad
formatter.maximumUnitCount = 0
formatter.allowedUnits = [.hour, .minute, .second]
return formatter.string(from: timeInterval)
}
}
Test code:
let hour = 60 * 50 * 32
Date.timestampString(timeInterval: TimeInterval(hour))
// output "26:40:00"
Change unitStyle to get different styles. like formatter.unitsStyle = .abbreviated get
output: "26h 40m 0s"

A Swift version of #Michael Frederick's answer :
let duration: NSTimeInterval = ...
let durationDate = NSDate(timeIntervalSince1970: duration)
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "HH:mm:ss"
dateFormatter.timeZone = NSTimeZone(name: "UTC")
let durationString = dateFormatter.stringFromDate(durationDate)

Related

Why do NSDate instances from NSCalendar and NSDateFormatter have slightly different values?

When passing dates over the wire from client to server and back again, I format the date to a string for JSON using the format #"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'" with the #"en_US_POSIX" locale. The same formatter provides an instance of NSDate from the date strings returned from the server to the client.
To test the conversions, I am trying to use NSDateComponents and NSCalendar to generate an independent date to use to validate the date from the formatter. However, the NSDate instances created from the NSCalendar and NSDateComponents vary ever so slightly from the NSDate instances provided by the NSDateFormatter. I do not understand why. Different dates produce a different number of variances. I apologize for yet another NSDate/NSDateFormatter question, but hope you find it somewhat novel.
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
dateFormatter.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
dateFormatter.dateFormat = #"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
dateFormatter.calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSMutableArray *valuesWithError = [NSMutableArray arrayWithCapacity:750];
NSMutableArray *valuesThatMatch = [NSMutableArray arrayWithCapacity:250];
for (NSInteger milliseconds = 0; milliseconds < 1000; milliseconds++) {
NSString *dateString = [NSString stringWithFormat:#"2001-01-01T00:00:00.%03dZ", milliseconds];
NSLog(#"%#", dateString);
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
calendar.locale = [[NSLocale alloc] initWithLocaleIdentifier:#"en_US_POSIX"];
calendar.timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
NSDateComponents *dc = [[NSDateComponents alloc] init];
dc.year = 2001;
dc.month = 1;
dc.day = 1;
dc.hour = 0;
dc.minute = 0;
dc.second = 0;
NSDate *expectedDate = [calendar dateFromComponents:dc];
NSTimeInterval baseInterval = [expectedDate timeIntervalSinceReferenceDate];
double mulitplier = 0.001;
NSTimeInterval millisecondsToAdd = milliseconds * mulitplier;
baseInterval += millisecondsToAdd;
expectedDate = [NSDate dateWithTimeIntervalSinceReferenceDate:baseInterval];
NSDate *dateFromFormat = [dateFormatter dateFromString:dateString];
NSTimeInterval expectedDateFromReferenceDate = [expectedDate timeIntervalSinceReferenceDate];
NSTimeInterval dateFromFormatFromReferenceDate = [dateFromFormat timeIntervalSinceReferenceDate];
NSTimeInterval differenceByTimeIntervalSubtraction = ABS(expectedDateFromReferenceDate - dateFromFormatFromReferenceDate);
NSTimeInterval differenceByTimeIntervalFromDate = [expectedDate timeIntervalSinceDate:dateFromFormat];
if (![expectedDate isEqualToDate:dateFromFormat]) {
NSLog(#"Difference = %e", differenceByTimeIntervalSubtraction);
[valuesWithError addObject:#(milliseconds)];
} else {
[valuesThatMatch addObject:#(milliseconds)];
}
}

NSDate compare is not working well

I've read all the questions and answer and all the tutorial about this subject, but for some reason it's not working for me. always showing me that the two dates are the same date!
Please some one help me to figure it out, I just want to check if one is bigger than the other (including date and time - without seconds) or if they are equal.
This is my code:
- (BOOL)isEndDateIsBiggerThanCurrectDate:(NSDate *)checkEndDate
{
NSString *endd = [NSDateFormatter localizedStringFromDate:checkEndDate
dateStyle:NSDateFormatterShortStyle
timeStyle:NSDateFormatterShortStyle];
NSString *curreeeent = [NSDateFormatter localizedStringFromDate:[NSDate date]
dateStyle:NSDateFormatterShortStyle
timeStyle:NSDateFormatterShortStyle];
NSDateFormatter * df = [[NSDateFormatter alloc]init];;
NSDate * newCurrent = [df dateFromString:endd];
NSDate * newEnd = [df dateFromString:curreeeent];
switch ([newCurrent compare:newEnd])
{
case NSOrderedAscending:
return YES;
break;
case NSOrderedSame:
return NO;
break;
case NSOrderedDescending:
return NO;
break;
}
}
Thank you very much!
For this, you have to use NSCalender.
NSCalendar *calendar = [NSCalendar currentCalendar];
NSInteger desiredComponents = (NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit | NSHourCalendarUnit | NSMinuteCalendarUnit);
NSDateComponents *firstComponents = [calendar components:desiredComponents fromDate:[NSDate date]];
NSDateComponents *secondComponents = [calendar components:desiredComponents fromDate: checkEndDate];
NSDate *first = [calendar dateFromComponents:firstComponents];
NSDate *second = [calendar dateFromComponents:secondComponents];
NSComparisonResult result = [first compare:second];
if (result == NSOrderedAscending) {
//checkEndDate is before now
} else if (result == NSOrderedDescending) {
//checkEndDate is after now
} else {
//both are same
}
You should really be using time intervals rather than converting between dates and strings.
Something like the following should suit your needs:
//current time
NSDate *now = [NSDate date];
//time in the future
NSDate *distantFuture = [NSDate distantFuture];
//gather time interval
if([now timeIntervalSinceDate:distantFuture] > 0)
{
//huzzah!
}
I've got the answer, just checking the exact time between two dates and compare it.
- (BOOL)isEndDateIsSmallerThanCurrent:(NSDate *)checkEndDate
{
NSDate* enddate = checkEndDate;
NSDate* currentdate = [NSDate date];
NSTimeInterval distanceBetweenDates = [enddate timeIntervalSinceDate:currentdate];
double secondsInMinute = 60;
NSInteger secondsBetweenDates = distanceBetweenDates / secondsInMinute;
if (secondsBetweenDates == 0)
return YES;
else if (secondsBetweenDates < 0)
return YES;
else
return NO;
}
Why don't you change the dates into time interval since 1970 and sort by that. Extremely simple number compare, much quicker than string compare, and they will always sort correct, not like 1,10,11,2,21,22,3,....
NSDate *now = [NSDate date];
NSTimeInterval ti = [now timeIntervalSince1970];
Thats it. No new object creations, much quicker and much less taxing on the cpu.
See here how you get rid of seconds, but it is easy because you have numbers, for seconds. See here How to set seconds to zero for NSDate

I would like to display the time statically on a UILabel when the view is loaded

That's the short story.
I have a nib with 6 UILabels for 6 different times.
The goal:
UILabel1 - calculate 90 minutes from current time
UILabel2 - 90 minutes from UILabel1 (or just 180 minutes from current time)
repeat, etc...
I can currently display the current times but I'm not sure how to calculate the times I need (see above).
- (void)viewDidLoad
{
[super viewDidLoad];
NSDate *today = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setTimeStyle:NSDateFormatterShortStyle];
NSString *currentTime1 = [dateFormatter stringFromDate:today];
NSString *currentTime2 = [dateFormatter stringFromDate:today];
NSString *currentTime3 = [dateFormatter stringFromDate:today];
NSString *currentTime4 = [dateFormatter stringFromDate:today];
NSString *currentTime5 = [dateFormatter stringFromDate:today];
NSString *currentTime6 = [dateFormatter stringFromDate:today];
timeLabel1.text = currentTime1;
timeLabel2.text = currentTime2;
timeLabel3.text = currentTime3;
timeLabel4.text = currentTime4;
timeLabel5.text = currentTime5;
timeLabel6.text = currentTime6;
}
Thanks in advance!
sidenote:I have found this to be a such a great place to find answers over the last 2 years!
Date with 90 minutes from current time
NSDate *nextDate = [NSDate dateWithTimeIntervalSinceNow:60*90];
Then
NSString *currentTime2 = [dateFormatter stringFromDate:nextDate ];
timeLabel2.text = currentTime2;
NSDate has the class method dateWithTimeIntervalSinceNow: for this.

Convert NSNumber (double) value into time

i try to convert a value like "898.171813964844" into 00:17:02 (hh:mm:ss).
How can this be done in objective c?
Thanks for help!
Final solution:
NSNumber *time = [NSNumber numberWithDouble:([online_time doubleValue] - 3600)];
NSTimeInterval interval = [time doubleValue];
NSDate *online = [NSDate date];
online = [NSDate dateWithTimeIntervalSince1970:interval];
NSDateFormatter *dateFormatter = [[[NSDateFormatter alloc] init] autorelease];
[dateFormatter setDateFormat:#"HH:mm:ss"];
NSLog(#"result: %#", [dateFormatter stringFromDate:online]);
Assuming you are just interested in hours, minutes and seconds and that the input value is less or equal 86400 you could do something like this:
NSNumber *theDouble = [NSNumber numberWithDouble:898.171813964844];
int inputSeconds = [theDouble intValue];
int hours = inputSeconds / 3600;
int minutes = ( inputSeconds - hours * 3600 ) / 60;
int seconds = inputSeconds - hours * 3600 - minutes * 60;
NSString *theTime = [NSString stringWithFormat:#"%.2d:%.2d:%.2d", hours, minutes, seconds];
I know the answer has already been accepted, but here is my response using NSDateFormatter and taking into account timezone (to your timezone hours [eg. GMT+4] being unexpectedly added #Ben)
NSTimeInterval intervalValue = 898.171813964844;
NSDateFormatter *hmsFormatter = [[NSDateFormatter alloc] init];
[hmsFormatter setDateFormat:#"HH:mm:ss"];
[hmsFormatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
NSLog(#"formatted date: %#", [hmsFormatter stringFromDate:[NSDate dateWithTimeIntervalSinceReferenceDate:intervalValue]]);
[side note] #phx: assuming 898.171813964844 is in seconds, this would represent 00:14:58 not 00:17:02.
Convert your NSNumber value to a NSTimeInterval with -doubleValue
Convert your NSTimeInterval value to a NSDate with +dateWithTimeIntervalSinceNow:
Convert your NSDate to a NSString with -descriptionWithCalendarFormat:timeZone:locale:

Convert NSDate to NSString

How do I convert, NSDate to NSString so that only the year in #"yyyy" format is output to the string?
How about...
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"yyyy"];
//Optionally for time zone conversions
[formatter setTimeZone:[NSTimeZone timeZoneWithName:#"..."]];
NSString *stringFromDate = [formatter stringFromDate:myNSDateInstance];
//unless ARC is active
[formatter release];
Swift 4.2 :
func stringFromDate(_ date: Date) -> String {
let formatter = DateFormatter()
formatter.dateFormat = "dd MMM yyyy HH:mm" //yyyy
return formatter.string(from: date)
}
I don't know how we all missed this: localizedStringFromDate:dateStyle:timeStyle:
NSString *dateString = [NSDateFormatter localizedStringFromDate:[NSDate date]
dateStyle:NSDateFormatterShortStyle
timeStyle:NSDateFormatterFullStyle];
NSLog(#"%#",dateString);
outputs '13/06/12 00:22:39 GMT+03:00'
Hope to add more value by providing the normal formatter including the year, month and day with the time.
You can use this formatter for more than just a year
[dateFormat setDateFormat: #"yyyy-MM-dd HH:mm:ss zzz"];
there are a number of NSDate helpers on the web, I tend to use:
https://github.com/billymeltdown/nsdate-helper/
Readme extract below:
NSString *displayString = [NSDate stringForDisplayFromDate:date];
This produces the following kinds of output:
‘3:42 AM’ – if the date is after midnight today
‘Tuesday’ – if the date is within the last seven days
‘Mar 1’ – if the date is within the current calendar year
‘Mar 1, 2008’ – else ;-)
In Swift:
var formatter = NSDateFormatter()
formatter.dateFormat = "yyyy"
var dateString = formatter.stringFromDate(YourNSDateInstanceHERE)
NSDateFormatter *dateformate=[[NSDateFormatter alloc]init];
[dateformate setDateFormat:#"yyyy"]; // Date formater
NSString *date = [dateformate stringFromDate:[NSDate date]]; // Convert date to string
NSLog(#"date :%#",date);
If you don't have NSDate -descriptionWithCalendarFormat:timeZone:locale: available (I don't believe iPhone/Cocoa Touch includes this) you may need to use strftime and monkey around with some C-style strings. You can get the UNIX timestamp from an NSDate using NSDate -timeIntervalSince1970.
+(NSString*)date2str:(NSDate*)myNSDateInstance onlyDate:(BOOL)onlyDate{
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
if (onlyDate) {
[formatter setDateFormat:#"yyyy-MM-dd"];
}else{
[formatter setDateFormat: #"yyyy-MM-dd HH:mm:ss"];
}
//Optionally for time zone conversions
// [formatter setTimeZone:[NSTimeZone timeZoneWithName:#"..."]];
NSString *stringFromDate = [formatter stringFromDate:myNSDateInstance];
return stringFromDate;
}
+(NSDate*)str2date:(NSString*)dateStr{
if ([dateStr isKindOfClass:[NSDate class]]) {
return (NSDate*)dateStr;
}
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:#"yyyy-MM-dd"];
NSDate *date = [dateFormat dateFromString:dateStr];
return date;
}
Just add this extension:
extension NSDate {
var stringValue: String {
let formatter = NSDateFormatter()
formatter.dateFormat = "yourDateFormat"
return formatter.stringFromDate(self)
}
}
If you are on Mac OS X you can write:
NSString* s = [[NSDate date] descriptionWithCalendarFormat:#"%Y_%m_%d_%H_%M_%S" timeZone:nil locale:nil];
However this is not available on iOS.
It's swift format :
func dateFormatterWithCalendar(calndarIdentifier: Calendar.Identifier, dateFormat: String) -> DateFormatter {
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: calndarIdentifier)
formatter.dateFormat = dateFormat
return formatter
}
//Usage
let date = Date()
let fotmatter = dateFormatterWithCalendar(calndarIdentifier: .gregorian, dateFormat: "yyyy")
let dateString = fotmatter.string(from: date)
print(dateString) //2018
swift 4 answer
static let dateformat: String = "yyyy-MM-dd'T'HH:mm:ss"
public static func stringTodate(strDate : String) -> Date
{
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = dateformat
let date = dateFormatter.date(from: strDate)
return date!
}
public static func dateToString(inputdate : Date) -> String
{
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = dateformat
return formatter.string(from: inputdate)
}
Use extension to have clear code
You can write an extension to convert any Date object to any desired calendar and any format
extension Date{
func asString(format: String = "yy/MM/dd HH:mm",
for identifier: Calendar.Identifier = .persian) -> String {
let formatter = DateFormatter()
formatter.calendar = Calendar(identifier: identifier)
formatter.dateFormat = format
return formatter.string(from: self)
}
}
Then use it like this:
let now = Date()
print(now.asString()) // prints -> 00/04/18 20:25
print(now.asString(format: "yyyy/MM/dd")) // prints -> 1400/04/18
print(now.asString(format: "MM/dd", for: .gregorian)) // prints -> 07/09
To learn how to specify your desired format string take a look at this link.
For a complete reference on how to format dates see Apple's official Date Formatting Guide here.
Simple way to use C# styled way to convert Date to String.
usage:
let a = time.asString()
// 1990-03-25
let b = time.asString("MM ∕ dd ∕ yyyy, hh꞉mm a")
// 03 / 25 / 1990, 10:33 PM
extensions:
extension Date {
func asString(_ template: String? = nil) -> String {
if let template = template {
let df = DateFormatter.with(template: template)
return df.string(from: self)
}
else {
return globalDateFormatter.string(from: self)
}
}
}
// Here you can set default template for DateFormatter
public let globalDateFormatter: DateFormatter = DateFormatter.with(template: "y-M-d")
public extension DateFormatter {
static func with(template: String ) -> DateFormatter {
let df = DateFormatter()
df.dateFormat = template
return df
}
}
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:(NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay) fromDate:myNSDateInstance];
NSInteger year = [components year];
// NSInteger month = [components month];
NSString *yearStr = [NSString stringWithFormat:#"%ld", year];
Define your own utility for format your date required date format
for eg.
NSString * stringFromDate(NSDate *date)
{ NSDateFormatter *formatter
[[NSDateFormatter alloc] init];
[formatter setDateFormat:#"MM ∕ dd ∕ yyyy, hh꞉mm a"];
return [formatter stringFromDate:date];
}
#ios #swift #convertDateinString
Simply just do like this to "convert date into string" as per format you passed:
let formatter = DateFormatter()
formatter.dateFormat = "dd-MM-YYYY" // pass formate here
let myString = formatter.string(from: date) // this will convert Date in String
Note: You can specify different formats such like "yyyy-MM-dd", "yyyy", "MM" etc...
Update for iOS 15
iOS 15 now supports calling .formatted on Date objects directly without an explicit DateFormatter.
Example for common formats
Documentation
date.formatted() // 6/8/2021, 7:30 PM
date.formatted(date: .omitted, time: .complete) // 19:30
date.formatted(date: .omitted, time: .standard) // 07:30 PM
date.formatted(date: .omitted, time: .shortened) // 7:30 PM
date.formatted(date: .omitted, time: .omitted)
Alternative syntax
Documentation
// We can also specify each DateComponent separately by chaining modifiers.
date.formatted(.dateTime.weekday(.wide).day().month().hour().minute())
// Tuesday, Jun 8, 7:30 pm
// Answer to specific question
date.formatted(.dateTime.year())
for Objective-C:
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:0];
NSDateFormatter *formatter = [NSDateFormatter new];
formatter.dateFormat = #"yyyy";
NSString *dateString = [formatter stringFromDate:date];
for Swift:
let now = Date()
let formatter = DateFormatter()
formatter.dateFormat = "yyyy"
let dateString = formatter.string(from: now)
That's a good website for nsdateformatter.You can preview date strings with different DateFormatter in different local.