I have what is essentially a JFormattedTextField which uses a DateFormatter, which gets its format from a user-controlled locale setting. The code below is an attempt to reproduce this without a ton of proprietary code. (I apologize for my ham-fisted attempts at top-level Swing stuff...)
My issue is, that if the user has chosen a locale with two-digit years, it becomes impossible to enter dates in the "wrong" century. For example, if I run the program below and edit the year to 2047 and click Ok, the program prints a date in 1947.
The reason seems to be that JFormattedTextField likes to "normalize" its data by round-tripping it through the text representation. One workaround is to override commitEdit() with a method that tests the roundtrip and, if it turns out to clobber the year, replaces the format with a hard-coded YYYY-MM-DD. This seems a bit heavy-handed, though. Is there a better way, except asking the users to choose a sane locale or hard-wiring the format for this particular field? (I know there are ways to chose which 100-year window is the right one, but that still limits me to a 100-year window).
import javax.swing.*;
import javax.swing.text.DateFormatter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.text.DateFormat;
import java.text.ParseException;
import java.util.Date;
import java.util.Locale;
public class Main {
private static void createAndShowGUI() {
JFrame frame = new JFrame("HelloWorldSwing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
var gbl = new GridBagLayout();
frame.setLayout(gbl);
final Container contentPane = frame.getContentPane();
Date date = new Date();
JFormattedTextField dateField = new JFormattedTextField(date);
dateField.setFormatterFactory(new JFormattedTextField.AbstractFormatterFactory() {
@Override
public JFormattedTextField.AbstractFormatter getFormatter(JFormattedTextField tf) {
return new DateFormatter(DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, Locale.GERMANY));
}
});
contentPane.add(dateField);
JButton button = new JButton("Ok");
contentPane.add(button);
button.addActionListener((ActionEvent e) -> {
try {
dateField.commitEdit();
} catch (ParseException ex) {
ex.printStackTrace();
}
System.out.println(dateField.getValue());
});
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(Main::createAndShowGUI);
}
}
The following works for me but I'm not saying that it's the best or only way.
Your problem is with the date only and not the time, so in the below code I disregard the time and handle the date only.
In your situation, method
getValue, of classJFormattedTextField, returns an instance ofjava.util.Date. This class has been superseded by classes in package java.time. One of the reasons is because of the [problematic] behavior you are seeing.Hence, in the below code, I take the text contents of the
JFormattedTextField, extract the date part and convert that to ajava.time.LocalDatewhich displays the year that you want.I added lots of
printlnstatements just to demonstrate what I wrote, above.When I run the above code and change the year to 47, then when I press the OK button, I get the following output:
In other words,
java.util.Datedisplays the year as 1947 whereasjava.time.LocalDatedisplays the year as 2047 (which is what you want, right?)