I am using java timer, but my problem is every time exceeding 60 seconds, I like my code working like;
1 minutes 59 seconds,
2 minutes 0 seconds..
My code is below.
private long lastReceivedMessage = System.currentTimeMillis();
#Scheduled(fixedDelayString = "${listenScheduled}", initialDelay = 1000)
private void distanceBetweenLastReceivedMessageAndCurrentTime() {
long currentTime = System.currentTimeMillis() - lastReceivedMessage;
logger.info("has threw 'INFO' event due to is not running as an expected since {} {} {} {} ", TimeUnit.MILLISECONDS.toMinutes(currentTime), "minutes", TimeUnit.MILLISECONDS.toSeconds(currentTime), "seconds");
java.time classes
Capture the current moment using java.time.Instant.
Instant then = Instant.now() ;
…
Duration d = Duration.between( then , Instant.now() ) ;
String output = d.toString() ;
The toString method generates text in standard ISO 8601 format: PnYnMnDTnHnMn. I suggest you report using that format. The format uses a P to mark the beginning. A T separates any years-months-days from any hours-minutes-seconds. So, two and a half minutes is PT2M30S.
If you insist on your format, call the to…Part methods on Duration.
It is not going to automatically separate the minutes and seconds. Also, I would recommend breaking up that logger.info statement for readability.
One way to do it is to convert it to seconds first, set the modulus (remainder) of the seconds and 60 as your seconds, then divide the minutes for the minutes value. Or you could just skip the conversion and divide + modulus by 60000.
long msElapsed = 660_000; //5min 30sec
long secElapsed = msElapsed / 1000;
long minutes = secElapsed / (long) 60;
long seconds = secElapsed % 60;
System.out.printf("%d %d",(int)minutes,(int)seconds);
Related
This question already has answers here:
Java 8: Difference between two LocalDateTime in multiple units
(11 answers)
Closed 3 years ago.
I tried this code:
public class TimePassed {
private long seconds;
private long minutes;
private long hours;
private long days;
private long years;
...
public TimePassed(double unixSeconds) {
Instant now = Instant.now();
Instant ago = Instant.ofEpochSecond((long) unixSeconds);
this.seconds = ChronoUnit.SECONDS.between(
ago.atZone(ZoneId.systemDefault()),
now.atZone(ZoneId.systemDefault())); //6100
this.minutes = ChronoUnit.MINUTES.between(
ago.atZone(ZoneId.systemDefault()),
now.atZone(ZoneId.systemDefault())); //101
this.hours = ChronoUnit.HOURS.between(
ago.atZone(ZoneId.systemDefault()),
now.atZone(ZoneId.systemDefault())); //1
this.days = ChronoUnit.DAYS.between(
ago.atZone(ZoneId.systemDefault()),
now.atZone(ZoneId.systemDefault())); //0
this.years = ChronoUnit.YEARS.between(
ago.atZone(ZoneId.systemDefault()),
now.atZone(ZoneId.systemDefault())); //0
}
}
However then the TimePassed object would have seconds = 6100 and minutes = 101 and hours = 1, while I want it to be hours = 1, minutes = 41, seconds = 40, so that 60*60 + 41*60 + 40 = 6100. Is it possible to do with java.time package? Because as of now I can only either get passed seconds, passed minutes or passed hours, etc. And neither would account for the other.
Java 9 answer: Duration.toXxxPart methods
Basic idea, not complete:
Duration dur = Duration.between(ago, now);
this.seconds = dur.toSecondsPart(); // 40
this.minutes = dur.toMinutesPart(); // 41
this.hours = dur.toHoursPart(); // 1
this.days = dur.toDaysPart(); // 0
Tested with instants that are 6100 seoncds apart like yours from the question. The toXxxPart methods were introduced in Java 9. For Java 8 (or ThreeTen Backport) you will need to start from the coarser units, the days, and subtract them from the duration before getting the next finer unit. See this answer by lauhub for an example
The years and days are a bit tricky to get completely correct, though. To get only the days that exceed the whole years here’s the full code:
ZoneId zone = ZoneId.systemDefault();
ZonedDateTime agoZdt = ago.atZone(zone);
ZonedDateTime nowZdt = now.atZone(zone);
this.years = ChronoUnit.YEARS.between(agoZdt, nowZdt);
ZonedDateTime afterWholeYears = agoZdt.plusYears(this.years);
Duration dur = Duration.between(afterWholeYears, nowZdt);
this.seconds = dur.toSecondsPart(); // 40
this.minutes = dur.toMinutesPart(); // 41
this.hours = dur.toHoursPart(); // 1
this.days = dur.toDays(); // 0
I am on purpose reading ZoneId.systemDefault() only once just for the unlikely case that someone changes the default time zone setting underway.
Something like this should work:
ZoneId zone = ZoneId.systemDefault();
ZonedDateTime ago = ZonedDateTime.ofInstant(Instant.ofEpochSeconds(unixSeconds), zone);
ZonedDateTime now = ZonedDateTime.now(zone);
Period period = Period.between(ago.toLocalDate(), now.toLocalDate());
ZonedDateTime adjusted = ago.with(now.toLocalDate());
if (adjusted.isAfter(now)) {
adjusted = adjusted.minusDays(1);
period = period.minusDays(1);
}
Duration duration = Duration.between(adjusted, now);
assert duration.toDaysPart() == 0;
years = period.getYears();
months = period.getMonths();
days = period.getDays();
hours = duration.toHoursPart();
minutes = duration.toMinutesPart();
seconds = duration.toSecondsPart();
Why/how this works:
The difference in non-time fields (year, month, day) is computed by using a specialized Period type, which is intended exactly for this purpose. It uses LocalDate part of two date-times, which is safe, since they are both in the same time zone
To know the difference in rest of the fields, we adjust the "ago" value, so that the days are exactly the same. If we happened to overshoot (which might happen if "ago" happened at earlier local time compared to "now"), we adjust to that by decreasing both the adjusted date-time and also the period by one day
Then, we use Duration class to get the difference between time-based fields. Since there we query the difference between adjusted date-times, our duration will not be more than one day, to which I added the assertion for.
Lastly, I used various methods available on both Period and Duration to obtain their "fields". Note that methods of Duration class that I used only available since Java 9, so if you don't have it yet, you'll have to use methods like toMinutes() and manually divide them by amount of, for example, minutes per hour and such:
// those constants you'll have to define on your own, shouldn't be hard
hours = duration.toHours() % Constants.HOURS_PER_DAY;
Alternatively, if you don't want to define constants, you can repeat the trick with adjusting the "ago" variable:
adjusted = ago.with(now.toLocalDate());
if (adjusted.isAfter(now)) {
adjusted = adjusted.minusDays(1);
period = period.minusDays(1);
}
hours = HOURS.between(adjusted, now);
adjusted = adjusted.withHour(now.getHour());
if (adjusted.isAfter(now)) {
adjusted = adjusted.minusHour(1);
hours -= 1;
}
minutes = MINUTES.between(adjusted, now);
adjusted = adjusted.withMinute(now.getMinute());
if (adjusted.isAfter(now)) {
adjusted = adjusted.minusMinutes(1);
minutes -= 1;
}
seconds = SECONDS.between(adjusted, now);
I'm trying to convert the number of seconds contained in a duration into hours by dividing the duration.getSeconds() value by 60 twice.
However when I do this the number is being converted into 0.0, instead of an actual value. I imagine this is because the number is too small to be represented, however I have used doubles to try and represent the number and it still doesn't work.
In the below code please assume startTime and endTime are valid LocalTimes produced by two separate calls to LocalTime.now()
Duration duration = Duration.between(startTime, endTime); //duration in sec
double durationInSec = duration.getSeconds();
double durationInHours = durationInSec / 60 / 60;
Works for me
LocalTime start = LocalTime.of ( 11 , 30 );
LocalTime stop = start.plusHours ( 2 );
Duration d = Duration.between ( start , stop );
double seconds = d.toSeconds ();
double hours = seconds / 60 / 60;
See this code run live at IdeOne.com.
start.toString() = 11:30
stop.toString() = 13:30
d.toString() = PT2H
seconds = 7200.0
hours = 2.0
Tip: When you know you want to work with fractions of double, append d to your numeric literals to avoid any confusion over the compiler's integer-to-fraction conversion and up/downscaling the types. Be explicit. So in your code, append each 60 with a d. May not be necessary here, but removes ambiguity for the reader at least.
double hours = seconds / 60d / 60d ;
<1 second = 0 hours
As others commented, if your elapsed time was less than a full second, your code results in a zero.
A Duration is internally represented by a count of whole seconds plus a fractional second as a count of nanoseconds. Your call to Duration::getSeconds() retrieves the whole seconds, without the fractional second. So for a duration of PT0.5S, getSeconds returns zero. Zero divided by sixty divided by sixty equals zero.
Duration d = Duration.parse ( "PT0.5S" ); // Half a second.
double hours = d.getSeconds () / 60d / 60d;
hours: 0.0
You should instead call Duration::toNanos to get a total number of nanoseconds elapsed. And adjust your division.
Duration d = Duration.parse ( "PT0.5S" ); // Half a second.
long nanos = d.toNanos () ;
double hours = nanos / 1_000_000_000d / 60d / 60d ;
hours: 1.388888888888889E-4
Avoid fractional hours
By the way, let me suggest that fractional hours is a poor way to handle spans-of-time. Hours, minutes, seconds, and such are not amenable to such decimal math.
Besides that, the floating-point types such as double are inherently inaccurate.
Use the Java classes intended for this purpose: Duration and Period. When reporting or exchanging textually the value of these objects, use standard ISO 8601 format. As seen above, 2 hours is represented by PT2H.
The java.time classes use ISO 8601 formats by default when parsing/generating strings. No need to specify a formatting pattern.
Duration d = Duration.parse( "PT2H" ) ;
This question already has an answer here:
How to calculate difference between two dates in years...etc with Joda-Time
(1 answer)
Closed 8 years ago.
I have a long-variable which represents an amount of delay in milliseconds. I want to transform this long to some kind of Date where it says how many hours, minutes, seconds, days, months, years have passed.
When using Date toString() from Java, as in new Date(5).toString, it says 5 milliseconds have passed from 1970. I need it to say 5 milliseconds have passed, and 0 minutes, hours, ..., years.
you cannot get direct values , without any reference date for your requirements, you need define first reference value like below:
String dateStart = "01/14/2012 09:29:58";
SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss")
Date d1 = format.parse(dateStart);
the above is your reference date , now you need to find the current date and time using following.
long currentDateTime = System.currentTimeMillis();
Date currentDate = new Date(currentDateTime);
Date d2.format(currentDate)
and the difference of these values like long diff=d2-d1 will gives values in milliseconds.
then
long diffSeconds = diff / 1000 % 60;
long diffMinutes = diff / (60 * 1000) % 60;
long diffHours = diff / (60 * 60 * 1000) % 24;
long diffDays = diff / (24 * 60 * 60 * 1000);
and similarly for months and years.
you can also refer the example given on this link for more information http://javarevisited.blogspot.in/2012/12/how-to-convert-millisecond-to-date-in-java-example.html
From what I understand from your question you could achieve your goal by writing a method that will suit your needs i.e.:
static public String dateFromMili (long miliseconds) {
// constants that will hold the number of miliseconds
// in a given time unit (year, month etc.)
final int YEAR_IN_MILISECONDS = 12*30*24*60*60*1000;
final int MONTH_IN_MILISECONDS = 30*24*60*60*1000;
final int DAY_IN_MILISECONDS = 24*60*60*1000;
final int HOUR_IN_MILISECONDS = 60*60*1000;
final int MINUTE_IN_MILISECONDS = 60*1000;
final int SECONDS_IN_MILISECONDS = 1000;
// now use those constants to return an appropriate string.
return miliseconds +" miliseconds, "
+miliseconds/SECONDS_IN_MILISECONDS+" seconds, "
+miliseconds/MINUTE_IN_MILISECONDS+" minutes, "
+miliseconds/HOUR_IN_MILISECONDS+" hours, "
+miliseconds/DAY_IN_MILISECONDS+" days, "
+miliseconds/MONTH_IN_MILISECONDS+" months, "
+miliseconds/YEAR_IN_MILISECONDS+" years have passed";
}
Than you will have to pas the number of miliseconds as a parameter to your new function that will return the desired String (i.e for two seconds):
dateFromMili (2000);
You could also print your answer:
System.out.println(dateFromMili(2000));
The result would look like this:
2000 miliseconds, 2 seconds, 0 minutes, 0 hours, 0 days, 0 months, 0 years have passed
Note that this method will return Strings with integer value (you will not get for example "2.222333 years" but "2 years"). Furthermore, it could be perfected by changing the noun from plural to singular, when the context is appropriate ("months" to "month").
I hope my answer helped.
This is how I solved the problem:
I used a library called Joda-Time (http://www.joda.org/joda-time/) (credits to Keppil!)
Joda-Time has various data-structures for Date and Time. You can represent a date and time by a DateTime-object.
To represent the delay I was looking for, I had two options: a Period data-structure or a Duration data-structure. A good explanation of the difference between those two can be found here: Joda-Time: what's the difference between Period, Interval and Duration? .
I thus used a Duration-object, based on the current date of my DateTime-object. It has all the methods to convert the amount of milliseconds to years, months, weeks, days, hours, minutes and seconds.
i did some research, but still can't find how to get the days... Here is what I got:
int seconds = (int) (milliseconds / 1000) % 60 ;
int minutes = (int) ((milliseconds / (1000*60)) % 60);
int hours = (int) ((milliseconds / (1000*60*60)) % 24);
int days = ????? ;
Please help, I suck at math, thank's.
For simple cases like this, TimeUnit should be used. TimeUnit usage is a bit more explicit about what is being represented and is also much easier to read and write when compared to doing all of the arithmetic calculations explicitly. For example, to calculate the number days from milliseconds, the following statement would work:
long days = TimeUnit.MILLISECONDS.toDays(milliseconds);
For cases more advanced, where more finely grained durations need to be represented in the context of working with time, an all encompassing and modern date/time API should be used. For JDK8+, java.time is now included (here are the tutorials and javadocs). For earlier versions of Java joda-time is a solid alternative.
If you don't have another time interval bigger than days:
int days = (int) (milliseconds / (1000*60*60*24));
If you have weeks too:
int days = (int) ((milliseconds / (1000*60*60*24)) % 7);
int weeks = (int) (milliseconds / (1000*60*60*24*7));
It's probably best to avoid using months and years if possible, as they don't have a well-defined fixed length. Strictly speaking neither do days: daylight saving means that days can have a length that is not 24 hours.
Go for TImeUnit in java
In order to import use, java.util.concurrent.TimeUnit
long millisec=System.currentTimeMillis();
long seconds=TimeUnit.MILLISECONDS.toSeconds(millisec);
long minutes=TimeUnit.MILLISECONDS.toMinutes(millisec);
long hours=TimeUnit.MILLISECONDS.toMinutes(millisec);
long days=TimeUnit.MILLISECONDS.toDays(millisec);
java.time
You can use java.time.Duration which is modelled on ISO-8601 standards and was introduced with Java-8 as part of JSR-310 implementation. With Java-9 some more convenient methods were introduced.
Demo:
import java.time.Duration;
public class Main {
public static void main(String[] args) {
// Duration between the two instants
Duration duration = Duration.ofMillis(1234567890L);
// Print Duration#toString
System.out.println(duration);
// Custom format
// ####################################Java-8####################################
String formattedElapsedTime = String.format(
"%d Day %02d Hour %02d Minute %02d Second %d Millisecond (%d Nanosecond)", duration.toDays(),
duration.toHours() % 24, duration.toMinutes() % 60, duration.toSeconds() % 60,
duration.toMillis() % 1000, duration.toNanos() % 1000000000L);
System.out.println(formattedElapsedTime);
// ##############################################################################
// ####################################Java-9####################################
formattedElapsedTime = String.format("%d Day %02d Hour %02d Minute %02d Second %d Millisecond (%d Nanosecond)",
duration.toDaysPart(), duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart(),
duration.toMillisPart(), duration.toNanosPart());
System.out.println(formattedElapsedTime);
// ##############################################################################
}
}
A sample run:
PT342H56M7.89S
14 Day 06 Hour 56 Minute 07 Second 890 Millisecond (890000000 Nanosecond)
14 Day 06 Hour 56 Minute 07 Second 890 Millisecond (890000000 Nanosecond)
Learn more about the modern date-time API from Trail: Date Time.
int days = (int) (milliseconds / 86 400 000 )
public static final long SECOND_IN_MILLIS = 1000;
public static final long MINUTE_IN_MILLIS = SECOND_IN_MILLIS * 60;
public static final long HOUR_IN_MILLIS = MINUTE_IN_MILLIS * 60;
public static final long DAY_IN_MILLIS = HOUR_IN_MILLIS * 24;
public static final long WEEK_IN_MILLIS = DAY_IN_MILLIS * 7;
You could cast int but I would recommend using long.
You can’t. Sorry. Or more precisely: you can if you know a time zone and a start time (or end time). A day may have a length of 23, 24 or 25 hours or some other length. So there isn’t any sure-fire formula for converting from milliseconds to days. So while you can safely rely on 1000 milliseconds in a second, 60 seconds in a minute (reservation below) and 60 minutes in an hour, the conversion to days needs more context in order to be sure and accurate.
Reservation: In real life a minute is occasionally 61 seconds because of a leap second. Not in Java. Java always counts a minute as 60 seconds because common computer clocks don’t know leap seconds. Common operating systems and Java itself do know not only summer time (DST) but also many other timeline anomalies that cause a day to be shorter or longer than 24 hours.
To demonstrate. I am writing this on March 29, 2021, the day after my time zone, Europe/Copenhagen, and the rest of the EU switched to summer time.
ZoneId myTimeZone = ZoneId.of("Europe/Copenhagen");
ZonedDateTime now = ZonedDateTime.now(myTimeZone);
ZonedDateTime twoDaysAgo = now.minusDays(2);
ZonedDateTime inTwoDays = now.plusDays(2);
System.out.println(ChronoUnit.MILLIS.between(twoDaysAgo, now));
System.out.println(ChronoUnit.MILLIS.between(now, inTwoDays));
Output:
169200000
172800000
So how many milliseconds are in two days depends on which two days you mean. And in which time zone.
So what to do?
If for your purpose you can safely define a day as 24 hours always, for example because your days are counted in UTC or your users are fine with the inaccuracy, use either Duration or TimeUnit. Since Java 9 the Duration class will additionally tell you how many hours, minutes and seconds there are in addition to the whole days. See the answer by Arvind Kumar Avinash. For the TimeUnit enum see the answers by whaley and Dev Parzival. In any case the good news is that it doesn’t matter if you suck at math because the math is taken care of for you.
If you know a time zone and a starting point, use ZonedDateTime and ChronoUnit.DAYS. In this case too the math is taken care of for you.
ZonedDateTime start = LocalDate.of(2021, Month.MARCH, 28).atStartOfDay(myTimeZone);
long millisToConvert = 170_000_000;
ZonedDateTime end = start.plus(millisToConvert, ChronoUnit.MILLIS);
long days = ChronoUnit.DAYS.between(start, end);
System.out.format("%d days%n", days);
2 days
If you additionally want the hours, minutes and seconds:
Duration remainingTime = Duration.between(start.plusDays(days), end);
System.out.format(" - and an additional %s hours %d minutes %d seconds%n",
remainingTime.toHours(),
remainingTime.toMinutesPart(),
remainingTime.toSecondsPart());
- and an additional 0 hours 13 minutes 20 seconds
If instead you had got an endpoint, subtract your milliseconds from the endpoint using the minus method (instead of the plus method used in the above code) to get the start point.
Under no circumstances do the math yourself as in the question and in the currently accepted answer. It’s error-prone and results in code that is hard to read. And if your reader sucks at math, he or she can spend much precious developer time trying to verify that you have done it correctly. Leave the math to proven library methods, and it will be much easier for your reader to trust that your code is correct.
In case you solve a more complex task of logging execution statistics in your code:
public void logExecutionMillis(LocalDateTime start, String callerMethodName) {
LocalDateTime end = getNow();
long difference = Duration.between(start, end).toMillis();
Logger logger = LoggerFactory.getLogger(ProfilerInterceptor.class);
long millisInDay = 1000 * 60 * 60 * 24;
long millisInHour = 1000 * 60 * 60;
long millisInMinute = 1000 * 60;
long millisInSecond = 1000;
long days = difference / millisInDay;
long daysDivisionResidueMillis = difference - days * millisInDay;
long hours = daysDivisionResidueMillis / millisInHour;
long hoursDivisionResidueMillis = daysDivisionResidueMillis - hours * millisInHour;
long minutes = hoursDivisionResidueMillis / millisInMinute;
long minutesDivisionResidueMillis = hoursDivisionResidueMillis - minutes * millisInMinute;
long seconds = minutesDivisionResidueMillis / millisInSecond;
long secondsDivisionResidueMillis = minutesDivisionResidueMillis - seconds * millisInSecond;
logger.info(
"\n************************************************************************\n"
+ callerMethodName
+ "() - "
+ difference
+ " millis ("
+ days
+ " d. "
+ hours
+ " h. "
+ minutes
+ " min. "
+ seconds
+ " sec."
+ secondsDivisionResidueMillis
+ " millis).");
}
P.S. Logger can be replaced with simple System.out.println() if you like.
I created a filter that monitors the length of a request.
long start = System.nanoTime();
...
long end = System.nanoTime();
How can I get the number of milliseconds from this now?
(end - start) / 1000000
1 microsecond = 1000 nanoseconds
1 millisecond = 1000 microseconds
Note, that the result will be rounded down, but you usually don't get true nanosecond accuracy anyway (accuracy depends on the OS). From the Javadoc on nanoTime():
This method provides nanosecond precision, but not
necessarily nanosecond accuracy.
Also note that you can use the TimeUnit class to help with conversion. With older versions of Java, the following code might be an example to transform a processing time into some other time format:
long startTime = System.nanoTime();
//Processing in-between.
long endTime = System.nanoTime();
long duration = endTime - startTime;
duration = TimeUnit.SECONDS.convert(duration, TimeUnit.NANOSECONDS);
Note that newer versions of Java have shortcuts in the TimeUnit class.
The above sample will turn nanoseconds long into seconds. Also note that this truncates it so you do lose some precision. Therefore, if you switch to minutes then you will lose the precision of seconds. If you want to get a result of "12 minutes and 32 seconds" then you would have to do further processing with this solution.
TimeUnit#toMillis(long) (since Java 5)
TimeUnit.NANOSECONDS.toMillis(end - start);
OR
Duration#toMillis() (since Java 8)
Duration.ofNanos(end - start).toMillis()
OR
Duration#between(Temporal, Temporal) (since Java 8)
Instant start = Instant.now();
...
Instant end = Instant.now();
Duration.between(start, end).toMillis()
OR
ChronoUnit.html#between(Temporal, Temporal) (since Java 8)
Instant start = Instant.now();
...
Instant end = Instant.now();
ChronoUnit.MILLIS.between(start, end)
Just subtract them and divide result by 10^6.
1 nanosecond is 10^-9 seconds and, correspondingly, 10^-6 milliseconds.
http://en.wikipedia.org/wiki/Nano-
You could just use System.currentTimeMillis().
Caveat:
Note that while the unit of time of the return value is a millisecond, the granularity of the value depends on the underlying operating system and may be larger. For example, many operating systems measure time in units of tens of milliseconds.
To get a meaningful result:
void procedure ( ... )
{
...
}
double measureProcedure ( double epsilon , ... )
{
double mean ;
double stderr = 2 * epsilon ;
while ( stderr > epsilon )
{
long start = System.nanoTime();
procedure ( ... ) ;
long end = System.nanoTime();
// recalculate mean , stderr
}
return ( mean / 1000000 ) ;
}