Dailycode.info

Short solution for short problems

iOS : Show datepicker from UITextfield (Extra Generic function for easy creation below using Categories)

Simple thing to ask and luckily, reasonable simple solution. You can add some code on the Editing Did Begin of your text box:

 

- (IBAction)txtFromClicked:(id)sender

{

    UIViewController* popoverContent = [[UIViewControlleralloc] init]; //ViewController

    

    UIView *popoverView = [[UIView alloc] init];   //view

    popoverView.backgroundColor = [UIColor blackColor];

    

    UIDatePicker *datePicker=[[UIDatePickeralloc]init];//Date picker

    datePicker.frame=CGRectMake(0,44,320, 216);

    datePicker.datePickerMode = UIDatePickerModeDate;

    if (self.txtFrom.text.length>0)

    {

        @try {

            NSDateFormatter * formatter = [[NSDateFormatter alloc]init];

            [formatter setDateFormat:@"dd/MM/yyyy"];

            NSDate * dateToSet = [formatter dateFromString:txt.text];

            datePicker.date = dateToSet;

        }

        @catch (NSException *exception) {

           //if the date is in wrong format, set date to today

           datePicker.date = [NSDate date];

        }

    }

    [datePicker setMinuteInterval:1];

    [datePicker setTag:10];

    [datePicker addTarget:selfaction:@selector(Result:) forControlEvents:UIControlEventValueChanged];

    [popoverView addSubview:datePicker];

    

    popoverContent.view = popoverView;

    self.popoverController = [[UIPopoverControlleralloc] initWithContentViewController:popoverContent];

    self.popoverController.delegate=self;

    

    [self.popoverControllersetPopoverContentSize:CGSizeMake(320, 264) animated:NO];

    [self.popoverControllerpresentPopoverFromRect:self.txtFrom.frameinView:self.viewpermittedArrowDirections:UIPopoverArrowDirectionUpanimated:YES];

}

 

- (void) Result : (id) sender

{

    NSDate * dateSelected = ((UIDatePicker *) sender).date;

    NSDateFormatter * formatter = [[NSDateFormatteralloc]init];

    [formatter setDateFormat:@"dd/MM/yyyy"];

    self.txtFrom.text = [formatter stringFromDate:dateSelected];

}

 
This code does the trick. It will also set the date in the picker if a date was selected before. What it does is simply show the date picker in a popover for the frame of the textfield. The result method has the sender date picker and there you can find the selected date.

To make this code a little more general, because you will use it probably more then once, I made this into a static method in a general class:

+ (UIPopoverController *) CreatePopOverControllerWithDatePickerForTextField: (UITextField *) txt andDelegate: (id) del

{

    UIPopoverController * cont;

    

    UIViewController* popoverContent = [[UIViewControlleralloc] init]; //ViewController

    

    UIView *popoverView = [[UIView alloc] init];   //view

    popoverView.backgroundColor = [UIColor blackColor];

    

    UIDatePicker *datePicker=[[UIDatePickeralloc]init];//Date picker

    datePicker.frame=CGRectMake(0,44,320, 216);

    datePicker.datePickerMode = UIDatePickerModeDate;

    if (txt.text.length>0)

    {

       @try {

            NSDateFormatter * formatter = [[NSDateFormatter alloc]init];

            [formatter setDateFormat:@"dd/MM/yyyy"];

            NSDate * dateToSet = [formatter dateFromString:txt.text];

            datePicker.date = dateToSet;

        }

        @catch (NSException *exception)

        {

            //if the date is in wrong format, set date to today

            datePicker.date = [NSDate date];

        }

    }

    [datePicker setMinuteInterval:1];

    [datePicker setTag:10];

    [datePicker addTarget:del action:@selector(Result:) forControlEvents:UIControlEventValueChanged];

    [popoverView addSubview:datePicker];

    

    popoverContent.view = popoverView;

    cont = [[UIPopoverControlleralloc] initWithContentViewController:popoverContent];

    cont.delegate=del;

    [cont setPopoverContentSize:CGSizeMake(320, 264) animated:NO];

    return cont;

}

Now you can simply create the date picker popover providing the textfield and delegate like this:

@interfacePlanningVC ()

@property (strong, nonatomic) UIPopoverController * popoverController;

@end

 

@implementation PlanningVC

 

@synthesize popoverController;

 

- (IBAction)txtFromClicked:(id)sender

{

    self.popoverController = [GeneralMESFunctionsCreatePopOverControllerWithDatePickerForTextField:self.txtFromandDelegate:self];

    [self.popoverControllerpresentPopoverFromRect:self.txtFrom.frameinView:self.viewpermittedArrowDirections:UIPopoverArrowDirectionUpanimated:YES];

}

 

...

 

So that did the trick, or so I thought. When I tried to use a second text box, I already had a problem in my delegate function, because there I literally assing the value to a specific text box. And in this method, I do not really know from which text box it is coming from. So I solved this in a generic way using categories. I created a category of a date picker and in the method I tell the date picker from which control it is coming from. Then when the Result method is called (Value of the date picker is changed) I can simply ask the date picker from which control its coming from. So first I needed to make a category of UIDatePicker extending the date picker with an extra property if type id. There I store the control:

 

//

//  UIDatePicker+MESUIDatePicker.h

//  GalvaSFIApp

//

//  Created by Mark Deraeve on 10/01/13.

//

 

#import <UIKit/UIKit.h>

 

@interface UIDatePicker (MESUIDatePicker)

@property (retain, nonatomic) id usedField;

@end

 

//

//  UIDatePicker+MESUIDatePicker.m

//  GalvaSFIApp

//

//  Created by Mark Deraeve on 10/01/13.

//

 

#import "UIDatePicker+MESUIDatePicker.h"

#import <objc/runtime.h>

 

static char const * const ObjectTagKey ="ObjectTag";

 

@implementation UIDatePicker (MESUIDatePicker)

@dynamic usedField;

 

- (id) usedField

{

    returnobjc_getAssociatedObject(self, ObjectTagKey);

}

 

- (void)setUsedField:(id) usedField

{

    objc_setAssociatedObject(self, ObjectTagKey, usedField, OBJC_ASSOCIATION_RETAIN_NONATOMIC);

}

 

@end

 

It looks a bit odd, but because it is a category, we have to use the c library to associate the property to the instance of the object. Using id provides us freedom to store whatever kind of control in there. It doesn't have to be a UITextBox.

 

So now I tuned my generic date picker popover creation method to use this category and add the sender textbox to the date picker:

 

#import "UIDatePicker+MESUIDatePicker.h"

 

@implementation GeneralMESFunctions

 

+ (UIPopoverController *) CreatePopOverControllerWithDatePickerForTextField: (UITextField *) txt andDelegate: (id) del

{

    UIPopoverController * cont;

    

    UIViewController* popoverContent = [[UIViewControlleralloc] init]; //ViewController

    

    UIView *popoverView = [[UIView alloc] init];   //view

    popoverView.backgroundColor = [UIColor blackColor];

    

    UIDatePicker *datePicker=[[UIDatePickeralloc]init];//Date picker

    datePicker.frame=CGRectMake(0,44,320, 216);

    datePicker.datePickerMode = UIDatePickerModeDate;

    datePicker.usedField = txt;

    if (txt.text.length>0)

    {

       @try {

            NSDateFormatter * formatter = [[NSDateFormatter alloc]init];

            [formatter setDateFormat:@"dd/MM/yyyy"];

            NSDate * dateToSet = [formatter dateFromString:txt.text];

            datePicker.date = dateToSet;

        }

        @catch (NSException *exception)

        {

            //if the date is in wrong format, set date to today

            datePicker.date = [NSDate date];

        }

    }

    [datePicker setMinuteInterval:1];

    [datePicker setTag:10];

    [datePicker addTarget:del action:@selector(Result:) forControlEvents:UIControlEventValueChanged];

    [popoverView addSubview:datePicker];

    

    popoverContent.view = popoverView;

    cont = [[UIPopoverControlleralloc] initWithContentViewController:popoverContent];

    cont.delegate=del;

    [cont setPopoverContentSize:CGSizeMake(320, 264) animated:NO];

    return cont;

}

 

Finally I can look which control triggered the EventValueChanged event and fill it up, for "completions" sake, I added the whole implementation:

 

//

//  PlanningVC.m

//  GalvaSFIApp

//

//  Created by Mark Deraeve on 29/11/12.

//

 

#import "PlanningVC.h"

#import "GeneralMESFunctions.h"

#import "UIDatePicker+MESUIDatePicker.h"

 

@interfacePlanningVC ()

@property (strong, nonatomic) UIPopoverController * popoverControllerFrom;

@property (strong, nonatomic) UIPopoverController * popoverControllerTo;

@end

 

@implementation PlanningVC

 

@synthesize popoverControllerFrom;

@synthesize popoverControllerTo;

 

- (IBAction)txtToClicked:(id)sender

{

    self.popoverControllerTo = [GeneralMESFunctionsCreatePopOverControllerWithDatePickerForTextField:self.txtToandDelegate:self];

    [self.popoverControllerTopresentPopoverFromRect:self.txtTo.frameinView:self.viewpermittedArrowDirections:UIPopoverArrowDirectionUpanimated:YES];

}

 

- (IBAction)txtFromClicked:(id)sender

{

    self.popoverControllerFrom = [GeneralMESFunctionsCreatePopOverControllerWithDatePickerForTextField:self.txtFromandDelegate:self];

    [self.popoverControllerFrompresentPopoverFromRect:self.txtFrom.frameinView:self.viewpermittedArrowDirections:UIPopoverArrowDirectionUpanimated:YES];

}

 

- (void) Result : (id) sender

{

    UIDatePicker * datePicker = ((UIDatePicker *) sender);

    NSDate * dateSelected = datePicker.date;

    NSDateFormatter * formatter = [[NSDateFormatteralloc]init];

    [formatter setDateFormat:@"dd/MM/yyyy"];

    UITextField * txt = (UITextField *) datePicker.usedField;

    txt.text = [formatter stringFromDate:dateSelected];

}

 

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil

{

    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];

    if (self) {

        // Custom initialization

    }

    returnself;

}

 

- (void)viewDidLoad

{

    [superviewDidLoad];

// Do any additional setup after loading the view.

}

 

- (void)didReceiveMemoryWarning

{

    [superdidReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}

 

@end

 

You could even use only 1 function to capture the touch down events of both text boxes and pass the sender in stead of the self.txt property.

Here you can see the result:

 

***Edit

If you cannot manage with my example, go and have a look here:

https://github.com/TimCinel/ActionSheetPicker

 

If found this when I was looking for a generic way to show a pickerview in a popup. It works great. I created and extra class that inherits from the AbstractActionSheetPicker. 


iOS : Get the current date without time (eg: 2013/1/7 0:0:0)

I had to look for this a minute or 2. Its not that straight forward as .Net. You will have to use the NSDateComponents to create a date with only the year, month and day from the NSDate date. After serialization, the date looks like this: 2013-01-07T00:00:00.00.

Code:

NSDateComponents * dc = [[NSCalendarcurrentCalendar] components:(NSYearCalendarUnit | NSMonthCalendarUnit | NSDayCalendarUnit) fromDate:[NSDatedate]];

plan.ShiftDate = [[NSCalendarcurrentCalendar] dateFromComponents:dc];

 

 

 


How to find the due date for SAP invoices? (extra: or get a date from a string in ABAB)

 

Some of the customized code was not going so good all the time. They asked me to look into this. It appears that the previous programmer did not do such a great job. He simply took the date from the vbdkr-zterm_tx1 text. But this text can have different formats and multiple numbers inside. This was the line of code used before:

ln_due_date vbdkr-zterm_tx1.
CONCATENATE ln_due_date(2'.' ln_due_date+2(2'.' ln_due_date+4(4)
INTO gd_due_date.

The ln_due_date was only 8 char and when you cast a string to type n , it will take the numbers in the string and start from the rear or overwrites. An example:

ln_due_date(8)    TYPE n. 

The content of vbdkr-zterm_tx1 normally looks like this (then the code will work):

Tot 31.08.2012 zonder aftrek

But when the vbdkr-zterm_tx1 was:

Tot 31.08.2012 krijgt u 1,000  % betalingskorting

It went wrong, it became 20.12.1000 instead of 31.08.2012.

Now I replaced this code with a program that is designed to get calculate the due date. This code replaces it and provides a stable and decent solution:

DATABEGIN OF TERMS OCCURS 3.
          
INCLUDE STRUCTURE VTOPIS.
  
DATA:  END OF TERMS.
* Due Date

  
CALL FUNCTION 'SD_PRINT_TERMS_OF_PAYMENT'
    
EXPORTING
     BLDAT                              
vbdkr-FKDAT
     BUDAT                              
vbdkr-FKDAT
     CPUDT                              
vbdkr-FKDAT
     
LANGUAGE                           nast-SPRAS
     TERMS_OF_PAYMENT                   
vbdkr-ZTERM
     
COUNTRY                            vbdkr-LAND1
    
TABLES
      TOP_TEXT                           
TERMS            .

  IF SY-SUBRC <> 0.

 *use the old date conversion if something goes wrong.

 
     ln_due_date 
vbdkr-zterm_tx1.
     
CONCATENATE ln_due_date(2'.' ln_due_date+2(2'.' ln_due_date+4(4)
     
INTO gd_due_date.
  
ENDIF.

  
CONCATENATE TERMS-HDATUM+6(2'.' TERMS-HDATUM+4(2'.' TERMS-HDATUM(4)
      
INTO gd_due_date.

You can find an example of an implamentation by SAP in following procedure: LV05NF17

If you just to get a date from a string, you'll find your answer on this site using regular expresssions:

REPORT Z_RegEx_Fetch_Date_from_Text.
**
** Regular Expression Matching using ABAP RegEx
**

DATA gv_text TYPE string.
DATA gt_dates TYPE char10_t,
DATA ls_dates TYPE char10.

gv_text = 'Date of entry : 17.02.2012, Sample text including dates in various forms like 8.8.2008 or 21.03.2012 or 2013.08.17 in order to test Regular Expression in ABAP string operations'.
WRITE :/ gv_text.

PERFORM uGetDatesRegEx USING gv_text CHANGING gt_dates.

LOOP AT gt_dates INTO ls_dates.
IF SY-TABIX = 1.
WRITE :/ 'Matched date list :'.
ENDIF.
WRITE :/ ls_dates.
ENDLOOP.


FORM uGetDatesRegEx USING p_text TYPE string
CHANGING pt_dates TYPE char10_t.

DATA lv_txt TYPE string.
DATA lv_pattern TYPE string.
DATA lt_result_tab TYPE match_result_tab.
DATA ls_submatch_result_tab TYPE match_result.

lv_pattern = '(\d{1,2}[.|/]\d{1,2}[.|/]\d{4})|(\d{4}[.|/]\d{1,2}[.|/]\d{1,2})'.

FIND ALL OCCURRENCES OF REGEX lv_pattern IN p_text RESULTS lt_result_tab.

LOOP AT lt_result_tab INTO ls_submatch_result_tab.

lv_txt = p_text+ls_submatch_result_tab-offset(ls_submatch_result_tab-length).
APPEND lv_txt TO pt_dates.

ENDLOOP.

ENDFORM.