Comparing two timestamps

14,302

Solution 1

The others already answered why. Here's a starting point to get around it:

import java.text.*;
import java.util.Date;

public class DatePercentage {

    private final SimpleDateFormat dateFmt = new SimpleDateFormat(
                                "yyyy-MM-dd HH:mm:ss");
    private final DecimalFormat decFmt = new DecimalFormat();

    public Date parse(String text) throws ParseException {
        ParsePosition pos = new ParsePosition(0);
        Date d = dateFmt.parse(text, pos);

        if (d == null) {
            throw new ParseException("Could not parse " + text + ": " + pos,
                                     pos.getErrorIndex());
        } else if (pos.getIndex() < text.length()) {
            Number dec = decFmt.parse(text, pos); // % milliseceonds
            double pct = dec == null ? 0 : dec.doubleValue();

            if (0 < pct && pct < 1) {
                long moreMillis = Math.round(pct * 1000);
                d = new Date(d.getTime() + moreMillis);
            }
        }
        return d;
    }

    public static void main(String[] args) throws ParseException {
        String date = "2011-12-31 07:11:01";
        String [] millis = {"", ".5", ".50", ".500", ".5001", 
                            ".051", ".5009", "garbage"};

        DatePercentage dp = new DatePercentage();

        for (int i = 0; i < millis.length; i++) {
            String str = date + millis[i];
            System.out.format("%2s: %26s -> %tQ%n", i+1, str, dp.parse(str));
        }
    }
}

Output:

 1:        2011-12-31 07:11:01 -> 1325333461000
 2:      2011-12-31 07:11:01.5 -> 1325333461500
 3:     2011-12-31 07:11:01.50 -> 1325333461500
 4:    2011-12-31 07:11:01.500 -> 1325333461500
 5:   2011-12-31 07:11:01.5001 -> 1325333461500
 6:    2011-12-31 07:11:01.051 -> 1325333461051
 7:   2011-12-31 07:11:01.5009 -> 1325333461501
 8: 2011-12-31 07:11:01garbage -> 1325333461000

Solution 2

The problem is that the S symbol parses numbers as milliseconds. Always. So, in the first case, ".5" is being parsed as 5 milliseconds, and ".50" is being parsed as 50 milliseconds. Neither of them is being parsed as half a second, which i suspect is what you want.

Sadly, this is a shortcoming in SimpleDateFormat. There is simply no way to parse or format decisecond or centisecond fields with it.

When i last had to do this (admittedly only for a time, not a date), i ended up parsing manually - splitting the string up with a regular expression, then converting the fields into a millisecond total by hand. You could perhaps slice off the fractional seconds field and parse that manually, then parse the remaining string with SimpleDateFormat.

The alternative is to pad the strings with trailing zeroes, so that the fractional seconds is always three digits, which will then be parsed correctly. Ugly, but at least simple.

Solution 3

It's right that equals returns false. Those two strings are different - .5 (interpreted as .05) cannot be the same as .50. Also it is better to use compareTo if you want to compare Dates.

And I would use only one SimpleDateFormat like this:

SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SS");

Date dateOne = format.parse(d1);
Date dateTwo = format.parse(d2);

So my suggestions are these:

  • If you really want to have those different values the same, compare them as strings with some regular expression (I wouldn't recommend this solution).
  • If you covert them to Date then they will be different because the aren't the same.
  • Or (like other people here suggest) you can remove the .SS part from the pattern but then you will lose the precision..
Share:
14,302
Amit
Author by

Amit

Updated on June 04, 2022

Comments

  • Amit
    Amit almost 2 years

    I want to compare the following two timestamps. It should return true but due to single digit and double digit milliseconds in the two timestamps, it is returning false. What can I do to make it return true

    public static void main(String[] args) throws ParseException {
        String d1 = "2011-12-31 07:11:01.5";
        String d2 = "2011-12-31 07:11:01.50";
        SimpleDateFormat s1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");
        SimpleDateFormat s2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SS");
    
        Date dateOne = s1.parse(d1);
        Date dateTwo = s2.parse(d2);
    
        System.out.println(dateOne.equals(dateTwo));
    }
    
  • user219882
    user219882 about 12 years
    This does not work. It gives the same results as it did with .SS.
  • Robin
    Robin about 12 years
    It does not matter what you use for parsing ss.S or ss.SSS, it will only be used for formatting. See the part of the javadoc I quoted in my answer
  • JB Nizet
    JB Nizet about 12 years
    @Tomas. You missed the part when I tell you to right-pad the string with zeros to make sure there are always three digits.
  • user219882
    user219882 about 12 years
    @JBNizet It's not worth the effort. I wouldn't recommend this kind of one-purpose solution with extra code to make it work.