I'm new to Java and DateTime formats in general, and I'm supposed to convert GPS data from CSV files. My question is how this is done for the format I'm working with. The data points I'm getting from the GPS data is in the format as follows:
time,lat,lon,elevation
I have split up the different data points and put them in a string array, and I'm supposed to convert the data points to either integer or double arrays, as follows:
public void convert() {
int n = timesstr.length; //Amount of data points
times = new int[n]; //Array for time in seconds (int)
latitudes = new double[n]; //Array for latitudes (double)
longitudes = new double[n]; //Array for longitudes (double)
elevations = new double[n]; //Array for elevations (double)
}
I'm planning to do a for-loop, converting the elements in the arrays one after one. Now the problem is how I'm supposed to convert the time from the data point to seconds from midnight, as the data point for time is formatted as ISO_INSTANT, e.g.
2017-08-13T08:52:26.000Z
How should I go about parsing and converting the data points from ISO_INSTANT to seconds from midnight? According to the information I got, the data point
2017-08-13T08:52:26.000Z
Should give the integer 31946 after conversion, as in 31956 seconds past midnight.
You can do it in the following way:
LocalDateTime.parse("2017-08-13T08:52:26.000Z", DateTimeFormatter.ISO_DATE_TIME).get(ChronoField.SECOND_OF_DAY);
Or as pointed out by #Andreas you can do:
ZonedDateTime.parse("2017-08-13T08:52:26.000Z").get(ChronoField.SECOND_OF_DAY);
is shorter, and more lenient. It even supports Daylight Savings Time, if a time zone other that Z is given. - Andreas
Related
I need to randomize a time in java.
If now the time is 24/2/2021 13:56:13, then I need to randomize a time between 23/2/2021 13:56:13 and 24/2/2021 13:56:13. I am not familiar to random function in Java so that I maybe need some help. Thank you for your attention.
Take LocalDateTime.now() then go back in time with a random amount of seconds between 0 and 86400
int randomSeconds = new Random().nextInt(3600 * 24);
LocalDateTime anyTime = LocalDateTime.now().minusSeconds(randomSeconds);
System.out.println(anyTime);
General solution
Define the beginning dates and end of the period
Compute the difference in seconds and get a random int in that range
Compute the random date with one of these 2 ways:
Go from the beginning and add the random amount of seconds
Go from the end and remove the random amount of seconds
LocalDateTime periodStart = LocalDateTime.now().minusDays(1);
LocalDateTime periodEnd = LocalDateTime.now();
int randomSeconds = new Random().nextInt((int) periodStart.until(periodEnd, ChronoUnit.SECONDS));
//LocalDateTime anyTime = periodStart.plusSeconds(randomSeconds);
LocalDateTime anyTime = periodEnd.minusSeconds(randomSeconds);
I have many time stamps showing at which time a user entered the room. I want to calculate an average time. The problem occurs when some action happens at night.
I tried to calculate it with milis, but it is wrong.
ArrayList<String> times = new ArrayList<String>();
times.add("00:20:01");
times.add("00:00:01");
times.add("23:40:01");
times.add("23:20:01");
times.add("23:20:01");
times.add("00:20:01");
times.add("23:40:01");
times.add("23:40:01");
times.add("00:00:01");
long commonMillis=0;
for (String date:times){
LocalTime time = new LocalTime(date);
long dayMilis = time.getMillisOfDay();
commonMillis = commonMillis + dayMilis;
}
LocalTime average = new LocalTime(commonMillis/times.size());
This code, for example, returns the value 14:08:54.333. Because the hours 00:00 and 23:00 -- calculated in millis -- are too far from each other.
Please help me to find right way to calculate the average time?
Three things:
You have to define an offset time:
If you want an average of times of different days without knowing the day, you have to define an offset time by yourself. This time is used to decide whether a time is belonging to the next day or not.
This offset time may be derived depending on the values you get.
Without an offset time, you implicitely use 0 o'clock.
Avoid overflows:
If your times list gets longer, you may run into an overflow if a long field is not sufficient to store the accumulated value. You can use a data structure which is overflow resistant like BigInteger or use the (culmulative) moving average approach.
Wrong result constructor:
The constructor LocalTime(long instant) implicitely uses your local DateTimeZone to calculate a local time from an Instant. This causes different times when using the same code between different time zones.
The method you want to use is LocalTime#fromMillisOfDay.
Here is an approach considering the above points:
long movingAverage = 0;
// 1. define offset
LocalTime offset = new LocalTime("12:00:00");
long offsetMillis = offset.getMillisOfDay();
for (String date : times) {
long sampleMillis = new LocalTime(date).getMillisOfDay();
// align to offset
if (sampleMillis < offsetMillis)
sampleMillis += DateTimeConstants.MILLIS_PER_DAY;
long diff = sampleMillis - offsetMillis;
// 2. use moving average
movingAverage = movingAverage + diff / times.size();
}
// 3. avoid LocalTime(long) constructor
LocalTime result = offset.plusMillis((int) movingAverage);
System.out.println(result); // 23:48:54.329
A naive approach would be to gather the long millisecond values in all the dates, add them up and divide them by the number of dates, transforming them back into a LocalDate. You probably need a BigInteger to hold the sum, though.
There is a problem when I tried to transform double to Date.
This is my code:
double itemDouble = 1370437809.00;
long itemLong = (long) (itemDouble * 1000);
Date itemDate = new Date(itemLong);
String itemDateStr = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SS").format(itemDate);
When the itemDouble is 1370437809.00, itemDateStr is 2013-06-05 21:10:09.00,
but when the itemDouble's decimal places is not zero, such as 1370437809.66, the itemDateStr is 2013-06-05 21:10:09.660. The formatted date string is not right.
How this happened?
According to your code, 1370437809.66 is a number of seconds since 1970. The decimal part represents 660 milliseconds. When you convert to a Date, you ask to display the milliseconds (the .SSS in the pattern). The result you get is correct.
you have 0.66*1000=660 that's correct
In my program, I receive strings that define a time stamp in milliseconds. Now I need to convert this to a proper date. The solution I found looks something like this:
String aTime = "1365504203.0269";
double t = Double.parseDouble(aTime);
Date date = new Date((long)t*1000);
SimpleDateFormat dateFormatDDMMYYYY = new SimpleDateFormat("dd.MM.yyyy");
SimpleDateFormat dateFormatHHMMssSS = new SimpleDateFormat("HH:mm:ss:SS");
String day = new String(dateFormatHHMMssSS.format(date));
String hour = new String(dateFormatDDMMYYYY.format(date));
System.out.println("The Date: "+day);
System.out.println("The Time: "+hour);
Unfortunately, this removes the accuracy of milliseconds from the time stamp. (I'm not sure if the time is even that accurate as I can hardly think about it anymore.)
Has it gone lost due to double->long conversion, or has it never been there at all? Any way to workaround this problem?
The problem is in this statement:
Date date = new Date((long)t*1000);
It casts the double to a long first, thereby truncating the decimal places, and then multiplies by 1000, which just adds three zeros. Try this:
Date date = new Date((long)(t*1000.0));
It uses double as the data type for multiplication, which moves the decimal places into the integer part, and then makes the decimal place truncating long conversion.
Using 1000.0 instead of 1000 as the constant forces the constant to be of double type as well, adding an extra level of certainty that the multiplication will happen with doubles.
I am trying to build a map with time starting from 06.00 to 23:59 as keys and I will keep track of a number for each time as value.I need the time to stored HH.mm as format and I am planning to build the map using a loop by incrementing one minute and run the following code inside the loop.The problem here is since I have to set the format as HH.MM strictly I have to get the input as String and format it and then parse it back as double which affects the perfomance.Is there a global setting to change so that whatever double number I choose in this particular class should be of the format ##.##.Also point here to note is since it is time it ends at 60 minutes and hence I have to break the current iteration with the help of .6.
Map map = new LinkedHashMap();
//Edit:Moved DecimalFormat Outside the loop
DecimalFormat df = new DecimalFormat("##.##");
for (double time= 06.00; time<= 22.00; time= time+ 01.00)
{
String timeString = df.format(appointmentTime);
time = Double.parseDouble(timeString);
if (timeString.indexOf(".6") != -1)
{
time= time+ 00.40;
}
map.put(time,"<number>");
}
I beliI believe you choose the most complicated approach. Instead of iterating the time variable you could iterate a simple number indicating the minutes since 0 o’clock and then generate your time double only for the map.
for(int totalMinutes = 6 * 60; totalMinutes <= 22 * 60; totalMinutes ++) {
map.put(buildTimeDouble(totalMinutes),”<number>”);
}
But I believe (I do not understand your question in that point), it would be better not to use a double for the map key, instead you could use your own Time class, something like:
Time{
private int hour;
private int minutes;
public Time(int hour; int minutes) {
this.hour = hour;
this.minutes = minutes;
}
public toString(){
return hour + “:” + minutes
}
public static Time fromTotalMinutes(int totalMinutesSinceZeroOclock){
return new Time(totalMinutesSinceZeroOclock / 60; totalMinutesSinceZeroOclock / 60);
}
}
If you are worried about performance, one modification you should make to your code is to construct the DecimalFormat just once, outside of the loop. The same instance can be reused over and over again inside the loop.
It's not a good approach to pre compute for all these values.Perhaps you can use a LRU cache.This can be easily implemented using a LinkedHashMap.I also think that you should not be using a double to represent time.Go through this article,it might give you some new ideas.
You should not work with doubles as counters, as rounding errors will creep in giving off-by-one errors.
Instead have an integer counter from which you calculate the times you need.