Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JXDatePicker using SimpleDateFormat to format dd.MM.yy to dd.MM.yyyy with current century

as already explained I want to achieve, that when the user is editing a date within a JXDatePicker, he can choose, weather he types it again in the same format, which is by default dd.MM.yyyy or just dd.MM.yy. When he uses the short form I want the Picker to choose the current century.

Example:

27.01.2012 edited to 27.01.10 should result in 27.01.2010

as well as:

27.01.2012 edited to 27.01.2010 should also result in 27.01.2010

By default the JXDatePicker handels it the following way:

27.01.2012 edited to 27.01.10 results in 27.01.0010

Which is not really the way I wanted it to work. After some short research I found the following Method in SimpleDateFormat

/**
 * Sets the 100-year period 2-digit years will be interpreted as being in
 * to begin on the date the user specifies.
 *
 * @param startDate During parsing, two digit years will be placed in the range
 * <code>startDate</code> to <code>startDate + 100 years</code>.
 */
public void set2DigitYearStart(Date startDate)

On first view this sounded exactly like what I need. So I tested it and unfortunatly it didnt work like I hoped it would. This is because I want to use dd.MM.yyyy as format to display dates and also want it to be displayed like that in editmode. For example when the user klicks on a date like 27.01.2012, I also want it to be like that in editmode, too and not just the short form: 27.01.12.

My Problem now is, that set2DigitYearStart(Date) unfortunatly only works, when I choose to use the shortform in editmode. I made a small example to show this case (SwingX Library is required, because of jxdatepicker and can be found be here).

public class DatePickerExample extends JPanel
{
  static JFrame frame;

  public DatePickerExample()
  {
    JXDatePicker picker = new JXDatePicker();
    JTextField field = new JTextField( 10 );

    add( field );
    add( picker );

    final Calendar instance = Calendar.getInstance();
    instance.set( 2012, 01, 26 );
    Date date = instance.getTime();
    picker.setDate( date );

    //    SimpleDateFormat format = new SimpleDateFormat( "dd.MM.yy" );//Works, but I wonna display and edit it with dd.MM.yyyy
    SimpleDateFormat format = new SimpleDateFormat( "dd.MM.yyyy" );
    final Date startDate = new Date( 0 );//01.01.1970
    format.set2DigitYearStart( startDate );

    picker.setFormats( format );
  }

  public static void main( String[] args )
  {
    frame = new JFrame();
    frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
    frame.setBounds( 400, 400, 400, 400 );
    frame.setLayout( new BorderLayout() );
    frame.add( new DatePickerExample() );
    frame.setVisible( true );
  }
}

Anyone already had the same requirement and can tell me how to make this work? Any ideas are welcome. Thank you very much in advance. ymene

like image 587
crusam Avatar asked Jan 27 '12 14:01

crusam


People also ask

How to format a date using SimpleDateFormat?

Creating SimpleDateFormat instance String pattern = "MM-dd-yyyy"; SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern); In the example above the String pattern is the pattern which will be used to format a date and the output will be generated in that pattern as “MM-dd-yyyy”.

What is the format of SimpleDateFormat?

SimpleDateFormat is a concrete class for formatting and parsing dates in a locale-sensitive manner. It allows for formatting (date -> text), parsing (text -> date), and normalization. SimpleDateFormat allows you to start by choosing any user-defined patterns for date-time formatting.

How to print date in specific format in java?

Formatting Dates String pattern = "yyyy-MM-dd"; SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern); String date = simpleDateFormat. format(new Date()); System. out. println(date);


1 Answers

Final (hopefully :)

Summary of the first edit:

  • DatePickerFormatter already implements a lookup strategy (or CompoundFormat, as suggested by @Robin)
  • the lookup sequence for parsing is configurable by client code
  • the idea is to try parsing starting with the first (typically the "longest"), if that fails try the next (typically "not-so-long") and so on until succeeded or a parseException is thrown
  • for year parsing, SimpleDateFormat has rules that conflict with that longest-first lookup: it requires that "yy" is tried before "yyyy"
  • doing so in datePicker has the unwanted side-effect of always showing the date with the short year format

The reason is DatePickerFormatter: it doesn't allow to specify the formatting format (simply uses the first). The way out is a custom DatePickerFormatter, which supports it (in the snippet, it's hardcoded to use the second):

SimpleDateFormat longFormat = new SimpleDateFormat( "dd.MM.yyyy" );
SimpleDateFormat shortFormat = new SimpleDateFormat( "dd.MM.yy" );
Date startDate = new Date( 0 );//01.01.1970
shortFormat.set2DigitYearStart( startDate );

DatePickerFormatter formatter = new DatePickerFormatter(
// invers sequence for parsing to satisfy the year parsing rules
        new DateFormat[] {shortFormat, longFormat}) {

            @Override
            public String valueToString(Object value) throws ParseException {
                if (value == null) return null;
                return getFormats()[1].format(value);
            }
        } ;
DefaultFormatterFactory factory = new DefaultFormatterFactory(formatter );
picker.getEditor().setFormatterFactory(factory);

Not entirely sure if we should support configuring the formatter in the base class. The DatePickerFormatter is a bit strange beast, not extending InternalFormatter and with the lookup process being a bit in competition with a FormatterFactory...

Original

It's not exactly the datePicker which handles it that way, it's the core formatting (as D1e already noted). None of the default format/ter/s support two formats at the same time: to see, try to achieve your goal with a core JFormattedTextField :-)

The way out might be a FormatterFactory: it allows to use different formats, depending on context: display and edit - the latter is used when the field is focused, the former at all other times. As the picker's editor is a JFormattedTextField, you can configure it directly (instead of using the setFormats methods)

    SimpleDateFormat format = new SimpleDateFormat( "dd.MM.yyyy" );
    SimpleDateFormat editFormat = new SimpleDateFormat( "dd.MM.yy" );

    final Date startDate = new Date( 0 );//01.01.1970
    instance.setTime(startDate);
    editFormat.set2DigitYearStart( instance.getTime() );
    DefaultFormatterFactory factory = new DefaultFormatterFactory(
            new DatePickerFormatter(new DateFormat[] {format}),
            new DatePickerFormatter(new DateFormat[] {format}),
            new DatePickerFormatter(new DateFormat[] {editFormat})
            );
    picker.getEditor().setFormatterFactory(factory);

Edit

head banging after reading Robin's recent answer (+1!) - at last, embarassingly after years and years, I understand what SwingX' DatePickerFormatter is trying to do: that is to support a lookup chain of formatters (from longer to shorter), the longest used after committing, the shorter to ease the typing by users.

Unfortunately that doesn't work as intuitively expected. Given a sequence of formats, longer to shorter (and appropriately configured to the century):

"yyyy", "yy"

and given input

"10"

feels like being passed on from first to second, resulting in

 2010

but isn't. As documented (who reads documention ... lazy me, cough ...) in SimpleDateFormat

Year: [ ... ] For parsing, if the number of pattern letters is more than 2, the year is interpreted literally, regardless of the number of digits. So using the pattern "MM/dd/yyyy", "01/11/12" parses to Jan 11, 12 A.D.

At the end of the day - as DatePickerFormatter tries to support that lookup but isn't successful - this might be considered a SwingX problem, after all :-)

like image 98
kleopatra Avatar answered Sep 18 '22 18:09

kleopatra