001    package org.jrobin.core.timespec;
002    
003    import org.jrobin.core.RrdException;
004    import org.jrobin.core.Util;
005    
006    import javax.swing.*;
007    import java.awt.*;
008    import java.awt.event.ActionEvent;
009    import java.awt.event.ActionListener;
010    import java.text.ParseException;
011    import java.text.SimpleDateFormat;
012    import java.util.Date;
013    
014    /**
015     * Small swing-based utility to convert timestamps (seconds since epoch) to readable dates and vice versa.
016     * Supports at-style time specification (like "now-2d", "noon yesterday") and other human-readable
017     * data formats:<p>
018     * <ul>
019     * <li>MM/dd/yy HH:mm:ss
020     * <li>dd.MM.yy HH:mm:ss
021     * <li>dd.MM.yy HH:mm:ss
022     * <li>MM/dd/yy HH:mm
023     * <li>dd.MM.yy HH:mm
024     * <li>yy-MM-dd HH:mm
025     * <li>MM/dd/yy
026     * <li>dd.MM.yy
027     * <li>yy-MM-dd
028     * <li>HH:mm MM/dd/yy
029     * <li>HH:mm dd.MM.yy
030     * <li>HH:mm yy-MM-dd
031     * <li>HH:mm:ss MM/dd/yy
032     * <li>HH:mm:ss dd.MM.yy
033     * <li>HH:mm:ss yy-MM-dd
034     * </ul>
035     * The current timestamp is displayed in the title bar :)<p>
036     */
037    public class Epoch extends JFrame {
038            private static final long serialVersionUID = 1L;
039            private static final String[] supportedFormats = {
040                            "MM/dd/yy HH:mm:ss", "dd.MM.yy HH:mm:ss", "yy-MM-dd HH:mm:ss", "MM/dd/yy HH:mm",
041                            "dd.MM.yy HH:mm", "yy-MM-dd HH:mm", "MM/dd/yy", "dd.MM.yy", "yy-MM-dd", "HH:mm MM/dd/yy",
042                            "HH:mm dd.MM.yy", "HH:mm yy-MM-dd", "HH:mm:ss MM/dd/yy", "HH:mm:ss dd.MM.yy", "HH:mm:ss yy-MM-dd"
043            };
044    
045            private static final SimpleDateFormat[] parsers = new SimpleDateFormat[supportedFormats.length];
046            private static final String helpText;
047    
048            private Timer timer = new Timer(1000, new ActionListener() {
049                    public void actionPerformed(ActionEvent e) {
050                            showTimestamp();
051                    }
052            });
053    
054            static {
055                    for (int i = 0; i < parsers.length; i++) {
056                            parsers[i] = new SimpleDateFormat(supportedFormats[i]);
057                            parsers[i].setLenient(true);
058                    }
059                    StringBuffer tooltipBuff = new StringBuffer("<html><b>Supported input formats:</b><br>");
060                    for (String supportedFormat : supportedFormats) {
061                            tooltipBuff.append(supportedFormat).append("<br>");
062                    }
063                    tooltipBuff.append("<b>AT-style time specification</b><br>");
064                    tooltipBuff.append("timestamp<br><br>");
065                    tooltipBuff.append("Copyright (C) 2003-2005 Sasa Markovic, All Rights Reserved</html>");
066                    helpText = tooltipBuff.toString();
067            }
068    
069            private JLabel topLabel = new JLabel("Enter timestamp or readable date:");
070            private JTextField inputField = new JTextField(25);
071            private JButton convertButton = new JButton("Convert");
072            private JButton helpButton = new JButton("Help");
073    
074            private static final SimpleDateFormat OUTPUT_DATE_FORMAT =
075                            new SimpleDateFormat("MM/dd/yy HH:mm:ss EEE");
076    
077            Epoch() {
078                    super("Epoch");
079                    constructUI();
080                    timer.start();
081            }
082    
083            private void constructUI() {
084                    JPanel c = (JPanel) getContentPane();
085                    c.setLayout(new BorderLayout(3, 3));
086                    c.add(topLabel, BorderLayout.NORTH);
087                    c.add(inputField, BorderLayout.WEST);
088                    c.add(convertButton, BorderLayout.CENTER);
089                    convertButton.setToolTipText(helpText);
090                    convertButton.addActionListener(new ActionListener() {
091                            public void actionPerformed(ActionEvent e) {
092                                    convert();
093                            }
094                    });
095                    c.add(helpButton, BorderLayout.EAST);
096                    helpButton.addActionListener(new ActionListener() {
097                            public void actionPerformed(ActionEvent e) {
098                                    JOptionPane.showMessageDialog(helpButton, helpText, "Epoch Help", JOptionPane.INFORMATION_MESSAGE);
099                            }
100                    });
101                    inputField.requestFocus();
102                    getRootPane().setDefaultButton(convertButton);
103                    setResizable(false);
104                    setDefaultCloseOperation(EXIT_ON_CLOSE);
105                    pack();
106                    centerOnScreen();
107                    setVisible(true);
108            }
109    
110            void centerOnScreen() {
111                    Toolkit t = Toolkit.getDefaultToolkit();
112                    Dimension screenSize = t.getScreenSize();
113                    Dimension frameSize = getPreferredSize();
114                    double x = (screenSize.getWidth() - frameSize.getWidth()) / 2;
115                    double y = (screenSize.getHeight() - frameSize.getHeight()) / 2;
116                    setLocation((int) x, (int) y);
117            }
118    
119            private void convert() {
120                    String time = inputField.getText().trim();
121                    if (time.length() > 0) {
122                            // try simple timestamp
123                            try {
124                                    long timestamp = Long.parseLong(time);
125                                    Date date = new Date(timestamp * 1000L);
126                                    formatDate(date);
127                            }
128                            catch (NumberFormatException nfe) {
129                                    // failed, try as a date
130                                    try {
131                                            inputField.setText("" + parseDate(time));
132                                    }
133                                    catch (RrdException e) {
134                                            inputField.setText("Could not convert, sorry");
135                                    }
136                            }
137                    }
138            }
139    
140            private void showTimestamp() {
141                    long timestamp = Util.getTime();
142                    setTitle(timestamp + " seconds since epoch");
143            }
144    
145            void formatDate(Date date) {
146                    inputField.setText(OUTPUT_DATE_FORMAT.format(date));
147            }
148    
149            private long parseDate(String time) throws RrdException {
150                    for (SimpleDateFormat parser : parsers) {
151                            try {
152                                    return Util.getTimestamp(parser.parse(time));
153                            }
154                            catch (ParseException e) {
155                                    // NOP
156                            }
157                    }
158                    return new TimeParser(time).parse().getTimestamp();
159            }
160    
161            /**
162             * Main method which runs this utility.
163             *
164             * @param args Not used.
165             */
166            public static void main(String[] args) {
167                    new Epoch();
168            }
169    }