UIDatePicker odd behavior when setting minuteInterval - ios

The following code displays an odd behavior under iOS 4.3 (maybe others version too). In this example, a UIDatePicker whose date is set to 4 Aug 2011 2:31 PM is displayed. The UILabel below the UIDatePicker displays the date for reference. The three UIButtons below, labeled 1, 5, 10 set the minuteInterval on the UIDatePicker.
Tapping 1 - shows the selected date in the UIDatePicker to be 4 Aug 2011 2:31 PM, and the minute interval is 1, which is to be expected.
Tapping 5 - shows the selected date in the UIDatePicker to be 4 Aug 2011 2:35 PM, and the minute interval is 5, which is to be expected (one could argue the time should round down, but that is not a huge issue).
Tapping 10 - shows the selected date in the UIDatePicker to be 4 Aug 2011 2:10 PM, and the minute interval is 10. Okay the minute interval is correct, but the selected time is 2:10? One would have expected 2:40 (if rounded up) or 2:30 (if rounded down).
BugDatePickerVC.h
#import <UIKit/UIKit.h>
#interface BugDatePickerVC : UIViewController {
NSDateFormatter *dateFormatter;
NSDate *date;
UIDatePicker *datePicker;
UILabel *dateL;
UIButton *oneB;
UIButton *fiveB;
UIButton *tenB;
}
- (void) buttonEventTouchDown:(id)sender;
#end
BugDatePickerVC.m
import "BugDatePickerVC.h"
#implementation BugDatePickerVC
- (id) init
{
if ( !(self = [super init]) )
{
return self;
}
dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateFormat = #"d MMM yyyy h:mm a";
date = [[dateFormatter dateFromString:#"4 Aug 2011 2:31 PM"] retain];
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// Date picker
datePicker = [[UIDatePicker alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 320.0f, 216.0f)];
datePicker.date = date;
datePicker.minuteInterval = 1;
[self.view addSubview:datePicker];
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// Label with the date.
dateL = [[UILabel alloc] initWithFrame:CGRectMake(10.0f, 230.0f, 300.0f, 32.0f)];
dateL.text = [dateFormatter stringFromDate:date];
[self.view addSubview:dateL];
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// Button that set the date picker's minute interval to 1.
oneB = [UIButton buttonWithType:UIButtonTypeRoundedRect];
oneB.frame = CGRectMake(10.0f, 270.0f, 100.0f, 32.0f);
oneB.tag = 1;
[oneB setTitle:#"1" forState:UIControlStateNormal];
[oneB addTarget:self
action:#selector(buttonEventTouchDown:)
forControlEvents:UIControlEventTouchDown];
[self.view addSubview:oneB];
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// Button that set the date picker's minute interval to 5.
fiveB = [UIButton buttonWithType:UIButtonTypeRoundedRect];
fiveB.frame = CGRectMake(10.0f, 310.0f, 100.0f, 32.0f);
fiveB.tag = 5;
[fiveB setTitle:#"5" forState:UIControlStateNormal];
[fiveB addTarget:self
action:#selector(buttonEventTouchDown:)
forControlEvents:UIControlEventTouchDown];
[self.view addSubview:fiveB];
// = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
// Button that set the date picker's minute interval to 10.
tenB = [UIButton buttonWithType:UIButtonTypeRoundedRect];
tenB.frame = CGRectMake(10.0f, 350.0f, 100.0f, 32.0f);
tenB.tag = 10;
[tenB setTitle:#"10" forState:UIControlStateNormal];
[tenB addTarget:self
action:#selector(buttonEventTouchDown:)
forControlEvents:UIControlEventTouchDown];
[self.view addSubview:tenB];
return self;
}
- (void) dealloc
{
[dateFormatter release];
[date release];
[datePicker release];
[dateL release];
[oneB release];
[fiveB release];
[tenB release];
[super dealloc];
}
- (void) buttonEventTouchDown:(id)sender
{
datePicker.minuteInterval = [sender tag];
}

Okay so I was able to change the behavior by explicitly setting the UIDatePicker date value to the date rounded to the minute interval using the following code:
- (void) handleUIControlEventTouchDown:(id)sender
{
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Set the date picker's minute interval.
NSInteger minuteInterval = [sender tag];
// Setting the date picker's minute interval can change what is selected on
// the date picker's UI to a wrong date, it does not effect the date
// picker's date value.
//
// For example the date picker's date value is 2:31 and then minute interval
// is set to 10. The date value is still 2:31, but 2:10 is selected on the
// UI, not 2:40 (rounded up) or 2:30 (rounded down).
//
// The code that follow's setting the date picker's minute interval
// addresses fixing the date value (and the selected date on the UI display)
// . In the example above both would be 2:30.
datePicker.minuteInterval = minuteInterval;
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Calculate the proper date value (and the date to be selected on the UI
// display) by rounding down to the nearest minute interval.
NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:NSMinuteCalendarUnit fromDate:date];
NSInteger minutes = [dateComponents minute];
NSInteger minutesRounded = ( (NSInteger)(minutes / minuteInterval) ) * minuteInterval;
NSDate *roundedDate = [[NSDate alloc] initWithTimeInterval:60.0 * (minutesRounded - minutes) sinceDate:date];
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Set the date picker's value (and the selected date on the UI display) to
// the rounded date.
if ([roundedDate isEqualToDate:datePicker.date])
{
// We need to set the date picker's value to something different than
// the rounded date, because the second call to set the date picker's
// date with the same value is ignored. Which could be bad since the
// call above to set the date picker's minute interval can leave the
// date picker with the wrong selected date (the whole reason why we are
// doing this).
NSDate *diffrentDate = [[NSDate alloc] initWithTimeInterval:60 sinceDate:roundedDate];
datePicker.date = diffrentDate;
[diffrentDate release];
}
datePicker.date = roundedDate;
[roundedDate release];
}
Pay attention to the part where the UIDatePicker's date is set twice. It was fun figuring that out.
Anyone know how to turn the animation off for the call to minuteInterval? The phantom scrolling when clicking 5 then 10 is a little unsightly.

I used the above solution by mmoris and created a method that returns rounded date.. (for ARC)
- (NSDate *)getRoundedDate:(NSDate *)inDate{
NSDate *returnDate;
NSInteger minuteInterval = 10;
NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:NSMinuteCalendarUnit fromDate:inDate];
NSInteger minutes = [dateComponents minute];
NSInteger minutesRounded = ( (NSInteger)(minutes / minuteInterval) ) * minuteInterval;
NSDate *roundedDate = [[NSDate alloc] initWithTimeInterval:60.0 * (minutesRounded - minutes) sinceDate:inDate];
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Set the date picker's value (and the selected date on the UI display) to
// the rounded date.
if ([roundedDate isEqualToDate:inDate])
{
// We need to set the date picker's value to something different than
// the rounded date, because the second call to set the date picker's
// date with the same value is ignored. Which could be bad since the
// call above to set the date picker's minute interval can leave the
// date picker with the wrong selected date (the whole reason why we are
// doing this).
NSDate *diffrentDate = [[NSDate alloc] initWithTimeInterval:60 sinceDate:roundedDate];
returnDate = diffrentDate;
//[diffrentDate release];
}
returnDate = roundedDate;
return returnDate;
}

Here's yet another approach, with an Objective-C category!
I took the spirit of #zurbergram's rounding behavior (up/down to closest) and #mmorris's overall answer and came up with this category:
#import <UIKit/UIKit.h>
#interface UIDatePicker (SetDateRounded)
-(void)setMinimumDateRoundedByMinuteInterval:(NSDate *)minimumDate;
-(void)setDateRoundedByMinuteInterval:(NSDate *)date animated:(BOOL)animatedYesNo;
#end
#implementation UIDatePicker (SetDateRounded)
-(void)setDateRoundedByMinuteInterval:(NSDate *)date animated:(BOOL)animatedYesNo
{
NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:NSMinuteCalendarUnit fromDate:date];
NSInteger minutes = [dateComponents minute];
NSInteger minutesRounded = roundf((float)minutes / (float)[self minuteInterval]) * self.minuteInterval;
NSDate *roundedDate = [[NSDate alloc] initWithTimeInterval:60.0 * (minutesRounded - minutes) sinceDate:date];
[self setDate:roundedDate animated:animatedYesNo];
}
-(void)setMinimumDateRoundedByMinuteInterval:(NSDate *)date
{
NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:NSMinuteCalendarUnit fromDate:date];
NSInteger minutes = [dateComponents minute];
NSInteger minutesRounded = roundf((float)minutes / (float)[self minuteInterval]) * self.minuteInterval;
NSDate *roundedDate = [[NSDate alloc] initWithTimeInterval:60.0 * (minutesRounded - minutes) sinceDate:date];
[self setMinimumDate:roundedDate];
}
#end
Then in your implementation, you can do something like this:
#import "UIDatePicker+SetDateRounded.h"
...
- (void)viewDidLoad
{
[super viewDidLoad];
_datePicker.minuteInterval = 15;
[_datePicker setMinimumDateRoundedByMinuteInterval:[NSDate date]];
[_datePicker setDateRoundedByMinuteInterval:[NSDate date] animated:YES];
}
...
Bonus method: setMinimumDateRoundedByMinuteInterval: lets you set the picker's initial minimum to match the same behavior. One refactor would be to abstract the actual calculation part out into its own method, instead of the copy pasta, but I'm sure folks can optimize that for themselves.

Here is an update version of getRoundedDate: that rounds up or down so that 1:03 pm rounds down to 1:00 pm and 1:12 pm rounds up to 1:15pm
-(NSDate *)getRoundedDate:(NSDate *)inDate
{
NSInteger minuteInterval = 15;
NSDateComponents *dateComponents = [[NSCalendar currentCalendar] components:NSMinuteCalendarUnit fromDate:inDate];
NSInteger minutes = [dateComponents minute];
float minutesF = [[NSNumber numberWithInteger:minutes] floatValue];
float minuteIntervalF = [[NSNumber numberWithInteger:minuteInterval] floatValue];
// Determine whether to add 0 or the minuteInterval to time found by rounding down
NSInteger roundingAmount = (fmodf(minutesF, minuteIntervalF)) > minuteIntervalF/2.0 ? minuteInterval : 0;
NSInteger minutesRounded = ( (NSInteger)(minutes / minuteInterval) ) * minuteInterval;
NSDate *roundedDate = [[NSDate alloc] initWithTimeInterval:60.0 * (minutesRounded + roundingAmount - minutes) sinceDate:inDate];
return roundedDate;
}

I had the same problem with a UIDatePicker only with hours and minutes, every time I selected a time the picker add 20 minutes in the UI, not in the selected time. The solution was quite easy in my case, set the picker.minuteInterval=5 before setting the value of the picker.
Hope this will help to other people.

zurbergram code in Swift :
func getRoundedDate(inDate: NSDate) -> NSDate {
let minuteInterval = 15
let dateComponents = NSCalendar.currentCalendar().components(NSCalendarUnit.MinuteCalendarUnit, fromDate: inDate)
let minutes = dateComponents.minute
let minutesF = NSNumber(integer: minutes).floatValue
let minuteIntervalF = NSNumber(integer: minuteInterval).floatValue
// Determine whether to add 0 or the minuteInterval to time found by rounding down
let roundingAmount = (fmodf(minutesF, minuteIntervalF)) > minuteIntervalF/2.0 ? minuteInterval : 0
let minutesRounded = (minutes / minuteInterval) * minuteInterval
let timeInterval = NSNumber(integer: (60 * (minutesRounded + roundingAmount - minutes))).doubleValue
let roundedDate = NSDate(timeInterval: timeInterval, sinceDate: inDate )
return roundedDate
}

Swift 4 version
func round(date: Date, for minuteInterval: Int) -> Date {
let dateComponents = Calendar.current.dateComponents([.minute], from: date)
let minutes = dateComponents.minute!
// Determine whether to add 0 or the minuteInterval to time found by rounding down
let intervalRemainder = Double(minutes).truncatingRemainder(
dividingBy: Double(minuteInterval)
)
let halfInterval = Double(minuteInterval) / 2.0
let roundingAmount: Int
if intervalRemainder > halfInterval {
roundingAmount = minuteInterval
} else {
roundingAmount = 0
}
let minutesRounded = minutes / minuteInterval * minuteInterval
let timeInterval = TimeInterval(
60 * (minutesRounded + roundingAmount - minutes)
)
let roundedDate = Date(timeInterval: timeInterval, since: date)
return roundedDate
}

Related

Time coming in NSDate format

I'm using ActionSheetDatePicker for time picker i change mode in picker as UIDatePickerModeCountDownTimer to take Hours and Minutes. It works well displayed Hours and min but when i getting Hrs and Min it return me NSDate init.
Ex. I selected 5 min to return me 300, so i get.
Here is code :
ActionSheetDatePicker *datePicker = [[ActionSheetDatePicker alloc] initWithTitle:#"Select a time" datePickerMode:UIDatePickerModeCountDownTimer selectedDate:self.selectedTime target:self action:#selector(ExtrTravelTimeWasSelected:element:) origin:sender];
datePicker.minuteInterval = minuteInterval;
[datePicker showActionSheetPicker];
and delegate
- (void)ExtrTravelTimeWasSelected:(NSDate *)selectedTime element:(id)element {
self.selectedTime = selectedTime;
}
So Is there any way to convert 300(NSDate) to Hr and Min ?
If I'm understanding correctly you're getting the value in seconds. try the following:
-(NSString *)getTimeStringFromSeconds:(double)seconds
{
NSDateComponentsFormatter *dcFormatter = [[NSDateComponentsFormatter alloc] init];
dcFormatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorPad;
dcFormatter.allowedUnits = NSCalendarUnitHour | NSCalendarUnitMinute;
dcFormatter.unitsStyle =
NSDateComponentsFormatterUnitsStylePositional;
return [dcFormatter stringFromTimeInterval:seconds];
}
Try this, I have updated your code,
- (void)ExtrTravelTimeWasSelected:(NSDate *)selectedTime element:(id)element {
self.selectedTime = selectedTime;
// Split up the date components
NSDateComponents *time = [[NSCalendar currentCalendar]
components:NSCalendarUnitHour | NSCalendarUnitMinute
fromDate:selectedTime];
NSLog(#"h:mm::%zd:%2zd",[time hour],[time minute]);
}

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 :)

NSDate and AVPlayerItem.currentTime

i know there are a lot of topics, but i can´t find a solution for my problem.
i have an AVPlayerItem and i want the currentTime-property (CMTime) convert to a readable format for my music player.
this is my code:
NSDate *seconds = [[NSDate alloc] initWithTimeIntervalSinceNow:CMTimeGetSeconds(self.playerItem.currentTime)];
NSDateFormatter *timeFormatter = [[NSDateFormatter alloc] init];
[timeFormatter setDateFormat:#"HH:mm:ss"];
self.currentTimeLabel.text = [NSString stringWithFormat:#"%#", [timeFormatter stringFromDate:seconds]];
it works but it adds 1 hour to the played Time. how can i subtract that hour?
thx!
try this code,
swift code:
delclare
var playerVal = AVPlayer()
then call below method where you want,
func updateTime() {
let currentTime = Float(CMTimeGetSeconds(playerVal.currentTime()))
let minutes = currentTime/60
let seconds = currentTime - minutes * 60
startValue.text = NSString(format: "%.2f:%.2f", minutes,seconds) as String
}
objective-C code:
delclare
AVPlayer playerVal;
then call below method where you want,
- (void)updateTime {
Float currentTime = CMTimeGetSeconds([playerVal currentTime]);
Float minutes = currentTime/60;
Float seconds = (currentTime - minutes) * 60;
startValue.text = [NSString stringWithFormat:#"%.2f:%.2f", minutes,seconds];
}
its working for me, hope its helpful
thx, i refined it a bit:
float currentTime = CMTimeGetSeconds([self.audioStreamPlayer currentTime]);
int seconds = (int) currentTime;
int minutes = (int) currentTime/60;
int hours = (int) ((currentTime/60)/60);
NSString *hoursString = [NSString stringWithFormat:#"%d",hours];
NSString *minutesString = [NSString stringWithFormat:#"%d",minutes];
NSString *secondsString = [NSString stringWithFormat:#"%d",seconds % 60];
if (hoursString.length == 1) {
hoursString = [NSString stringWithFormat:#"0%d", hours];
}
if (minutesString.length == 1) {
minutesString = [NSString stringWithFormat:#"0%d",minutes];
}
if (secondsString.length == 1) {
secondsString = [NSString stringWithFormat:#"0%d", seconds % 60];
}
self.currentTimeLabel.text = [NSString stringWithFormat:#"%#:%#:%#", hoursString, minutesString, secondsString];
works!

Handle Foursquare hours API to find out if the venue is opened or closed

I have a foursquare hours array (Foursquare API) that stores segments of hours when a specific venue is open. It looks something like this:
[{
"days":[1,2,3,4,7],
"includesToday":true,
"open":[
{"end":"+0200","start":"1000"}],
"segments":[]},
{
"days":[5,6]
,"open":[
{"end":"+0300","start":"1000"}],
"segments":[]}
]
How do I find out if the venue is opened or closed at current time?
I handle it like this: 4sq hours API gist
-(NSDictionary*)isVenueOpenDictionaryForHours:(NSArray*)hours{
// defaults and inits
NSCalendar *gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDictionary *lastSegmentYesterday = [[NSDictionary alloc] init];
NSDate *dateNow = [NSDate date];
NSString *venueOpenText = [[NSString alloc] init];
NSString *venueOpen = #"no";
// get components for today
NSDateComponents *compsNow = [gregorian components:NSWeekdayCalendarUnit|NSHourCalendarUnit|NSMinuteCalendarUnit|NSDayCalendarUnit|NSMonthCalendarUnit|NSYearCalendarUnit fromDate:dateNow];
// get weekday for today and yesterday so we can lookup 4sq API
NSInteger weekday = [compsNow weekday];
NSInteger weekdayYesterday = (weekday>1)?weekday-1:7;
// look for todays' segment
NSMutableArray *venueOpenSegments = [[NSMutableArray alloc] init]; // stores all the segments when the venue is open
for (NSDictionary *segment in hours){
// get today's segment (if it exists)
if ([segment[#"days"] containsObject:[NSNumber numberWithInteger:weekday]]){
for (NSDictionary *dictOpen in segment[#"open"])
[venueOpenSegments insertObject:#{#"end": [dictOpen[#"end"] mutableCopy], #"start":[dictOpen[#"start"] mutableCopy]}.mutableCopy atIndex:venueOpenSegments.count];
}
// check the day before if the venue is open past midnight
if (([segment[#"days"] containsObject:[NSNumber numberWithInteger:weekdayYesterday]] && [segment[#"open"] count])){
// get the last segment (that should be the one passing midnight)
NSDictionary *tempSegment = [segment[#"open"] lastObject];
// if it has more than 4 characters it's after midnight ("+02:00"), also, ignore if it closes at midnight
if ([tempSegment[#"end"] length] > 4 && ![tempSegment[#"end"]isEqualToString:#"+0000"]){
// create a new segment that starts at midnight and lasts till the time it closes (early AMs usually)
lastSegmentYesterday = #{#"start":#"0000", #"end":[tempSegment[#"end"] substringFromIndex:1]};
}
}
}
// add last night segment that passes midnight as the first segment of today
if (lastSegmentYesterday.count){
[venueOpenSegments insertObject:lastSegmentYesterday atIndex:0];
}
// go through all the segments and find out if the venue is closed or open
if (venueOpenSegments.count){
NSDateComponents *comps = [[NSDateComponents alloc] init];
NSDateFormatter *timeFormatter = [[NSDateFormatter alloc]init];
timeFormatter.dateFormat = #"HH:mm"; // set time output format
int segmentNumber = 0;
for (NSMutableDictionary *segment in venueOpenSegments){
segmentNumber++;
// confing start date
[comps setDay:compsNow.day];
[comps setMonth:compsNow.month];
[comps setYear:compsNow.year];
[comps setHour:[[segment[#"start"] substringToIndex:2] intValue]];
[comps setMinute:[[segment[#"start"] substringFromIndex:2] intValue]];
NSDate *dateStart = [[[NSCalendar currentCalendar] dateFromComponents:comps] copy];
// config end date
// check if the segment goes to next day
BOOL closesTomorrow = NO;
if ( [segment[#"end"] length]==5 ){
segment[#"end"] = [segment[#"end"] substringFromIndex:1];
closesTomorrow = YES;
}
[comps setHour:[[segment[#"end"] substringToIndex:2] intValue]];
[comps setMinute:[[segment[#"end"] substringFromIndex:2] intValue]];
NSDate *dateEnd = [[[NSCalendar currentCalendar] dateFromComponents:comps] copy];
// add a day if it closes tomorrow
if (closesTomorrow){
NSDateComponents *nextDayComponent = [[NSDateComponents alloc] init];
nextDayComponent.day = 1;
dateEnd = [gregorian dateByAddingComponents:nextDayComponent toDate:dateEnd options:0];
}
// start checking if it's open or closed
// now < segment start
if ([dateNow compare:dateStart] == NSOrderedAscending){
venueOpenText = [NSString stringWithFormat:#"opens at %#",[timeFormatter stringFromDate: dateStart]];
venueOpen = #"later";
break;
}
// segment end < now
else if ([dateEnd compare:dateNow] == NSOrderedAscending){
if (segmentNumber == venueOpenSegments.count){
venueOpenText = [NSString stringWithFormat:#"closed since %#",[timeFormatter stringFromDate: dateEnd]];
break;
}
continue;
}
// segment start < now < segment end
else if ([dateStart compare:dateNow] == NSOrderedAscending && [dateNow compare:dateEnd] == NSOrderedAscending){
venueOpenText = [NSString stringWithFormat:#"open till %#",[timeFormatter stringFromDate: dateEnd]];
venueOpen = #"yes";
break;
}
// rare but possible... last minute of the venue being open (I treat it as closed)
else {
venueOpenText = #"closing right now";
}
}
}
else venueOpen = #"closed today"; // no segments for today, so it's closed for the dayæ
// return results
return #{#"open":venueOpen, #"string":venueOpenText};
}
and I update my UILabel like this:
NSDictionary *venueOpen = [self isVenueOpenDictionaryForHours:_arrayVenues[indexPath.row][#"hours"]];
label.text = venueOpen[#"string"];
if ([venueOpen[#"open"] isEqualToString:#"no"]){
label.textColor = [UIColor colorWithHexString:#"b91d47" alpha:1]; // red
} else if ([venueOpen[#"open"] isEqualToString:#"yes"]) {
label.textColor = [UIColor colorWithHexString:#"1e7145" alpha:1]; // green
} else if ([venueOpen[#"open"] isEqualToString:#"later"]) {
label.textColor = [UIColor colorWithHexString:#"e3a21a" alpha:1]; // yellow
}
BTW, I use pod 'HexColors' for colorWithHexString methods

NSDate to Tick conversion

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;
}

Resources