I am having some strange output when I am attempting to get an average from a long value and converting it to a String (in HH:mm:ss) format. I'm using the Joda time library, which mostly has been a life saver.
Here's what I have so far:
//this is in a static class
public static Duration calculateTime(Date start, Date end) {
Duration duration = new Duration(start.getTime(), end.getTime());
return duration;
}
public static String convertMillisToTime(long milliseconds) {
return String.format("%02d:%02d:%02d",
TimeUnit.MILLISECONDS.toHours(milliseconds),
TimeUnit.MILLISECONDS.toMinutes(milliseconds) -
TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(milliseconds)),
TimeUnit.MILLISECONDS.toSeconds(milliseconds) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(milliseconds)));
}
long averageRunTime = 0;
averageRunTime += calculateTime(drs.startTime, drs.endTime).getMillis();
Since this is done in an array list, to get the average, I am taking
averageRunTime = averageRunTime / (long)arrayList.size();
when I get to the point of
convertMillisToTime(averageRunTime);
It's returning a value that is higher than any times I have. IE( I have no job times that are over 11 hours) but this is returning me a String with 11:mm:ss. Not quite sure WHY?
I used the convertMillisToTime from: How to convert milliseconds to "hh:mm:ss" format?
Can anyone point me in the right direction?
Thank you in advance,
RR
Edit: I've modified the code that converts the long to time using TimeUnit. It's strange though, I grabbed three runs (time streams) and got 09:14:17, 08:57:18, 09:10:25 for the length of each run, and the average is coming out as: 10:27:26.
You could just use a formatter from Joda Time instead, for example...
public static final PeriodFormatter PERIOD_FORMATTER = new PeriodFormatterBuilder().printZeroAlways().
appendHours().appendSeparator(":").
appendMinutes().appendSeparator(":").
appendSeconds().appendSeparator(".").
appendMillis().toFormatter();
public static String toString(Duration duration) {
return duration == null ? "[invalid duration]" : duration.toPeriod().toString(PERIOD_FORMATTER);
}
Related
I am implementing a service (not going to production anywhere anytime) which should receive a LocalDateTime and a Duration and should check if given time is between company working hours (which are 8:00-22:00), the working hours should be (somehow) configurable:
lets say that I have a:
public class CompanyWorkingHoursService {
private static final Int OPENING_HOUR = 8;
private static final Int CLOSING_HOUR = 22;
private boolean isMeetingBetweenWorkingHours(LocalDateTime beginningDateTime, Duration duration) {
LocalDateTime endingDateTime = beginningDateTime.plus(duration);
}
and I'm stuck.
I can change the type of OPENING_HOUR and CLOSING_HOUR to whatever I want. I can get hours and minutes from LocalDateTime but those are integers. And I don't want to compare whole dates - i need just hours and minutes.
I have found some solutions using java.util.Date but I would like to stay with LocalDateTime if possible...
The "best" thing is to avoid integers. So define the opening and closing hours as LocalTime, and compare the dates using the isAfter(), isBefore() and equals() provided by LocalTime:
private static final LocalTime OPENING_HOUR = LocalTime.of(8, 0);
private static final LocalTime CLOSING_HOUR = LocalTime.of(22, 0);
private boolean isMeetingBetweenWorkingHours(LocalDateTime beginningDateTime, Duration duration) {
LocalDateTime endingDateTime = beginningDateTime.plus(duration);
return !beginningDateTime.toLocalTime().isBefore(OPENING_HOUR)
&& !endingDateTime.toLocalTime().isAfter(CLOSING_HOUR));
}
If the working hours should be (somehow) configurable, you could pass them to the method, too. Afterwards create LocalDateTime instances from those values in combination with the date of the meeting.
Maybe like this:
public static boolean isMeetingBetweenWorkingHours(
LocalDateTime startMeeting, Duration meetingDuration,
int openFrom, int openUntil) { // pass start and end hour of day
/*
* create the working time hours using the hours of day passed
* and using the date of the meeting start passed
*/
LocalDateTime startWorkingHours = LocalDateTime.of(startMeeting.toLocalDate(),
LocalTime.of(openFrom, 0));
LocalDateTime endWorkingHours = LocalDateTime.of(startMeeting.toLocalDate(),
LocalTime.of(openUntil, 0));
// calculate the end time of the meeting
LocalDateTime endMeeting = startMeeting.plus(meetingDuration);
// then return if the meeting fully fits into the working time slot
return !startMeeting.isBefore(startWorkingHours)
&& !endMeeting.isAfter(endWorkingHours);
}
I've included the whole method below, but really the challenge is simulating DateTime.MaxValue.Ticks in Java 8. I also don't know the equivalent of ".ToString("D19") in Java.
I thought I had figured out how to begin, which was by using Instant.MAX.toEpochMilli(), which I could then multiply by 10000 to get Ticks. Sadly, this simple statement throws an exception, so it's a non-starter:
Caught: java.lang.ArithmeticException: long overflow
Here is the original method. It's used to query Azure Storage Tables for historical metrics.
// Creates a TableQuery for getting metrics by timestamp
private static TableQuery GenerateMetricTimestampQuery(string partitionKey, DateTime startTime, DateTime endTime)
{
return GenerateMetricQuery(
partitionKey,
(DateTime.MaxValue.Ticks - endTime.Ticks + 1).ToString("D19") + "__",
(DateTime.MaxValue.Ticks - startTime.Ticks).ToString("D19") + "__");
}
Here is an example of a RowKey field value:
2519303419199999999__
I've spent a day on this and I'm pretty stumped. Any help would be greatly appreciated.
If possible, I would prefer to do this without JodaTime.
UPDATE1*** Based on a comment, here is an example of the exception in Java.
import java.time.Instant;
public class Tester {
public static void main(String[] args){
System.out.println(Instant.MAX.toEpochMilli());
}
}
UPDATE Original answer didn't account for offset difference between Java epoch (1970) and .NET ticks (0001). Corrected!
For reference, Long.MAX_VALUE (Java) is:
9,223,372,036,854,775,807
In .NET, DateTime.MaxValue is:
9999-12-31 23:59:59.9999999
3,155,378,975,999,999,999 ticks1 (~ 1/3 of long)
In Java 8, Instant.MAX is:
+1000000000-12-31 23:59:59.999999999
31,556,889,864,403,199,999,999,999 nanos (overflows long)
315,568,898,644,031,999,999,999 ticks2 (overflows long)
31,556,889,864,403,199,999 millis (overflows long)
31,556,889,864,403,199 seconds (~ 1/292 of long)
For reference, your value of 2519303419199999999 is:
2016-08-23 13:28:00
636,075,556,800,000,000 ticks1 (~ 1/14 of long)
14,719,588,800,000,000 ticks2 (~ 1/626 of long)
1) Since 0001-01-01 (.NET) 2) Since 1970-01-01 (Java)
As you can see, Instant.MAX in "ticks" will not fit in a long. Not even milliseconds will fit.
More importantly Instant.MAX is not the same value as DateTime.MaxValue.
I would suggest you just create a constant for the value, e.g.
public static final long DATETIME_MAXVALUE_TICKS = 3155378975999999999L; // .NET: DateTime.MaxValue.Ticks
That way you'll get same string values as you .NET code:
public static final long EPOCH_OFFSET = 62135596800L; // -Instant.parse("0001-01-01T00:00:00Z").getEpochSecond()
private static long getTicks(Instant instant) {
long seconds = Math.addExact(instant.getEpochSecond(), EPOCH_OFFSET);
long ticks = Math.multiplyExact(seconds, 10_000_000L);
return Math.addExact(ticks, instant.getNano() / 100);
}
public static void main(String[] args) {
Instant startTime = Instant.parse("2016-08-23T13:28:00Z");
String s = String.format("%19d", DATETIME_MAXVALUE_TICKS - getTicks(startTime));
System.out.println(s);
}
Output:
2519303419199999999
long maxSeconds = Instant.MAX.getEpochSecond(); //31556889864403199
int maxNanos = Instant.MAX.getNano(); //999999999
These two values can be used together to create a precise MAX value as number:
31556889864403199,999999999
If you need to print it you need to join them as String.
You can also create a BigDecimal from these two values like:
BigDecimal max = new BigDecimal(Long.toString(maxSeconds) + "." + String.format("%09d", maxNanos));
And operate on it:
BigDecimal now = new BigDecimal(String.format("%d.%09d", Instant.now().getEpochSecond(), Instant.now().getNano()));
System.out.println(max.subtract(now).toString());
I want to convert the result of System.nanoTime() to a date.
public void tempBan(Player p, Player banner, int timeInSeconds){
Long timeInNano = (long) (timeInSeconds * 10^9);
int newTime = (int) (System.nanoTime() + timeInNano);
// here I want to convert newTime to a date
}
I have converted the seconds into nanoseconds by multiplying by 10^9. Now I need to convert the current system time plus the parameter which I converted into nanoseconds into a date.
Unfortunately, System.nanoTime() is not what you want for this.
To quote the JavaDoc:
This method can only be used to measure elapsed time and is not related to any other notion of system or wall-clock time. The value returned represents nanoseconds since some fixed but arbitrary origin time (perhaps in the future, so values may be negative). The same origin is used by all invocations of this method in an instance of a Java virtual machine; other virtual machine instances are likely to use a different origin.
You probably want System.currentTimeMillis(), in which case you can use new Date(System.currentTimeMillis() + milliseconds) to get the date for that number of milliseconds in the future.
While you could then subtract System.nanoTime(), scale the value, and add System.currentTimeMillis() to have a similar result... since you're adding System.nanoTime() anyway and therefore have the original number of seconds, you could just use System.currentTimeMillis() directly.
In the theory, you should not use the only System.nanotime(), but you can do a simple trick with this method in order to get nanoseconds of the current time.
public class TimeProvider{
private final static long jvm_diff;
static {
jvm_diff = System.currentTimeMillis()*1000_000-System.nanoTime();
}
public static long getAccurateNow(){
return System.nanoTime()+jvm_diff;
}
}
Even though, you can create your own Clock implementation with this way for using high-level java data time classes.
public class HighLevelClock extends Clock {
private final ZoneId zoneId;
public HighLevelClock(ZoneId zoneId) {
this.zoneId = zoneId;
}
static long nano_per_second = 1000_000_000L;
#Override
public ZoneId getZone() {
return zoneId;
}
#Override
public Clock withZone(ZoneId zoneId) {
return new HighLevelClock(zoneId);
}
#Override
public Instant instant() {
long nanos = TimeProvider.getAccurateNow();
return Instant.ofEpochSecond(nanos/nano_per_second, nanos%nano_per_second);
}
}
Now we can use our clock implementation like the following:
Clock highLevelClock = new HighLevelClock(ZoneId.systemDefault());
System.out.println(LocalDateTime.now(highLevelClock)); //2020-04-04T19:22:06.756194290
System.out.println(ZonedDateTime.now(highLevelClock)); //2020-04-04T19:22:06.756202923+04:00[Asia/Baku]
System.out.println(LocalTime.now(highLevelClock)); //19:22:06.756220764
You can convert it into system time using the below code
public static long convertToUnixMs(final long timeMs) {
final long refMonoMs = monoTimeMs();
final long refUnixMx = System.currentTimeMillis();
return refUnixMx + (timeMs - refMonoMs);
}
public static long monoTimeMs() {
return System.nanoTime() / 1000000;
}
Explanation:
System.nonoTime() is a monotonic time that increases only, it has no idea of what time it is right now, but it would only increase regardless. So it is a good way for measuring elapsing time. But you can not convert this into a sensible time as it has no reference to the current time.
The provided method is a way to convert your stored nano time into a sensible time. First, you have a timeMs that is in nano time that you would like to convert. Then, you created another nanotime (i.e refMonoMs) and another System.currentTimeMillis() (i.e refUnixMx). Then you minus refMonoMs from the timeMs, and add the reference back into it to get the sensible time back.
I have to convert seconds in UTC into day then add interval of one day and return seconds in UTC.
Here is what I have:
option #1
public static final long nextDayStartSec(long epochSecondsInUTC) {
return (epochSecondsInUTC / TimeUnit.DAYS.toSeconds(1) + 1) * TimeUnit.DAYS.toSeconds(1);
}
But not all days contain 86400 seconds according to Wikipedia:
Modern Unix time is based on UTC, which counts time using SI seconds,
and breaks up the span of time into days almost always 86400 seconds
long, but due to leap seconds occasionally 86401 seconds.
option #2
public static final long nextDayStartSec(long epochSecondsInUTC) {
return DateUtils.addMilliseconds(DateUtils.round(new Date(TimeUnit.SECONDS.toMillis(epochSecondsInUTC)), Calendar.DATE), -1)
.toInstant().atZone(systemDefault()).toLocalDateTime().toEpochSecond(ZoneOffset.UTC);
}
But it uses wide range of libraries (including Apache Commons) and hard to read.
Is there something simple that I missed?
If you use Java 8, the new time API allows you to write it this way (it adds one day to the given instant):
public static final long nextDayStartSec(long epochSecondsInUTC) {
OffsetDateTime odt = Instant.ofEpochSecond(epochSecondsInUTC).atOffset(ZoneOffset.UTC);
return odt.plusDays(1).toEpochSecond();
}
If you want to get the instant of the start of the next day, it could look like this:
public static final long nextDayStartSec(long epochSecondsInUTC) {
OffsetDateTime odt = Instant.ofEpochSecond(epochSecondsInUTC).atOffset(ZoneOffset.UTC);
return odt.toLocalDate().plusDays(1).atStartOfDay(ZoneOffset.UTC).toEpochSecond();
}
I have this code in java which is about SystemTime:
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH.mm.ss");
//Gets the time of the boardtime object in milliseconds
public long getMs() {
return super.getTimeInMillis();
}
//Sets the time of the boardtime object in milliseconds
public void setMs(long ms) {
super.setTimeInMillis(ms);
}
I tried to convert it to C#:
For the first part, I used DateTimeFormatInfo class:
private static DateTimeFormatInfo sdf = new DateTimeFormatInfo();
for getting the system time in milliseconds I used TimeSpan:
long milliseconds = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
I do not know if what I have done until now is correct or not but I can not find any C# equivalent for the setTime.
This is what I have done until now:
private static DateTimeFormatInfo sdf = new DateTimeFormatInfo();
public long getMs(){
long milliseconds = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
return milliseconds;
}
public void setMs(long ms){
}
Thanks in advance
If you just want to set/get the time from milliseconds, you can do this with a C# TimeSpan:
private TimeSpan time
public void setMs(long ms)
{
this.time = TimeSpan.FromMilliseconds(ms);
}
public long getMs()
{
return this.time.TotalMilliseconds;
}
Your getMs() as defined above returns the number of MS since 1/1/0001 (see here). Based on this MSDN page, to set system time from C# you need to construct a SYSTEMTIME struct, initialize it properly, and pass it to the function SetSystemTime(). The page has a simple example that shows how to do that. How do we construct the right SYSTEMTIME struct? One can use the function FileTimeToSystemTime(), which takes the number of ticks since 1/1/1601 (note the different year) and converts it to a SYSTEMTIME.
So, in short:
In your setMs() function, convert the parameter that was passed (ticks since 1/1/0001) to ticks since 1/1/1601 (basically, subtract 1600 years in ticks)
Construct a FILETIME struct from that value
Call FileTimeToSystemTime() to get the corresponding SYSTEMTIME
Call SetSystemTime() and pass that value
If there's an easier way, I'd be interested to know. Hope this helps!
If you want to take the time as milliseconds, then use the TimeSpan.TotalMilliseconds method, constructed from a DateTime object using TimeSpan.FromTicks. Create a DateTime object and manipulate the timestamp using milliseconds, then use the predefined DateTime.AddMilliseconds method by adding resp. subtracting milliseconds:
var now = DateTime.Now; // or new DateTime(2014, 05, 29, 21, 27, 05);
Console.WriteLine(now.ToString("yyyy-MM-dd HH.mm.ss"));
var future = now.AddMilliseconds(1234567);
var past = now.AddMilliseconds(-1234567);
Console.WriteLine(future.ToString("yyyy-MM-dd HH.mm.ss"));
Console.WriteLine(past.ToString("yyyy-MM-dd HH.mm.ss"));
// get milliseconds from current date time object using TimeSpan.TotalMilliseconds
var ts = TimeSpan.FromTicks(now.Ticks);
Console.WriteLine(ts.TotalMilliseconds);
The output is:
2014-05-29 21.27.05
2014-05-29 21.47.40
2014-05-29 21.06.31
63536995625703,1
Have a look at this MSDN article about Custom Date and Time Format Strings for more custom date and time formatting options for a DateTime object.