即使日期格式不包含毫秒,如何始终包含毫秒?

问题描述

此示例有 2 列数据。

第 1 列是没有毫秒的日期,第 2 列是毫秒的数据。

显示允许用户更改日期格式。关键是第 1 列不应包含毫秒,而第 2 列应始终包含毫秒。

如果日期格式为 dd-MM-yyyy HH:mm:ss,则在处理第 2 列中的数据时,代码可以简单地附加“.SSS”,但格式可能有很大差异。例如,它甚至可以是“MM-dd-yy”而不包含任何时间参考,但第二列应始终包含时间和毫秒。

这是代码。有额外的杂项代码只是为了确保第一次看到毫秒。

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.TableCellRenderer;

public class DateFormatRendererExample 
{

    public static void main(String[] args) 
    {
        DateExampleSetup dateExampleSetup = new DateExampleSetup (); 

    }

}


class DateExampleSetup extends JFrame 
{
    final static Class[] columnClass = new Class[] { Date.class,Date.class };
    String currentDateFormat = "MM-dd-yyyy HH:mm:ss";
    String oldDateFormat = "MM-dd-yyyy HH:mm:ss";
    MyTableModel model;
    
    public DateExampleSetup() 
    {

        model = new MyTableModel();
        model.addRow("05-22-2020 12:12:12","06-02-2020 20:11:55.123");
        model.addRow("10-18-2020 14:16:17","01-02-2020 09:09:49.567");
        
        JTable table = new JTable(model);
        table.setDefaultRenderer(Date.class,new MyDateCellRenderer(this));
        JTextField dateFormatField = new JTextField(20);
        dateFormatField.setText(currentDateFormat);
        JButton activateDateFormat = new JButton("Activate new Date Format");
        activateDateFormat.addActionListener(new ActionListener(){

            @Override
            public void actionPerformed(ActionEvent arg0) 
            {
                
                setCurrentDateFormat(dateFormatField.getText());
                MyTableModel newModel = new MyTableModel ();
                newModel.addRow("05-22-2020 12:12:12","06-02-2020 20:11:55.1234");
                newModel.addRow("10-18-2020 14:16:17","02-02-2020 09:09:49.5678");
                table.setModel(newModel);
                newModel.fireTableDataChanged();
                setoldDateFormat(getCurrentDateFormat());
            }
            
        });
        setLayout(new BorderLayout());
        add(dateFormatField,BorderLayout.norTH);
        add(table,BorderLayout.CENTER);
        add(activateDateFormat,BorderLayout.soUTH);
        setVisible(true);
        setSize(500,300);
        
    }
    public String getCurrentDateFormat()
    {
        return currentDateFormat;
    }
    public void setCurrentDateFormat(String newCurrent)
    {
        currentDateFormat = newCurrent;
    }
    public String getoldDateFormat()
    {
        return oldDateFormat;
    }
    public void setoldDateFormat(String newCurrent)
    {
        currentDateFormat = newCurrent;
    }

}

class MyDateCellRenderer extends JLabel implements TableCellRenderer 
{
    DateExampleSetup des;
    boolean firstTimeRow1 = true;
    boolean firstTimeRow2 = true;
    
    public MyDateCellRenderer(DateExampleSetup des)
    {
        super();
        this.des = des;
    }
      public Component getTableCellRendererComponent(JTable table,Object value,boolean isSelected,boolean hasFocus,int row,int col) {
          
        try 
        {
            ///Just to get the milliseconds to show the first time.
            if (firstTimeRow1 && row == 0 && col == 1)
            {
                SimpleDateFormat tempDateFormat = new SimpleDateFormat("MM-dd-yyyy HH:mm:ss.SSS");
                Date tempDate = null;
                tempDate = tempDateFormat.parse((String)value);
                value = tempDateFormat.format(tempDate);
                setText(value.toString());
                firstTimeRow1 = false;
            }
            else if (firstTimeRow2 && row == 1 && col == 1)
            {
                SimpleDateFormat tempDateFormat = new SimpleDateFormat("MM-dd-yyyy HH:mm:ss.SSS");
                Date tempDate = null;
                tempDate = tempDateFormat.parse((String)value);
                value = tempDateFormat.format(tempDate);
                setText(value.toString());
                firstTimeRow2 = false;
            }
            else
            {
                SimpleDateFormat oldDateFormat = new SimpleDateFormat(des.getoldDateFormat());
                SimpleDateFormat newDateFormat = new SimpleDateFormat(des.getCurrentDateFormat());
                Date date = null;
                date = oldDateFormat.parse((String)value);
                value = newDateFormat.format(date);
                setText(value.toString());
            }
        } 
        catch (ParseException e) 
        {
            e.printstacktrace();
        }

        return this;
      }
    }

class MyTableModel extends AbstractTableModel {

    private List<String[]> rows;
    private String columnNames[] = { "Regular Date ","Date with milliseconds"};

    public MyTableModel() {
        rows = new ArrayList<>(25);
    }
    
    @Override
    public int getRowCount() {
        return rows.size();
    }

    @Override
    public int getColumnCount() {
        return 2;
    }

    @Override
    public Class<?> getColumnClass(int columnIndex) {
        return Date.class;
    }

    @Override
    public Object getValueAt(int rowIndex,int columnIndex) {
        String[] row = rows.get(rowIndex);
        return row[columnIndex];
    }
    
    @Override
    public String getColumnName(int col) {
        return columnNames[col];
    }
    
    public void addRow(String s1,String s2) 
    {
        String[] row = new String[getColumnCount()];
        row[0] = s1;
        row[1] = s2;
        rows.add(row);
        fireTableRowsInserted(getRowCount(),getRowCount());
    }            
} 

执行时显示以下帧。请注意,第二列是毫秒。

enter image description here

当日期更改为“dd-MM-yyyy”并按下“激活新日期格式”按钮时,第 2 列中的日期将丢失小时、分钟和秒,尤其是毫秒。

enter image description here

是否可以对一列使用单一日期格式(几乎可以是任何格式),同时对另一列使用相同的格式,同时确保 HH:mm:ss.sss 始终存在?

解决方法

您首先需要明确定义输入规则、输出要求以及调整输入以满足这些输出要求的规则。

似乎用户输入没有规则,这使得这很困难..他们可以输入任何他们想要的!也许至少需要数年、数月和数天来简化这一点?另一个输入要求可能是,如果它们包括毫秒,那么它们也必须包括秒,如果是秒然后是分钟,如果是分钟然后是小时,等等。这意味着你不必担心只有分钟没有小时或类似的东西.

似乎您的输出要求是包含年、月、日、小时、分钟、秒、毫秒,所有这些都在用户格式中,用于他们定义的任何内容,但添加到未定义的任何格式中。但是您添加剩余字段的规范是什么?

这里有一些代码可以帮助您入门。如果您要向模式添加更多字段,则需要添加的其他内容可能是进一步检查输入使用的分隔符。

public static void main(String[] args) throws Exception {

    // try with additional valid input patterns,such as 'MM/dd/yyyy' etc
    String[] patterns = {
            "yyyy-MM-dd HH:mm:ss.SSS","yyyy-MM-dd HH:mm:ss","yyyy-MM-dd HH:mm","yyyy-MM-dd HH","yyyy-MM-dd","HH:mm:ss.S yyyy-MM-dd","HH:mm:ss yyyy-MM-dd","HH:mm yyyy-MM-dd",};
    LocalDateTime date = LocalDateTime.now();
    for (String pattern : patterns) {
        String newPattern = fillInPattern(pattern);
        System.out.println(pattern + "\t\t" + newPattern + "\t\t" + DateTimeFormatter.ofPattern(newPattern).format(date));
    }
    // Output:
    // yyyy-MM-dd HH:mm:ss.SSS      yyyy-MM-dd HH:mm:ss.SSS     2021-05-04 11:15:53.743
    // yyyy-MM-dd HH:mm:ss          yyyy-MM-dd HH:mm:ss.SSS     2021-05-04 11:15:53.743
    // yyyy-MM-dd HH:mm             yyyy-MM-dd HH:mm:ss.SSS     2021-05-04 11:15:53.743
    // yyyy-MM-dd HH                yyyy-MM-dd HH:mm:ss.SSS     2021-05-04 11:15:53.743
    // yyyy-MM-dd                   yyyy-MM-dd HH:mm:ss.SSS     2021-05-04 11:15:53.743
    // HH:mm:ss.S yyyy-MM-dd        HH:mm:ss.SSS yyyy-MM-dd     11:15:53.743 2021-05-04
    // HH:mm:ss yyyy-MM-dd          HH:mm:ss.SSS yyyy-MM-dd     11:15:53.743 2021-05-04
    // HH:mm yyyy-MM-dd             HH:mm:ss.SSS yyyy-MM-dd     11:15:53.743 2021-05-04
}

private static String fillInPattern(String pattern) {
    // Get the range of each of the pattern fields you need to check
    // Parsing like this should be mostly safe since field pattern characters are generally adjacent to each other
    // and you don't expect repeats of a field. You could invalidate any pattern which violates this assumption.
    Map<Character,Range> fields = new HashMap<>();
    for (int i = 0; i < pattern.length(); i++) {
        char c = pattern.charAt(i);
        if (c == 'H' || c == 'm' || c == 's' || c == 'S') {
            int start = i;
            while (i < pattern.length() && pattern.charAt(i) == c) {
                i++;
            }
            fields.put(c,new Range(start,i));
        }
    }
    // Add the missing fields:
    // Works when you guarantee that if there's millis then there's seconds,if seconds then minutes,and if minutes then hours..
    StringBuilder builder = new StringBuilder(pattern);
    if (!fields.containsKey('H')) {
        builder.append(" HH:mm:ss.SSS");
    } else if (!fields.containsKey('m')) {
        builder.insert(fields.get('H').end(),":mm:ss.SSS");
    } else if (!fields.containsKey('s')) {
        builder.insert(fields.get('m').end(),":ss.SSS");
    } else if (!fields.containsKey('S')) {
        builder.insert(fields.get('s').end(),".SSS");
    } else {
        // it contains all the fields but make sure there's enough fractional seconds
        Range fSecs = fields.get('S');
        if (fSecs.length() < 3) {
            builder.replace(fSecs.start(),fSecs.end(),"SSS");
        }
    }
    return builder.toString();
}

public static class Range {
    private final int start;
    private final int end;

    public Range(int start,int end) {
        this.start = start;
        this.end = end;
    }

    public int start() { return start;  }
    public int end() { return end; }
    public int length() { return end - start; }
    @Override public String toString() { return start + "-" + end; }
}
,

只需将渲染器更改为此

try {
     if (col == 0) {
          SimpleDateFormat oldDateFormat = new SimpleDateFormat(des.getOldDateFormat());
          SimpleDateFormat newDateFormat = new SimpleDateFormat(des.getCurrentDateFormat());
          Date date = oldDateFormat.parse((String) value);
          value = newDateFormat.format(date) ;
          setText(value.toString());
    } else {
          SimpleDateFormat tempDateFormat = new SimpleDateFormat("MM-dd-yyyy HH:mm:ss.SSS");
          Date tempDate = tempDateFormat.parse((String) value);
          value = tempDateFormat.format(tempDate);
          setText(value.toString());
    }
} catch (ParseException e) {
            e.printStackTrace();
}

但正如前面提到的@Ole V.V.您不应使用 DateSimpleDateFormat。此外,我最好不要在您的模型中使用 String 而是已经使用 LocalDateTime - 所以它不允许将字符串转换为时间,反之亦然