Setting the Decimal to format ##.## in java - java

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.

Related

How to convert the time of a day in number of seconds given the following conditions

Given the time of a day in number of seconds, convert it into time in hhmmss format. Note that the time is past noon, and hence the hours will never be less than 12.
Sample Input #1
(86399)
Sample Output #1
235959
MyApproach:
I want to ask how the time is converted
given the time in seconds
86399
According to what I understood I converted this time like
($86399$/$3600$)=23 hrs
($86399$/$60$)=1439minutes
$86399$=$87861$seconds
I think I am doing wrong and I don't know why?
Can Anyone guide how to convert this time?
#Edit
Below is my code:
public class SecondsToTime
{
public static void main(String args[])
{
SecondsToTime obj = new SecondsToTime();
int result = obj.toTime(86399);
System.out.println(result);
}
public int toTime(int seconds)
{
int a=n/$3600$=23 hrs //if n=86399
int b=n/$60$=1439minutes //if n=86399
int c=n=$87861$seconds //if n=86399
return a+b+c;
}
}
You have the first step, you're just missing the second one. To get the number of minutes past the hour:
(input / 60) % 60
In other words:
(timeOfDayInSeconds / secondsPerMinute) % minutesPerHour

calculate an average time with joda time

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.

Compute times in Java eg. 1900-1710 = 110 mins

is there any way in java to do that? I want it to compute the times like that. 0950-0900 is 50 mins but 1700-1610 = 50 mins instead of 90, 1900-1710 = 110 instead of 190. thanks :)
Have a look at Duration (part of the new Date & Time API introduced in Java SE 8).
Eg. (untested):
long minutes = Duration.between(toLocalTime(1710), toLocalTime(1900)).toMinutes();
private LocalTime toLocalTime(int time){
return LocalTime.of(time / 100, time % 100);
}
You can use the new Java Date API from Java 8.
LocalTime start = LocalTime.parse("19:00");
LocalTime end = LocalTime.parse("17:10");
Duration elapsed = Duration.between(start, end);
System.out.println(elapsed.toMinutes());
This will output: -110 and 110 if you switch start and end.
If you've just got integers, and you don't care about validation, you can do it all without touching time parts at all:
public int getMinutesBetween(int time1, int time2) {
// Extract hours and minutes from compound values, which are base-100,
// effectively.
int hours1 = time1 / 100;
int hours2 = time2 / 100;
int minutes1 = time1 % 100;
int minutes2 = time2 % 100;
// Now we can perform the arithmetic based on 60-minute hours as normal.
return (hours2 - hours1) * 60 + (minutes2 - minutes1);
}
However, I'd strongly recommend that you use more appropriate representations - these aren't just normal int values... they're effectively "time of day" values, so LocalTime (in either Joda Time or Java 8's java.time) is the most appropriate representation, IMO.

I cant count time period

I have code which checks if the given "A" time (in milliseconds) is in the given "b" time period.
private static boolean isInTimeInterval(long time, int timePeriod) {
long curTime = Calendar.getInstance().getTimeInMillis();
// time period is in hours, 1 hour is 3600000 ms;
long startTime = curTime - timePeriod * 3600000;
if (time >= startTime && time < curTime){
return true;
}
return false;
}
I take the time from a file and parse it into a long like this:
(Long.parseLong(array[2]))
But it doesn't work correctly, what is wrong ?
To simplify things, I would suggest that you first subtract the start time from the end time, check to see if that is positive and then decide if the remaining milliseconds is smaller than the requested time period.
long difference = Calendar.getInstance().getTimeInMillis() - time;
long timeRange = timePeriod * 3600000;
return (0 <= difference && differance <= timeRange);
It makes the code slightly smaller in lines, but more importantly, it simplifies the math to where you know the code isn't the problem.
As far as the errors you are likely encountering, I'd look to your
Long.parseLong(array[2])
As that is likely grabbing the input in a manner you aren't expecting. For starters, I'd put in some logging or at least one-time println debugging statements to verify the input times are what I thought they were.

What is the most efficient way to convert long to HH:mm:ss and display it in a label?

I'm wanting to have my JLabel display values in the format of HH:mm:ss without making use of any external libraries. (the label will update every second)
So for example, the following input in seconds and the desired output are below:
Seconds: Output:
--------------------------------------------------
long seconds = 0 00:00:00
long seconds = 5 00:00:05
long seconds = 500 00:08:20
long seconds = 5000 01:23:20
Note: the seconds value is of type long
I'm aware that typically one would just do the following conversions to get the desired numbers:
long s = 5000; //total seconds
long hrs = (s / 3600) //hours
long mins = ((s%3600)/60) //minutes
long secs = (s%60) //seconds
However, this leaves decimals on the values. Perhaps there is some sort of formatting that will allow me to toss the un-needed decimals.
Options I have come across were String.format(), SimpleDateFormat(), or concatenating a string myself.
The thing is, I will be updating this JLabel every second and sometimes it can count to the equivalent of 5-6 days if not longer.
So I'm looking for someone who has more experience in the area than I, and knows the most efficient way to tackle this issue.
I would use SimpleDateFormat if I were you.
If SDF is too slow for you, profile all your options and pick the fastest one, then refactor the rest of your code until it's fast enough.
Remember that premature optimization is the root of all evil, and that you should only really do any optimizing after you've profiled your code and missed your target execution time.
SimpleDateFormat() is really quite appropriate for your needs.
Use the TimeUnit class, as shown here in combination with the javax.swing.Timer class set to execute at 1 second intervals.
If you don't mind values wrapping then use SimpleDateFormat as follows. Remember x1000 to convert to milliseconds and to manually override the timezone.
long value = 5 * 24 * 3600 + 5000;
// wrapping solution
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
// ensure no daylight saving +1 hour
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println(sdf.format(value * 1000));
Output
01:23:20
If you want the hours to go past 23.59.59 then this is the simplest I could come up with. I used DecimalFormat to force at least 2 digits for the hours.
long value = 5 * 24 * 3600 + 5000;
long hours = value / 3600; // whole hours
long mins = value / 60 - hours * 60;
long secs = value % 60;
System.out.println(String.format("%s:%2d:%2d",
new DecimalFormat("00").format(hours), mins, secs));
Output
121:23:20
I've found this to be extremely fast. Try it out. Seconds go from 0 - 59, minutes go from 0 - 59, hours go from 0 - 2,562,047,788,015. Afterwards the hours become negative and begin going towards that maximum.
performing the "+" operator on Strings is very slow. A StringBuilder performs grouping strings together the fastest from what I've seen. You should also be using "chars" not "String/Byte" Bytes are very slow as well. I'd prefer doing only multiplication however dividing by 36 and 6 give decimals that are to large for holding.
StringBuilder sb = new StringBuilder(8);
long hours = time / 3600000;
long minutes = (time - hours * 3600000) / 60000;
long seconds = (time - hours * 3600000 - minutes * 60000) / 1000;
if (hours < 10)
sb.append('0');
sb.append(hours);
sb.append(':');
if (minutes < 10)
sb.append('0');
sb.append(minutes);
sb.append(':');
if (seconds < 10)
sb.append('0');
sb.append(seconds);
String formattedTime = sb.toString();
.....
If you don't want to use a formatter class, you can get your work done by using basic operations like conversion among wrapper classes and String operations. Take a look at this code:
long h, m, s; // Initialize them after calculation.
String h1, m1, s1;
h1 = Long.toString( h );
m1 = Long.toString( m );
s1 = Long.toString( s );
if ( s1.length() < 2 )
s1 = "0" + s1;
if ( m1.length() < 2 )
m1 = "0" + m1;
if ( h1.length() < 2 )
h1 = "0" + h1;
String output = h1+":"+m1+":"+s1;
Supposing you have correctly calculated values of seconds, minutes and hours, you can gather String versions of these variables, then format them with a simple length check and finally concatenate these time unit parts.
i think you want to do the math you indicated, but take the floor of each value. then concatenate..
public class Test{
public static void main(String args[]){
double d = -100.675;
float f = -90;
System.out.println(Math.floor(d));
System.out.println(Math.floor(f));
System.out.println(Math.ceil(d));
System.out.println(Math.ceil(f));
}
}

Categories