Fischer Ludrian
Fischer Ludrian

Reputation: 677

How to detect if a timestamp lies between two other timestamps?

I have a HashMap that looks more or less like this:

private HashMap<String, String> fu = new HashMap<String, String>();

fu.put("16:04:00.476", "A");
fu.put("16:09:58.228", "B");
fu.put("16:17:58.227", "C");
fu.put("16:22:42.478", "D");
fu.put("16:27:23.728", "E");
fu.put("16:38:34.977", "F");
fu.put("16:46:46.227", "G");

Now I have another timestamp, called bar, and I want to find the suitable letter:

private String findLetter(String timestamp) {
   return "";
}

The timestamps in the HashMap can be considered starting times. That means, A starts at 16:04:00.476 and lasts until B starts. B lasts until C starts and so on. Now, this method should return the letter in which the timestamp passed as a parameters is located in.

The first thing I did is to convert the time stamps into a Date Object to use the Date#after method to see if it is after a certain start time, but how can I make sure that it is also before the next start time?

Upvotes: 0

Views: 1738

Answers (5)

jlordo
jlordo

Reputation: 37813

If the format of your keys doesn't change, you can simply do:

private NavigableMap<String, String> fu = new TreeMap<>();

and then

private String findLetter(String timestamp) {
    return map.get(map.lowerKey(timestamp));
}

If you plan to change the format in the future, you can do the following (but have to adjust the timeformat)

private static final DateFormat DATE_FORMAT = new SimpleDateFormat("HH:mm:ss.SSS");

private NavigableMap<String, String> fu = new TreeMap<>(new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        try {
            long t1 = DATE_FORMAT.parse(o1).getTime();
            long t2 = DATE_FORMAT.parse(o2).getTime();
            return Long.compare(t1, t2);
        } catch (ParseException e) {
            throw new IllegalArgumentException(e);
        }
    }
});

and then you can simply do

private String findLetter(String timestamp) {
       return map.get(map.lowerKey(timestamp));
}

Upvotes: 0

Daniel Kaplan
Daniel Kaplan

Reputation: 67350

I've modified your source code in a way that is more convenient to show you how to do this correctly. I'm going to leave it up to an exercise for you to make it work the way you want, but IMO it's pretty straightforward to see how to do it. This uses the JodaTime library.

package com.sandbox;

import org.joda.time.DateTime;
import org.joda.time.Interval;

import java.util.ArrayList;
import java.util.List;

public class Sandbox {

    public static void main(String[] args) {
        List<DateTime> dateTimes = new ArrayList<DateTime>();
        dateTimes.add(new DateTime(100000));
        dateTimes.add(new DateTime(105000));
        dateTimes.add(new DateTime(110000));
        dateTimes.add(new DateTime(115000));
        dateTimes.add(new DateTime(120000));

        List<Interval> intervals = new ArrayList<Interval>();

        for (int i = 0; i < dateTimes.size() - 1; i++) {
            DateTime start = dateTimes.get(i);
            DateTime end = dateTimes.get(i + 1);
            intervals.add(new Interval(start, end));
        }

        assert 0 == findIndex(100000L, intervals);
        assert 0 == findIndex(100001L, intervals);
        assert 3 == findIndex(115000L, intervals);
        assert 3 == findIndex(115001L, intervals);
    }

    private static Integer findIndex(Long timestamp, List<Interval> intervals) {
        DateTime dateTime = new DateTime(timestamp);

        for (int i = 0; i < intervals.size(); i++) {
            Interval interval = intervals.get(i);
            if (interval.contains(dateTime)) {
                return i;
            }
        }
        return -1;
    }


}

This is way more work than is required when you consider @Thierry's solution works. But if your requirements change, this code will probably be more flexible to those changes. Still, I'd use his suggestion first if you don't think your requirements will change.

Upvotes: 0

Djon
Djon

Reputation: 2260

If you have parsed the Strings into Dates already, then you can use one of the only method not deprecated, getTime(), which will return a long representing the milliseconds.

You can then compare this value, given that 0 is the Epoch, and as I am writing this answer it's 1370548040476.

Upvotes: 0

Victor Sorokin
Victor Sorokin

Reputation: 11996

Here's simple solution based on TreeMap, as suggested. It assumes that all time points you shown are inside the same day.

class Sample {

    private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss.SSS");

    private static final String DEFAULT_DAY_PREFIX = "1980-05-15 ";

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

        TreeMap<Long, String> orderedDates = new TreeMap<Long, String>();

        orderedDates.put(parseToDate("16:04:00.476"), "A");
        orderedDates.put(parseToDate("16:09:58.228"), "B");
        orderedDates.put(parseToDate("16:17:58.227"), "C");

        System.out.println(orderedDates.floorEntry(parseToDate("16:04:00.500")).getValue());
        System.out.println(orderedDates.floorEntry(parseToDate("16:09:58.100")).getValue());
        System.out.println(orderedDates.floorEntry(parseToDate("16:09:58.300")).getValue());
        System.out.println(orderedDates.floorEntry(parseToDate("16:17:58.300")).getValue());
    }

    private static long parseToDate(String dayPoint) throws ParseException {
        return SDF.parse(DEFAULT_DAY_PREFIX + dayPoint).getTime();
    }
}

Upvotes: 0

Thierry
Thierry

Reputation: 5233

A HashMap is not ordered, so first you should use a TreeMap, for example. And look a the next entry to check if it's after your current time stamp

Upvotes: 6

Related Questions